rssVideos: --total-duration
Controleld binging
This commit is contained in:
parent
00a9da6afc
commit
5b7926df8f
|
@ -62,6 +62,45 @@ class SaveInfoPP(yt_dlp.postprocessor.common.PostProcessor):
|
|||
self.rvelement.ytdl_infos = info
|
||||
return [], info
|
||||
|
||||
def parse_duration(string: str) -> int:
|
||||
DURATION_MULTIPLIERS = {"s": 1, "m": 60, "h": 3600, "": 1}
|
||||
|
||||
mult_index = string[-1].lower()
|
||||
if mult_index.isdigit():
|
||||
mult_index = ""
|
||||
else:
|
||||
string = string[:-1]
|
||||
try:
|
||||
multiplier = DURATION_MULTIPLIERS[mult_index]
|
||||
except IndexError:
|
||||
raise ValueError(f"Unknown duration multiplier: {mult_index}")
|
||||
|
||||
return int(string) * multiplier
|
||||
|
||||
|
||||
def compare_duration(compstr: str) -> typing.Callable[[int], bool]:
|
||||
DURATION_COMPARATORS = {
|
||||
"<": int.__lt__,
|
||||
"-": int.__lt__,
|
||||
">": int.__gt__,
|
||||
"+": int.__gt__,
|
||||
"=": int.__eq__,
|
||||
"": int.__le__,
|
||||
}
|
||||
|
||||
comp_index = compstr[0]
|
||||
if comp_index.isdigit():
|
||||
comp_index = ""
|
||||
else:
|
||||
compstr = compstr[1:]
|
||||
try:
|
||||
comparator = DURATION_COMPARATORS[comp_index]
|
||||
except IndexError:
|
||||
raise ValueError(f"Unknown duration comparator: {comp_index}")
|
||||
|
||||
duration = parse_duration(compstr)
|
||||
|
||||
return lambda d: comparator(d, duration)
|
||||
|
||||
def format_duration(duration: int) -> str:
|
||||
return time.strftime("%H:%M:%S", time.gmtime(duration))
|
||||
|
@ -152,6 +191,7 @@ class RVElement:
|
|||
|
||||
@functools.cached_property
|
||||
def ytdl_infos(self) -> typing.Optional[dict]:
|
||||
# TODO Sanitize according to documentation
|
||||
log.info(f"Researching: {self}")
|
||||
try:
|
||||
infos = self.parent.ytdl_dry.extract_info(self.link, download=False)
|
||||
|
@ -215,17 +255,6 @@ class RVElement:
|
|||
return
|
||||
self.download()
|
||||
|
||||
MATCHES_DURATION_MULTIPLIERS = {"s": 1, "m": 60, "h": 3600, None: 1}
|
||||
|
||||
MATCHES_DURATION_COMPARATORS = {
|
||||
"<": int.__lt__,
|
||||
"-": int.__lt__,
|
||||
">": int.__gt__,
|
||||
"+": int.__gt__,
|
||||
"=": int.__eq__,
|
||||
None: int.__le__,
|
||||
}
|
||||
|
||||
def matches_filter(self, args: configargparse.Namespace) -> bool:
|
||||
# Inexpensive filters
|
||||
if args.seen != "any" and (args.seen == "seen") != self.watched:
|
||||
|
@ -250,35 +279,11 @@ class RVElement:
|
|||
if not self.is_video:
|
||||
log.debug(f"Not a video: {self}")
|
||||
return False
|
||||
if args.duration:
|
||||
dur = args.duration
|
||||
|
||||
mult_index = dur[-1].lower()
|
||||
if mult_index.isdigit():
|
||||
mult_index = None
|
||||
else:
|
||||
dur = dur[:-1]
|
||||
try:
|
||||
multiplier = self.MATCHES_DURATION_MULTIPLIERS[mult_index]
|
||||
except IndexError:
|
||||
raise ValueError(f"Unknown duration multiplier: {mult_index}")
|
||||
|
||||
comp_index = dur[0]
|
||||
if comp_index.isdigit():
|
||||
comp_index = None
|
||||
else:
|
||||
dur = dur[1:]
|
||||
try:
|
||||
comparator = self.MATCHES_DURATION_COMPARATORS[comp_index]
|
||||
except IndexError:
|
||||
raise ValueError(f"Unknown duration comparator: {comp_index}")
|
||||
|
||||
duration = int(dur)
|
||||
if not comparator(self.duration, duration * multiplier):
|
||||
log.debug(
|
||||
f"Duration {self.duration} not matching {args.duration}: {self}"
|
||||
)
|
||||
return False
|
||||
if args.duration and not compare_duration(args.duration)(self.duration):
|
||||
log.debug(
|
||||
f"Duration {self.duration} not matching {args.duration}: {self}"
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
@ -439,11 +444,26 @@ class RVDatabase:
|
|||
elements = sorted(
|
||||
elements, key=lambda el: el.duration if el.is_video else 0
|
||||
)
|
||||
elif args.order == "short":
|
||||
elif args.order == "long":
|
||||
elements = sorted(
|
||||
elements, key=lambda el: el.duration if el.is_video else 0, reverse=True
|
||||
)
|
||||
|
||||
# Post sorting filtering
|
||||
if args.total_duration:
|
||||
rem = parse_duration(args.total_duration)
|
||||
old_els = list(elements)
|
||||
elements = list()
|
||||
while rem > 0:
|
||||
for el in old_els:
|
||||
if el.duration < rem:
|
||||
elements.append(el)
|
||||
rem -= el.duration
|
||||
old_els.remove(el)
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
return elements
|
||||
|
||||
|
||||
|
@ -522,6 +542,10 @@ def get_args() -> configargparse.Namespace:
|
|||
default="unseen",
|
||||
help="Only include seen/unseen/any videos",
|
||||
)
|
||||
parser.add(
|
||||
"--total-duration",
|
||||
help="Use videos that fit under the total given",
|
||||
)
|
||||
# TODO Envrionment variables
|
||||
parser.add(
|
||||
"--max-duration",
|
||||
|
@ -558,7 +582,6 @@ def get_args() -> configargparse.Namespace:
|
|||
"clean",
|
||||
"seen",
|
||||
"unseen",
|
||||
"duration",
|
||||
),
|
||||
default="download",
|
||||
)
|
||||
|
@ -606,8 +629,7 @@ def main() -> None:
|
|||
database.clean()
|
||||
else:
|
||||
database.attempt_clean()
|
||||
if args.action == "duration":
|
||||
duration = 0
|
||||
duration = 0
|
||||
for element in database.filter(args):
|
||||
if args.action == "download":
|
||||
element.preload()
|
||||
|
@ -625,12 +647,10 @@ def main() -> None:
|
|||
if element.watched:
|
||||
log.info(f"Maked as unseen: {element}")
|
||||
element.watched = False
|
||||
elif args.action == "duration":
|
||||
duration += element.duration
|
||||
else:
|
||||
raise NotImplementedError(f"Unimplemented action: {args.action}")
|
||||
if args.action == "duration":
|
||||
print(format_duration(duration))
|
||||
duration += element.duration if element.is_video else 0
|
||||
log.info(f"Total duration: {format_duration(duration)}")
|
||||
database.attempt_clean()
|
||||
database.save()
|
||||
|
||||
|
|
Loading…
Reference in a new issue