rssVideos: Sync read state

Deleted but previously downloaded = read
This commit is contained in:
Geoffrey Frogeye 2021-12-29 12:56:07 +01:00
parent b0f14812d5
commit c36534f696

View file

@ -108,13 +108,15 @@ class RVElement:
parent: "RVDatabase" parent: "RVDatabase"
item: dict item: dict
downloaded_filepath: typing.Optional[str] downloaded_filepath: typing.Optional[str]
watched: bool
def __init__(self, parent: "RVDatabase", item: dict) -> None: def __init__(self, parent: "RVDatabase", item: dict) -> None:
self.parent = parent self.parent = parent
self.item = item self.item = item
self.downloaded_filepath = None self.downloaded_filepath = None
self.watched = False
@property
def id(self) -> str:
return self.item["id"]
@property @property
def title(self) -> str: def title(self) -> str:
@ -142,10 +144,9 @@ class RVElement:
log.debug(f"From cache: {self}") log.debug(f"From cache: {self}")
if cache.downloaded_filepath: if cache.downloaded_filepath:
self.downloaded_filepath = cache.downloaded_filepath self.downloaded_filepath = cache.downloaded_filepath
if cache.watched:
self.watched = True
def __str__(self) -> str: def __str__(self) -> str:
# return self.item.get("id")
str = f"{self.guid}: {self.creator if self.creator else '?'} {self.title}" str = f"{self.guid}: {self.creator if self.creator else '?'} {self.title}"
if self.is_researched: if self.is_researched:
if self.is_video: if self.is_video:
@ -232,6 +233,12 @@ class RVElement:
return return
self.download() 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: def matches_filter(self, args: configargparse.Namespace) -> bool:
# Inexpensive filters # Inexpensive filters
if args.seen != "any" and (args.seen == "seen") != self.watched: if args.seen != "any" and (args.seen == "seen") != self.watched:
@ -272,8 +279,8 @@ class RVElement:
proc = subprocess.run(cmd) proc = subprocess.run(cmd)
proc.check_returncode() proc.check_returncode()
self.watched = True self.clean()
self.parent.save() self.try_mark_read()
def clean(self) -> None: def clean(self) -> None:
assert self.is_video assert self.is_video
@ -284,6 +291,32 @@ class RVElement:
if not self.parent.args.dryrun: if not self.parent.args.dryrun:
os.unlink(file) 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: class RVDatabase:
SAVE_FILE = ".cache.p" SAVE_FILE = ".cache.p"
@ -478,6 +511,20 @@ class RVDatabase:
return elements 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: def get_args() -> configargparse.Namespace:
defaultConfigPath = os.path.join( defaultConfigPath = os.path.join(
@ -595,8 +642,6 @@ def get_args() -> configargparse.Namespace:
"watch", "watch",
"binge", "binge",
"clean", "clean",
"seen",
"unseen",
), ),
default="download", default="download",
) )
@ -654,6 +699,7 @@ def main() -> None:
else: else:
duration = 0 duration = 0
for element in database.filter(args): for element in database.filter(args):
duration += element.duration if element.is_video else 0
if args.action == "download": if args.action == "download":
element.preload() element.preload()
elif args.action == "list": elif args.action == "list":
@ -662,19 +708,11 @@ def main() -> None:
element.watch() element.watch()
if args.action == "watch": if args.action == "watch":
break 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: else:
raise NotImplementedError(f"Unimplemented action: {args.action}") raise NotImplementedError(f"Unimplemented action: {args.action}")
duration += element.duration if element.is_video else 0
log.info(f"Total duration: {format_duration(duration)}") log.info(f"Total duration: {format_duration(duration)}")
database.attempt_clean() database.attempt_clean()
database.try_mark_watched_read()
database.save() database.save()