diff --git a/jellyfinstats/__main__.py b/jellyfinstats/__main__.py index 33ba6f4..3d34f6c 100644 --- a/jellyfinstats/__main__.py +++ b/jellyfinstats/__main__.py @@ -1,7 +1,11 @@ from argparse import ArgumentParser from os.path import join from . import _ -from .audio import prepare_audio_map, generate_audio_report +from .audio import ( + prepare_audio_map, + generate_audio_report, + fix_audio_report_library, +) from .cache import IdRelativeCache from .config import Config from .db import PlaybackReportingDb, LibraryDb, JellyfinDb @@ -15,9 +19,12 @@ 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("--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("--fix", help=_("Fix incorrect play duration."), action='store_true', default=False) # noqa: E501 arg = p.parse_intermixed_args() cfg = Config(arg.config, arg) with PlaybackReportingDb(cfg.playback_reporting_db) as pdb: + if arg.fix: + fix_audio_report_library(pdb) with LibraryDb(cfg.library_db) as ldb: with IdRelativeCache(cfg.output_dir) as icache: with JellyfinDb(cfg.jellyfin_db) as jdb: @@ -30,4 +37,5 @@ with PlaybackReportingDb(cfg.playback_reporting_db) as pdb: output = join(cfg.output_dir, 'audio', username) maxDate = u['MaxDate'] minDate = u['MinDate'] - generate_audio_report(pdb, re[0], re[1], re[2], output, userid) + generate_audio_report( + pdb, re[0], re[1], re[2], output, userid) diff --git a/jellyfinstats/audio.py b/jellyfinstats/audio.py index 3f7bbbf..80ca03e 100644 --- a/jellyfinstats/audio.py +++ b/jellyfinstats/audio.py @@ -8,7 +8,7 @@ from datetime import datetime from re import compile from os import makedirs from os.path import join -from math import floor +from math import ceil, floor ITEMNAME_PATTERN = compile(r'(?P.*) - (?P.*) \((?P.*)\)') # noqa: E501 @@ -405,3 +405,31 @@ def generate_audio_report(pdb: PlaybackReportingDb, itemMap, rowMap, albumMap, for artist in alArtCountMap: count = alArtCountMap[artist] alAr.write(artist, count['count'], count['play_count'], format_duration(count['duration']), count['duration']) # noqa: E501 + + +def fix_audio_report_library(pdb: PlaybackReportingDb): + clients = pdb.get_client_devices() + for client in clients: + clientName = client['ClientName'] + deviceName = client['DeviceName'] + prev = None + offset = 0 + data = pdb.get_activitys(offset, itemType='Audio', + clientName=clientName, + deviceName=deviceName) + while len(data) > 0: + for i in data: + if prev is None: + prev = i + continue + delta = ceil(parse_time( + i['DateCreated']) - parse_time(prev['DateCreated'])) + dur = prev['PlayDuration'] + if delta < dur - 1: + print(f'Change song(id={prev["rowid"]}) play duration from {dur} to {delta}') # noqa: E501 + pdb.update_playduration(prev["rowid"], delta) + prev = i + offset += len(data) + data = pdb.get_activitys(offset, itemType='Audio', + clientName=clientName, + deviceName=deviceName) diff --git a/jellyfinstats/db.py b/jellyfinstats/db.py index e59953e..d243b3e 100644 --- a/jellyfinstats/db.py +++ b/jellyfinstats/db.py @@ -21,7 +21,8 @@ class PlaybackReportingDb: def get_activitys(self, offset: int = 0, limit: int = 100, itemType: str = None, userId: str = None, - startTime: float = None, endTime: float = None): + startTime: float = None, endTime: float = None, + clientName: str = None, deviceName: str = None): where_sqls = [] where_sql = '' args = [] @@ -37,6 +38,12 @@ class PlaybackReportingDb: if endTime is not None: where_sqls.append('DateCreated <= ?') args.append(format_time(endTime)) + if clientName is not None: + where_sqls.append("ClientName = ?") + args.append(clientName) + if deviceName is not None: + where_sqls.append("DeviceName = ?") + args.append(deviceName) if len(where_sqls): where_sql = ' WHERE ' + " AND ".join(where_sqls) args.append(limit) @@ -45,6 +52,11 @@ class PlaybackReportingDb: cur.row_factory = sqlite3.Row return [dict(i) for i in cur.fetchall()] + def get_client_devices(self): + cur = self._db.execute("SELECT ClientName, DeviceName FROM PlaybackActivity GROUP BY ClientName, DeviceName;") # noqa: E501 + cur.row_factory = sqlite3.Row + return [dict(i) for i in cur.fetchall()] + def get_users(self, itemType: str = None): where_sql = '' args = [] @@ -55,6 +67,9 @@ class PlaybackReportingDb: cur.row_factory = sqlite3.Row return [dict(i) for i in cur.fetchall()] + def update_playduration(self, rowid: int, duration: int): + self._db.execute("UPDATE PlaybackActivity SET PlayDuration = ? WHERE rowid = ?;", [duration, rowid]) # noqa: E501 + class LibraryDb: def __init__(self, fn: str):