From c36534f69691873e386cd3808ac741e01044a17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geoffrey=20=E2=80=9CFrogeye=E2=80=9D=20Preud=27homme?= Date: Wed, 29 Dec 2021 12:56:07 +0100 Subject: [PATCH] rssVideos: Sync read state Deleted but previously downloaded = read --- config/scripts/rssVideos | 72 ++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/config/scripts/rssVideos b/config/scripts/rssVideos index 6211f20..50abb08 100755 --- a/config/scripts/rssVideos +++ b/config/scripts/rssVideos @@ -108,13 +108,15 @@ class RVElement: parent: "RVDatabase" item: dict downloaded_filepath: typing.Optional[str] - watched: bool def __init__(self, parent: "RVDatabase", item: dict) -> None: self.parent = parent self.item = item self.downloaded_filepath = None - self.watched = False + + @property + def id(self) -> str: + return self.item["id"] @property def title(self) -> str: @@ -142,10 +144,9 @@ class RVElement: log.debug(f"From cache: {self}") if cache.downloaded_filepath: self.downloaded_filepath = cache.downloaded_filepath - if cache.watched: - self.watched = True def __str__(self) -> str: + # return self.item.get("id") str = f"{self.guid}: {self.creator if self.creator else '?'} – {self.title}" if self.is_researched: if self.is_video: @@ -232,6 +233,12 @@ class RVElement: return self.download() + @property + def watched(self) -> bool: + if not self.is_researched: + return False + return self.was_downloaded and not self.downloaded + def matches_filter(self, args: configargparse.Namespace) -> bool: # Inexpensive filters if args.seen != "any" and (args.seen == "seen") != self.watched: @@ -272,8 +279,8 @@ class RVElement: proc = subprocess.run(cmd) proc.check_returncode() - self.watched = True - self.parent.save() + self.clean() + self.try_mark_read() def clean(self) -> None: assert self.is_video @@ -284,6 +291,32 @@ class RVElement: if not self.parent.args.dryrun: os.unlink(file) + def mark_read(self) -> None: + log.debug(f"Marking {self} read") + if self.parent.args.dryrun: + return + r = requests.post( + f"{self.parent.args.url}/reader/api/0/edit-tag", + data={ + "i": self.id, + "a": "user/-/state/com.google/read", + "ac": "edit", + "token": self.parent.feed_token, + }, + headers=self.parent.auth_headers, + ) + r.raise_for_status() + if r.text.strip() != "OK": + raise RuntimeError(f"Couldn't mark {self} as read: {r.text}") + log.info(f"Marked {self} as read") + self.parent.elements.remove(self) + + def try_mark_read(self) -> None: + try: + self.mark_read() + except requests.ConnectionError: + log.warning(f"Couldn't mark {self} as read") + class RVDatabase: SAVE_FILE = ".cache.p" @@ -478,6 +511,20 @@ class RVDatabase: return elements + @functools.cached_property + def feed_token(self) -> str: + r = requests.get( + f"{self.args.url}/reader/api/0/token", + headers=self.auth_headers, + ) + r.raise_for_status() + return r.text.strip() + + def try_mark_watched_read(self) -> None: + for element in self.elements: + if element.watched: + element.try_mark_read() + def get_args() -> configargparse.Namespace: defaultConfigPath = os.path.join( @@ -595,8 +642,6 @@ def get_args() -> configargparse.Namespace: "watch", "binge", "clean", - "seen", - "unseen", ), default="download", ) @@ -654,6 +699,7 @@ def main() -> None: else: duration = 0 for element in database.filter(args): + duration += element.duration if element.is_video else 0 if args.action == "download": element.preload() elif args.action == "list": @@ -662,19 +708,11 @@ def main() -> None: element.watch() if args.action == "watch": break - elif args.action == "seen": - if not element.watched: - log.info(f"Maked as seen: {element}") - element.watched = True - elif args.action == "unseen": - if element.watched: - log.info(f"Maked as unseen: {element}") - element.watched = False else: raise NotImplementedError(f"Unimplemented action: {args.action}") - duration += element.duration if element.is_video else 0 log.info(f"Total duration: {format_duration(duration)}") database.attempt_clean() + database.try_mark_watched_read() database.save()