rssVideos: More sort orders and duration command

This commit is contained in:
Geoffrey Frogeye 2021-12-19 11:45:41 +01:00
parent 4890555668
commit 9684586eec
Signed by: geoffrey
GPG key ID: C72403E7F82E6AD8

View file

@ -17,6 +17,7 @@ import random
import re import re
import subprocess import subprocess
import sys import sys
import time
import typing import typing
import urllib.parse import urllib.parse
import urllib.request import urllib.request
@ -43,6 +44,9 @@ def configure_logging(args: configargparse.Namespace) -> None:
logger=log, logger=log,
) )
def format_duration(duration: int) -> int:
return time.strftime("%H:%M:%S", time.gmtime(duration))
class RVElement: class RVElement:
parent: "RVDatabase" parent: "RVDatabase"
@ -101,7 +105,7 @@ class RVElement:
return "ytdl_infos" in self.__dict__ return "ytdl_infos" in self.__dict__
def salvage_cache(self, cache: "RVElement") -> None: def salvage_cache(self, cache: "RVElement") -> None:
if cache.is_researched: if not self.parent.args.research and cache.is_researched:
self.__dict__["ytdl_infos"] = cache.__dict__["ytdl_infos"] self.__dict__["ytdl_infos"] = cache.__dict__["ytdl_infos"]
log.debug(f"From cache: {self}") log.debug(f"From cache: {self}")
if cache.was_downloaded: if cache.was_downloaded:
@ -110,7 +114,16 @@ class RVElement:
self.watched = True self.watched = True
def __str__(self) -> str: def __str__(self) -> str:
return f"{self.guid}: {self.creator} {self.title} {self.link}" str = f"{self.guid}: {self.creator if self.creator else '?'} {self.title}"
if self.is_researched:
if self.is_video:
str += f" ({format_duration(self.duration)})"
else:
str += " (N/A)"
else:
str += " (?)"
str += f" {self.link}"
return str
@property @property
def downloaded(self) -> bool: def downloaded(self) -> bool:
@ -194,6 +207,7 @@ class RVElement:
} }
def matches_filter(self, args: configargparse.Namespace) -> bool: def matches_filter(self, args: configargparse.Namespace) -> bool:
# Inexpensive filters
if args.seen != "any" and (args.seen == "seen") != self.watched: if args.seen != "any" and (args.seen == "seen") != self.watched:
log.debug(f"Not {args.seen}: {self}") log.debug(f"Not {args.seen}: {self}")
return False return False
@ -209,6 +223,8 @@ class RVElement:
if args.creator and (not self.creator or not re.search(args.creator, self.creator)): if args.creator and (not self.creator or not re.search(args.creator, self.creator)):
log.debug(f"Creator not matching {args.creator}: {self}") log.debug(f"Creator not matching {args.creator}: {self}")
return False return False
# Expensive filters
if not self.is_video: if not self.is_video:
log.debug(f"Not a video: {self}") log.debug(f"Not a video: {self}")
return False return False
@ -239,6 +255,7 @@ class RVElement:
if not comparator(self.duration, duration * multiplier): if not comparator(self.duration, duration * multiplier):
log.debug(f"Duration {self.duration} not matching {args.duration}: {self}") log.debug(f"Duration {self.duration} not matching {args.duration}: {self}")
return False return False
return True return True
def watch(self) -> None: def watch(self) -> None:
@ -378,15 +395,32 @@ class RVDatabase:
def filter(self, args: configargparse.Namespace) -> typing.Iterable[RVElement]: def filter(self, args: configargparse.Namespace) -> typing.Iterable[RVElement]:
elements: typing.Iterable[RVElement] elements: typing.Iterable[RVElement]
if args.order == "old": # Inexpensive sort
elements = self.elements if args.order == "new":
elif args.order == "new":
elements = reversed(self.elements) elements = reversed(self.elements)
elif args.order == "title":
elements = sorted(self.elements, key=lambda el: el.title)
elif args.order == "creator":
elements = sorted(self.elements, key=lambda el: el.creator or '')
elif args.order == "link":
elements = sorted(self.elements, key=lambda el: el.link)
elif args.order == "random": elif args.order == "random":
elements_random = self.elements.copy() elements_random = self.elements.copy()
random.shuffle(elements_random) random.shuffle(elements_random)
elements = elements_random elements = elements_random
return filter(lambda el: el.matches_filter(args), elements) else:
elements = self.elements
# Possibly expensive filtering
elements = filter(lambda el: el.matches_filter(args), elements)
# Expensive sort
if args.order == "short":
elements = sorted(elements, key=lambda el: el.duration if el.is_video else 0)
elif args.order == "short":
elements = sorted(elements, key=lambda el: el.duration if el.is_video else 0, reverse=True)
return elements
def get_args() -> configargparse.Namespace: def get_args() -> configargparse.Namespace:
@ -428,6 +462,11 @@ def get_args() -> configargparse.Namespace:
env_var="RSS_VIDEOS_FEED", env_var="RSS_VIDEOS_FEED",
required=True, required=True,
) )
parser.add(
"--research",
help="Fetch video info again",
action="store_true",
)
parser.add( parser.add(
"--videos", "--videos",
help="Directory to store videos", help="Directory to store videos",
@ -438,7 +477,7 @@ def get_args() -> configargparse.Namespace:
# Which videos # Which videos
parser.add( parser.add(
"--order", "--order",
choices=("old", "new", "random"), choices=("old", "new", "title", "creator", "link", "short", "long", "random"),
default="old", default="old",
help="Sorting mechanism", help="Sorting mechanism",
) )
@ -476,7 +515,7 @@ def get_args() -> configargparse.Namespace:
parser.add( parser.add(
"action", "action",
nargs="?", nargs="?",
choices=("download", "list", "watch", "binge", "clean", "seen", "unseen"), choices=("download", "list", "watch", "binge", "clean", "seen", "unseen", "duration"),
default="download", default="download",
) )
@ -515,6 +554,8 @@ def main() -> None:
database.clean() database.clean()
else: else:
database.attempt_clean() database.attempt_clean()
if args.action == "duration":
duration = 0
for element in database.filter(args): for element in database.filter(args):
if args.action == "download": if args.action == "download":
element.preload() element.preload()
@ -522,12 +563,18 @@ def main() -> None:
print(element) print(element)
elif args.action in ("watch", "binge"): elif args.action in ("watch", "binge"):
element.watch() element.watch()
if args.action == "watch":
break
elif args.action == "seen": elif args.action == "seen":
element.watched = True element.watched = True
elif args.action == "unseen": elif args.action == "unseen":
element.watched = False element.watched = False
if args.action == "watch": elif args.action == "duration":
break duration += element.duration
else:
raise NotImplementedError(f"Unimplemented action: {args.action}")
if args.action == "duration":
print(format_duration(duration))
database.attempt_clean() database.attempt_clean()
database.save() database.save()