diff --git a/apiserver/server.py b/apiserver/server.py index efacb1e..9537c6c 100644 --- a/apiserver/server.py +++ b/apiserver/server.py @@ -76,8 +76,12 @@ cors = CORS(flask_app) def api(): skip = request.args.get('skip', 0) limit = request.args.get('limit', settings.FEED_LENGTH) + is_smallweb_filter = request.args.get('smallweb') == 'true' and smallweb_set + sources_filter = request.args.getlist('source') - if request.args.get('smallweb') == 'true' and smallweb_set: + if not is_smallweb_filter and not sources_filter: + stories = database.get_stories(limit, skip) + else: limit = int(limit) skip = int(skip) filtered_stories = [] @@ -90,24 +94,28 @@ def api(): for story_str in stories_batch: story = json.loads(story_str) - story_url = story.get('url') or story.get('link') or '' - if not story_url: - continue - hostname = urlparse(story_url).hostname - if hostname: - hostname = hostname.replace('www.', '') - if hostname in smallweb_set: - filtered_stories.append(story_str) - if len(filtered_stories) == limit: - break + + if is_smallweb_filter: + story_url = story.get('url') or story.get('link') or '' + if not story_url: + continue + hostname = urlparse(story_url).hostname + if not hostname or hostname.replace('www.', '') not in smallweb_set: + continue + + if sources_filter: + if story.get('source') not in sources_filter: + continue + + filtered_stories.append(story_str) + if len(filtered_stories) == limit: + break if len(filtered_stories) == limit: break current_skip += limit stories = filtered_stories - else: - stories = database.get_stories(limit, skip) # hacky nested json res = Response('{"stories":[' + ','.join(stories) + ']}') diff --git a/webclient/src/App.js b/webclient/src/App.js index a62369b..fef9d8a 100644 --- a/webclient/src/App.js +++ b/webclient/src/App.js @@ -26,6 +26,15 @@ function App() { const [bodyFont, setBodyFont] = useState(localStorage.getItem('bodyFont') || 'Sans Serif'); const [articleFont, setArticleFont] = useState(localStorage.getItem('articleFont') || 'Apparatus SIL'); const [filterSmallweb, setFilterSmallweb] = useState(() => localStorage.getItem('filterSmallweb') === 'true'); + const [feedSources, setFeedSources] = useState(() => { + const saved = localStorage.getItem('feedSources'); + return saved ? JSON.parse(saved) : { + hackernews: true, + reddit: true, + lobsters: true, + tildes: true, + }; + }); const updateCache = useCallback((key, value) => { cache.current[key] = value; @@ -57,6 +66,14 @@ function App() { localStorage.setItem('filterSmallweb', isChecked); }; + const handleFeedSourceChange = (source) => { + setFeedSources(prevSources => { + const newSources = { ...prevSources, [source]: !prevSources[source] }; + localStorage.setItem('feedSources', JSON.stringify(newSources)); + return newSources; + }); + }; + const changeBodyFont = (font) => { setBodyFont(font); localStorage.setItem('bodyFont', font); @@ -177,6 +194,22 @@ function App() { +