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 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()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue