Support generate audio report by year
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user