rssVideos: More sort orders and duration command
This commit is contained in:
parent
4890555668
commit
9684586eec
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in a new issue