First attempt at multiple pages of homepage subscriptions

This commit is contained in:
southerntofu 2021-08-04 20:52:59 +02:00
parent 90c054e258
commit fe0b83bd0e
3 changed files with 26 additions and 20 deletions

29
main.py
View File

@ -191,22 +191,19 @@ class Context():
# appended to the "failures" context entry, otherwise a single request would crash the whole homepage.
def subscriptions(self, page=1, lang=None):
# Let's follow subscriptions from the current working dir
# TODO: make it configurable, maybe by "playlist" or by language?
# TODO: make it configurable, maybe by "playlist" defined in config?
subscriptions = Subscriptions('.', self.api, cache)
info = subscriptions.info()
# TODO: limit does nothing here?!
videos = subscriptions.videos(limit=12)
# Lang-filtering is done deeper in the API, so if a channel has 3 differents videos per publication for different languages,
# we can still get the expected number of recent videos from there instead of only considering the eg. 5 latest videos in said lang
# TODO: Is it working well? Should write some tests
videos = subscriptions.videos(page=page, lang=lang)
failures = info.failures
failures.extend(videos.failures)
filtered_videos = videos.successes
if lang != None:
# TODO: What to do when language is not defined on video? Should we have "default language" for account/channel?
# Currently it's displayed in all languages
filtered_videos = list(filter(lambda vid: vid["language"]["id"] == lang or vid["language"]["id"] == None, filtered_videos))
self.insert("subscriptions", info.successes)
self.insert("videos", filtered_videos)
# Sanitize errors for HTML so we can have newlines in errors but not risk content injection
@ -214,16 +211,20 @@ class Context():
return self
# --- INDEX ROUTE ---
@app.route("/")
async def main():
context = Context(api).subscriptions()
@app.route("/", defaults = {"page": 1})
@app.route("/<int:page>")
async def main(page):
# TODO: Pagination
context = Context(api).subscriptions(page=page)
# Inside subscriptions variable in templates, you may find either an account info structure, or a channel info structure. Channels may be recognized due to `ownerAccount` property.
# Failed requests do not fail the index.html rendering, instead they are stored in "failures" context key
return await render("index.html", context.failed(), context.build)
@app.route("/<lang:lang>")
async def main_lang(lang):
context = Context(api).subscriptions(lang=lang)
@app.route("/<lang:lang>", defaults = {"page": 1})
@app.route("/<lang:lang>/<int:page>")
async def main_lang(lang, page):
# TODO: Pagination
context = Context(api).subscriptions(page=page, lang=lang)
return await render("index.html", context.failed(), context.build)
# --- END INDEX ROUTE ---

View File

@ -343,9 +343,10 @@ class API:
# Fetch latest videos from multiple accounts, returned as MultipleResults
# NOTE: This new API method enforces usage of Account class as channel. DO NOT USE WITH (account, domain) tuple.
def accounts_videos(self, accounts, limit=None, sort=True, ttl=None):
api_limit = 10 if limit == None else limit
results = MultipleResults()
for account in accounts:
results.insert_paginated(self.account_videos(account.domain, account.name))
results.insert_paginated(self.account_videos(account.domain, account.name, count=api_limit))
if limit or sort:
# We also sort when limit is set, because otherwise limit will discard useful information
results.successes.sort(key = lambda vid: dateutil.isoparse(vid["createdAt"]), reverse=True)
@ -386,9 +387,10 @@ class API:
# Fetch latest videos from multiple channels, returned as MultipleResults
# NOTE: This new API method enforces usage of Account class as channel. DO NOT USE WITH (account, domain) tuple.
def channels_videos(self, channels, limit=None, sort=True, ttl=None):
api_limit = 10 if limit == None else limit
results = MultipleResults()
for channel in channels:
results.insert_paginated(self.channel_videos(channel.domain, channel.name))
results.insert_paginated(self.channel_videos(channel.domain, channel.name, count=api_limit))
if limit or sort:
# We also sort when limit is set, because otherwise limit will discard useful information
results.successes.sort(key = lambda vid: dateutil.isoparse(vid["createdAt"]), reverse=True)

View File

@ -153,11 +153,14 @@ class Subscriptions:
# Get the latest `limit` videos from accounts and channels subscriptions combined. Returns a list of successes and failures
# NOTE: duplicates are not handled, why would you add both an account and the corresponding channel?
def videos(self, limit=12, sort=True, ttl=None):
results = MultipleResults().merge_with(self.api.accounts_videos(self.accounts(), limit=limit, ttl=ttl, sort=False)) \
.merge_with(self.api.channels_videos(self.channels(), limit=limit, ttl=ttl, sort=False))
if sort:
def videos(self, page=None, sort=True, lang=None, ttl=None):
results = MultipleResults().merge_with(self.api.accounts_videos(self.accounts(), ttl=ttl, sort=False)) \
.merge_with(self.api.channels_videos(self.channels(), ttl=ttl, sort=False))
if lang != None:
results.successes = list(filter(lambda vid: vid["language"]["id"] == lang or vid["language"]["id"] == None, results.successes))
if page or sort:
results.successes.sort(key = lambda vid: dateutil.isoparse(vid["createdAt"]), reverse=True)
if page: results.successes = results.successes[15*(page-1):15*page]
return results
# List of locally-subscribed accounts (accounts.list)