Support generate audio report by year

This commit is contained in:
2024-09-16 21:52:53 +08:00
parent 9fee4fc572
commit 613f52218b
2 changed files with 62 additions and 17 deletions

View File

@@ -9,6 +9,7 @@ from .audio import (
from .cache import IdRelativeCache from .cache import IdRelativeCache
from .config import Config from .config import Config
from .db import PlaybackReportingDb, LibraryDb, JellyfinDb from .db import PlaybackReportingDb, LibraryDb, JellyfinDb
from .utils import gen_year_range, parse_datetime
p = ArgumentParser(prog="jellyfinstats") p = ArgumentParser(prog="jellyfinstats")
@@ -19,23 +20,58 @@ p.add_argument("--jellyfin-data-dir", help=_("The path to jellyfin data director
p.add_argument("--output-dir", help=_("The directory for output files.")) p.add_argument("--output-dir", help=_("The directory for output files."))
p.add_argument("--ask-page-size", help=_("Specify maximum items to display in one page."), type=int) # noqa: E501 p.add_argument("--ask-page-size", help=_("Specify maximum items to display in one page."), type=int) # noqa: E501
p.add_argument("--jellyfin-db", help=_("The path to jellyfin.db")) p.add_argument("--jellyfin-db", help=_("The path to jellyfin.db"))
p.add_argument("--fix", help=_("Fix incorrect play duration."), action='store_true', default=False) # noqa: E501 ps = p.add_subparsers(dest='action', help=_('sub-command help'), required=False, metavar='action') # noqa: E501
arg = p.parse_intermixed_args() audio = ps.add_parser('audio', help=_('Generate audio report.'))
audio.add_argument("--fix", help=_("Fix incorrect play duration."), action='store_true', default=False) # noqa: E501
audio.add_argument("-u", "--user", help=_("Generate report for specify users."), action='append', default=[]) # noqa: E501
audio.add_argument("-i", "--user-id", help=_("Generate report for specify users."), action='append', default=[]) # noqa: E501
audios = audio.add_subparsers(dest='type', help=_("Report type. Default: ") + "all", required=False, metavar='type') # noqa: E501
audio_all = audios.add_parser('all', help=_("All time report"))
audio_year = audios.add_parser('year', help=_("Year report"))
audio_year.add_argument('year', action='extend', nargs='*', help=_("Generate year report for specify years."), default=[], type=int) # noqa: E501
audio_year.add_argument('-s', '--start', help=_("The start year of range of years."), type=int) # noqa: E501
audio_year.add_argument('-e', '--end', help=_("The end year of range of years."), type=int) # noqa: E501
audio_year.add_argument('--utc', action='store_true', help=_("Use UTC time."), default=False) # noqa: E501
arg = p.parse_args()
if arg.action == 'a':
arg.action = 'audio'
cfg = Config(arg.config, arg) cfg = Config(arg.config, arg)
with PlaybackReportingDb(cfg.playback_reporting_db) as pdb: with PlaybackReportingDb(cfg.playback_reporting_db) as pdb:
if arg.fix: if arg.action == 'audio' and arg.fix:
fix_audio_report_library(pdb) fix_audio_report_library(pdb)
with LibraryDb(cfg.library_db) as ldb: with LibraryDb(cfg.library_db) as ldb:
with IdRelativeCache(cfg.output_dir) as icache: with IdRelativeCache(cfg.output_dir) as icache:
with JellyfinDb(cfg.jellyfin_db) as jdb: with JellyfinDb(cfg.jellyfin_db) as jdb:
re = prepare_audio_map(pdb, ldb, icache, cfg) if arg.action == 'audio':
users = pdb.get_users('Audio') if arg.type is None:
for u in users: arg.type = 'all'
userid = u['UserId'] re = prepare_audio_map(pdb, ldb, icache, cfg)
user = jdb.get_user(userid) users = pdb.get_users('Audio')
username = user['Username'] if user else userid for u in users:
output = join(cfg.output_dir, 'audio', username) userid = u['UserId']
maxDate = u['MaxDate'] user = jdb.get_user(userid)
minDate = u['MinDate'] username = user['Username'] if user else userid
generate_audio_report( if arg.user or arg.user_id:
pdb, re[0], re[1], re[2], output, userid) if username not in arg.user and userid not in arg.user_id: # noqa: E501
continue
output = join(cfg.output_dir, 'audio', username)
maxDate = u['MaxDate']
minDate = u['MinDate']
if arg.type == 'all':
generate_audio_report(
pdb, re[0], re[1], re[2], output, userid)
elif arg.type == 'year':
minTime = parse_datetime(minDate)
minYear = minTime.year
maxTime = parse_datetime(maxDate)
maxYear = maxTime.year
for year in range(minYear, maxYear + 1):
if arg.year and year not in arg.year:
continue
if arg.start is not None and year < arg.start:
continue
if arg.end is not None and year > arg.end:
continue
time = gen_year_range(year, arg.utc)
toutput = join(output, str(year))
generate_audio_report(pdb, re[0], re[1], re[2], toutput, userid, max(time[0], minTime.timestamp()), min(time[1], maxTime.timestamp())) # noqa: E501

View File

@@ -1,6 +1,7 @@
from math import ceil, floor from math import ceil, floor
from datetime import datetime, timezone from datetime import datetime, timezone
from re import compile from re import compile
from typing import Tuple
from . import _ from . import _
from .config import Config from .config import Config
@@ -78,10 +79,13 @@ def format_time(time: float | None = None, tz=timezone.utc) -> str:
return d.strftime('%Y-%m-%d %H:%M:%S.%f') return d.strftime('%Y-%m-%d %H:%M:%S.%f')
def parse_time(time: str) -> float: def parse_datetime(time: str) -> datetime:
re = DATETIME_RE.match(time) re = DATETIME_RE.match(time)
t = datetime(int(re[1]), int(re[2]), int(re[3]), int(re[4]), int(re[5]), int(re[6]), int(re[7].ljust(6, '0')), timezone.utc) # noqa: E501 return datetime(int(re[1]), int(re[2]), int(re[3]), int(re[4]), int(re[5]), int(re[6]), int(re[7].ljust(6, '0')), timezone.utc) # noqa: E501
return t.timestamp()
def parse_time(time: str) -> float:
return parse_datetime(time).timestamp()
def convert_uid(uid: str) -> str: def convert_uid(uid: str) -> str:
@@ -103,3 +107,8 @@ def format_duration(duration: float | None) -> str:
min = str(floor(duration / 60)).rjust(2, "0") min = str(floor(duration / 60)).rjust(2, "0")
sec = str(duration % 60).rjust(2, "0") sec = str(duration % 60).rjust(2, "0")
return f"{re}{min}:{sec}" return f"{re}{min}:{sec}"
def gen_year_range(year: int, utc: bool = False) -> Tuple[float, float]:
tz = timezone.utc if utc else None
return (datetime(year, 1, 1, tzinfo=tz).timestamp(), datetime(year, 12, 31, 23, 59, 59, 999999, tzinfo=tz).timestamp()) # noqa: E501