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
1 changed files with 57 additions and 10 deletions

View File

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