Update code
This commit is contained in:
@@ -30,4 +30,4 @@ 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], output, userid)
|
||||
generate_audio_report(pdb, re[0], re[1], re[2], output, userid)
|
||||
|
||||
@@ -3,14 +3,17 @@ from .cache import IdRelativeCache
|
||||
from .config import Config
|
||||
from .csv import CSVFile
|
||||
from .db import PlaybackReportingDb, LibraryDb
|
||||
from .utils import ask_choice, parse_time
|
||||
from .utils import ask_choice, format_duration, parse_time
|
||||
from datetime import datetime
|
||||
from re import compile
|
||||
from os import makedirs
|
||||
from os.path import join
|
||||
from math import floor
|
||||
|
||||
|
||||
ITEMNAME_PATTERN = compile(r'(?P<album_artist>.*) - (?P<track>.*) \((?P<album>.*)\)') # noqa: E501
|
||||
NOT_KNOWN = "Not Known"
|
||||
TIME_BASE = 10_000_000
|
||||
|
||||
|
||||
def print_item(item):
|
||||
@@ -155,9 +158,9 @@ def prepare_audio_map(pdb: PlaybackReportingDb, ldb: LibraryDb,
|
||||
if re is None:
|
||||
raise ValueError(f"Failed to parse ItemName: {itemName}")
|
||||
re = re.groupdict()
|
||||
if re['album_artist'] == 'Not Known':
|
||||
if re['album_artist'] == NOT_KNOWN:
|
||||
re['album_artist'] = None
|
||||
if re['album'] == 'Not Known':
|
||||
if re['album'] == NOT_KNOWN:
|
||||
re['album'] = None
|
||||
items = ldb.get_audios(re['track'], re['album'])
|
||||
if len(items) == 1:
|
||||
@@ -184,18 +187,57 @@ def prepare_audio_map(pdb: PlaybackReportingDb, ldb: LibraryDb,
|
||||
rowMap[rowid] = itemId
|
||||
offset += len(data)
|
||||
data = pdb.get_activitys(offset, itemType='Audio')
|
||||
return itemMap, rowMap
|
||||
albumMap = {}
|
||||
for itemId in itemMap:
|
||||
item = itemMap[itemId]
|
||||
album = ''
|
||||
album_artists = ''
|
||||
if 'type' in item:
|
||||
album = item['Album']
|
||||
album_artists = item['AlbumArtists']
|
||||
else:
|
||||
it = ITEMNAME_PATTERN.match(item['ItemName']).groupdict()
|
||||
if it['album'] != NOT_KNOWN:
|
||||
album = it['album']
|
||||
if it['album_artist'] != NOT_KNOWN:
|
||||
album_artists = it['album_artist']
|
||||
if album:
|
||||
if album not in albumMap:
|
||||
album_artists = album_artists if album_artists else None
|
||||
items = ldb.get_albums(album, album_artists)
|
||||
if len(items) == 0:
|
||||
items = ldb.get_albums(album)
|
||||
if len(items) == 1:
|
||||
albumMap[album] = items[0]
|
||||
elif len(items) > 1:
|
||||
print(len(items))
|
||||
raise NotImplementedError('FIX ME')
|
||||
else:
|
||||
data = {'name': album}
|
||||
if 'type' in item:
|
||||
data['album_artists'] = item['AlbumArtists']
|
||||
data['date'] = item['PremiereDate']
|
||||
data['year'] = item['ProductionYear']
|
||||
data['publisher'] = item['Studios']
|
||||
else:
|
||||
data['album_artists'] = album_artists
|
||||
data['date'] = None
|
||||
data['year'] = None
|
||||
data['publisher'] = None
|
||||
albumMap[album] = data
|
||||
return itemMap, rowMap, albumMap
|
||||
|
||||
|
||||
def generate_audio_report(pdb: PlaybackReportingDb, itemMap, rowMap,
|
||||
def generate_audio_report(pdb: PlaybackReportingDb, itemMap, rowMap, albumMap,
|
||||
output: str, userId: str = None,
|
||||
startTime: float = None, endTime: float = None):
|
||||
makedirs(output, exist_ok=True)
|
||||
offset = 0
|
||||
data = pdb.get_activitys(offset, itemType='Audio', userId=userId,
|
||||
startTime=startTime, endTime=endTime)
|
||||
albumCountMap = {}
|
||||
with CSVFile(join(output, "history.csv")) as his:
|
||||
his.write(_("Id"), _("Date"), _("Time"), _("Name"), _("Artists"), _("Album"), _("Album artists"), _("Original item id"), _("Item id"), _("Play Duration"), _("Record content"), _("Client name"), _("Device name"), _("Playback method")) # noqa: E501
|
||||
his.write(_("Id"), _("Date"), _("Time"), _("Name"), _("Artists"), _("Album"), _("Album artists"), _("Duration"), _("Duration") + _("(seconds)"), _("Original item id"), _("Item id"), _("Play duration"), _("Play duration") + _("(seconds)"), _("Record content"), _("Client name"), _("Device name"), _("Playback method"), _("Play count")) # noqa: E501
|
||||
while len(data) > 0:
|
||||
for i in data:
|
||||
rowid = i['rowid']
|
||||
@@ -211,19 +253,66 @@ def generate_audio_report(pdb: PlaybackReportingDb, itemMap, rowMap,
|
||||
album_artists = ''
|
||||
original_item_id = i['ItemId']
|
||||
play_duration = i['PlayDuration']
|
||||
duration = None
|
||||
play_count = 1
|
||||
if 'type' in item:
|
||||
name = item['Name']
|
||||
artists = item['Artists']
|
||||
album = item['Album']
|
||||
album_artists = item['AlbumArtists']
|
||||
duration = item['RunTimeTicks'] / 10_000_000
|
||||
play_count = floor(play_duration / duration)
|
||||
extrad = play_duration % duration
|
||||
if extrad > 60 or extrad > duration * 0.95:
|
||||
play_count += 1
|
||||
else:
|
||||
it = ITEMNAME_PATTERN.match(item['ItemName']).groupdict()
|
||||
name = it['track']
|
||||
if it['album'] != 'Not Known':
|
||||
if it['album'] != NOT_KNOWN:
|
||||
album = it['album']
|
||||
if it['album_artist'] != "Not Known":
|
||||
if it['album_artist'] != NOT_KNOWN:
|
||||
album_artists = it['album_artist']
|
||||
his.write(rowid, date, time, name, artists, album, album_artists, original_item_id, itemId, play_duration, i['ItemName'], i['ClientName'], i['DeviceName'], i['PlaybackMethod']) # noqa: E501
|
||||
his.write(rowid, date, time, name, artists, album, album_artists, format_duration(duration), duration, original_item_id, itemId, format_duration(play_duration), play_duration, i['ItemName'], i['ClientName'], i['DeviceName'], i['PlaybackMethod'], play_count) # noqa: E501
|
||||
if album:
|
||||
if album in albumCountMap:
|
||||
tmp = albumCountMap[album]
|
||||
tmp['count'] += 1
|
||||
tmp['play_count'] += play_count
|
||||
tmp['duration'] += play_duration
|
||||
else:
|
||||
albumCountMap[album] = {'count': 1,
|
||||
'play_count': play_count,
|
||||
'duration': play_duration}
|
||||
offset += len(data)
|
||||
data = pdb.get_activitys(offset, itemType='Audio', userId=userId,
|
||||
startTime=startTime, endTime=endTime)
|
||||
with CSVFile(join(output, 'album.csv')) as al:
|
||||
al.write(_("Name"), _("Album artists"), _("Artists"), _("Record count"), _("Play count"), _("Play duration"), _("Play duration") + _("(seconds)"), _("Duration"), _("Duration") + _("(seconds)"), _("Year"), _("Publish date"), _("Publisher"), _("Item id")) # noqa: E501
|
||||
for album in albumCountMap:
|
||||
if album not in albumMap:
|
||||
continue
|
||||
item = albumMap[album]
|
||||
album_artists = ''
|
||||
artists = ''
|
||||
count = albumCountMap[album]
|
||||
duration = None
|
||||
year = None
|
||||
publisher = None
|
||||
itemId = None
|
||||
if 'type' in item:
|
||||
album_artists = item['AlbumArtists']
|
||||
artists = item['Artists']
|
||||
duration = item['RunTimeTicks'] / TIME_BASE
|
||||
year = item['ProductionYear']
|
||||
date = item['PremiereDate']
|
||||
publisher = item['Studios']
|
||||
itemId = item['PresentationUniqueKey']
|
||||
else:
|
||||
album_artists = item['album_artists']
|
||||
year = item['year']
|
||||
date = item['date']
|
||||
publisher = item['publisher']
|
||||
if year and date:
|
||||
if date.endswith("-01-01 00:00:00"):
|
||||
date = None
|
||||
al.write(album, album_artists, artists, count['count'], count['play_count'], format_duration(count['duration']), count['duration'], format_duration(duration), duration, year, date, publisher, itemId) # noqa: E501
|
||||
|
||||
@@ -58,7 +58,9 @@ def writeField(f: IO[bytes], *k):
|
||||
f.write(b',')
|
||||
else:
|
||||
a = True
|
||||
if isinstance(i, bool):
|
||||
if i is None:
|
||||
i = ''
|
||||
elif isinstance(i, bool):
|
||||
i = str(int(i))
|
||||
elif isinstance(i, Enum):
|
||||
i = str(i.value)
|
||||
|
||||
@@ -97,6 +97,19 @@ class LibraryDb:
|
||||
cur.row_factory = sqlite3.Row
|
||||
return [dict(i) for i in cur.fetchall()]
|
||||
|
||||
def get_albums(self, album: str = None, albumArtists: str = None):
|
||||
args = ['MediaBrowser.Controller.Entities.Audio.MusicAlbum']
|
||||
where_sql = ''
|
||||
if album is not None:
|
||||
where_sql += ' AND Name = ?'
|
||||
args.append(album)
|
||||
if albumArtists is not None:
|
||||
where_sql += ' AND AlbumArtists = ?'
|
||||
args.append(albumArtists)
|
||||
cur = self._db.execute(f"SELECT * FROM TypedBaseItems WHERE type = ?{where_sql};", args) # noqa: E501
|
||||
cur.row_factory = sqlite3.Row
|
||||
return [dict(i) for i in cur.fetchall()]
|
||||
|
||||
|
||||
class JellyfinDb:
|
||||
def __init__(self, fn: str):
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: jellyfinStats 1.0\n"
|
||||
"Report-Msgid-Bugs-To: [email protected]\n"
|
||||
"POT-Creation-Date: 2024-05-15 13:56+0800\n"
|
||||
"POT-Creation-Date: 2024-05-16 10:47+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <[email protected]>\n"
|
||||
@@ -17,102 +17,190 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: __main__.py:10
|
||||
#: __main__.py:20
|
||||
msgid "The path to config file."
|
||||
msgstr ""
|
||||
|
||||
#: __main__.py:11
|
||||
#: __main__.py:21
|
||||
msgid "The path to playback_reporting.db"
|
||||
msgstr ""
|
||||
|
||||
#: __main__.py:12
|
||||
#: __main__.py:22
|
||||
msgid "The path to library.db"
|
||||
msgstr ""
|
||||
|
||||
#: __main__.py:13
|
||||
#: __main__.py:23
|
||||
msgid "The path to jellyfin data directory."
|
||||
msgstr ""
|
||||
|
||||
#: __main__.py:14
|
||||
#: __main__.py:24
|
||||
msgid "The directory for output files."
|
||||
msgstr ""
|
||||
|
||||
#: __main__.py:15
|
||||
#: __main__.py:25
|
||||
msgid "Specify maximum items to display in one page."
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:15 audio.py:35
|
||||
#: __main__.py:26
|
||||
msgid "The path to jellyfin.db"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:22 audio.py:42
|
||||
msgid "Album: "
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:17
|
||||
#: audio.py:24
|
||||
msgid "Artists: "
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:19 audio.py:37
|
||||
#: audio.py:26 audio.py:44
|
||||
msgid "Album artists: "
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:33
|
||||
#: audio.py:40
|
||||
msgid "Original item: "
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:40 audio.py:77
|
||||
#: audio.py:47 audio.py:84
|
||||
msgid "Please choose audio item:"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:40 audio.py:48 audio.py:74
|
||||
#: audio.py:47 audio.py:55 audio.py:81
|
||||
msgid "No item"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:40
|
||||
#: audio.py:47
|
||||
msgid "Choose other items"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:48
|
||||
#: audio.py:55
|
||||
msgid "Input item id"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:48
|
||||
#: audio.py:55
|
||||
msgid "Input track name"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:48
|
||||
#: audio.py:55
|
||||
msgid "Input album name"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:50 audio.py:76
|
||||
#: audio.py:57 audio.py:83
|
||||
msgid "Choose in given choices"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:51
|
||||
#: audio.py:58
|
||||
msgid "Please choose action: "
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:64
|
||||
#: audio.py:71
|
||||
msgid "Please input item id:"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:69
|
||||
#: audio.py:76
|
||||
msgid "Item not found."
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:74
|
||||
#: audio.py:81
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:85
|
||||
#: audio.py:92
|
||||
msgid "Items not found."
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:89
|
||||
#: audio.py:96
|
||||
msgid "Please input track name:"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:94
|
||||
#: audio.py:101
|
||||
msgid "Please input album name:"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Id"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Date"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Time"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Artists"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Album"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Album artists"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Duration"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "(seconds)"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Original item id"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Item id"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Play duration"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Record content"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Client name"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Device name"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Playback method"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Play count"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:290
|
||||
msgid "Record count"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:290
|
||||
msgid "Year"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:290
|
||||
msgid "Publish date"
|
||||
msgstr ""
|
||||
|
||||
#: audio.py:290
|
||||
msgid "Publisher"
|
||||
msgstr ""
|
||||
|
||||
#: cache.py:23
|
||||
msgid "Unsupported version: "
|
||||
msgstr ""
|
||||
@@ -121,32 +209,37 @@ msgstr ""
|
||||
msgid "Failed to load cache."
|
||||
msgstr ""
|
||||
|
||||
#: config.py:40 config.py:51
|
||||
#: config.py:40 config.py:51 config.py:69
|
||||
#, python-format
|
||||
msgid "%s not set."
|
||||
msgstr ""
|
||||
|
||||
#: utils.py:6
|
||||
#: utils.py:11
|
||||
msgid "Please choose: "
|
||||
msgstr ""
|
||||
|
||||
#: utils.py:23
|
||||
#: utils.py:28
|
||||
#, python-format
|
||||
msgid "Page %i/%i"
|
||||
msgstr ""
|
||||
|
||||
#: utils.py:31
|
||||
#: utils.py:36
|
||||
msgid "First page"
|
||||
msgstr ""
|
||||
|
||||
#: utils.py:33
|
||||
#: utils.py:38
|
||||
msgid "Previous page"
|
||||
msgstr ""
|
||||
|
||||
#: utils.py:36
|
||||
#: utils.py:41
|
||||
msgid "Next page"
|
||||
msgstr ""
|
||||
|
||||
#: utils.py:38
|
||||
#: utils.py:43
|
||||
msgid "Last page"
|
||||
msgstr ""
|
||||
|
||||
#: utils.py:97
|
||||
#, python-format
|
||||
msgid "%i day"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: jellyfinStats 1.0\n"
|
||||
"Report-Msgid-Bugs-To: [email protected]\n"
|
||||
"POT-Creation-Date: 2024-05-15 13:56+0800\n"
|
||||
"POT-Creation-Date: 2024-05-16 10:47+0800\n"
|
||||
"PO-Revision-Date: 2024-05-15 10:20+0800\n"
|
||||
"Last-Translator: mhy <[email protected]>\n"
|
||||
"Language-Team: Chinese (simplified) <[email protected]>\n"
|
||||
@@ -16,102 +16,190 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: __main__.py:10
|
||||
#: __main__.py:20
|
||||
msgid "The path to config file."
|
||||
msgstr "配置文件位置。"
|
||||
|
||||
#: __main__.py:11
|
||||
#: __main__.py:21
|
||||
msgid "The path to playback_reporting.db"
|
||||
msgstr "playback_reporting.db 文件位置。"
|
||||
|
||||
#: __main__.py:12
|
||||
#: __main__.py:22
|
||||
msgid "The path to library.db"
|
||||
msgstr "library.db 文件位置。"
|
||||
|
||||
#: __main__.py:13
|
||||
#: __main__.py:23
|
||||
msgid "The path to jellyfin data directory."
|
||||
msgstr "Jellyfin 数据目录位置。"
|
||||
|
||||
#: __main__.py:14
|
||||
#: __main__.py:24
|
||||
msgid "The directory for output files."
|
||||
msgstr "输出目录位置。"
|
||||
|
||||
#: __main__.py:15
|
||||
#: __main__.py:25
|
||||
msgid "Specify maximum items to display in one page."
|
||||
msgstr "指定一页可以显示的最大条目数。"
|
||||
|
||||
#: audio.py:15 audio.py:35
|
||||
#: __main__.py:26
|
||||
msgid "The path to jellyfin.db"
|
||||
msgstr "jellyfin.db 文件位置。"
|
||||
|
||||
#: audio.py:22 audio.py:42
|
||||
msgid "Album: "
|
||||
msgstr "专辑:"
|
||||
|
||||
#: audio.py:17
|
||||
#: audio.py:24
|
||||
msgid "Artists: "
|
||||
msgstr "艺术家:"
|
||||
|
||||
#: audio.py:19 audio.py:37
|
||||
#: audio.py:26 audio.py:44
|
||||
msgid "Album artists: "
|
||||
msgstr "专辑艺术家:"
|
||||
|
||||
#: audio.py:33
|
||||
#: audio.py:40
|
||||
msgid "Original item: "
|
||||
msgstr "原项目:"
|
||||
|
||||
#: audio.py:40 audio.py:77
|
||||
#: audio.py:47 audio.py:84
|
||||
msgid "Please choose audio item:"
|
||||
msgstr "请选择音乐项目:"
|
||||
|
||||
#: audio.py:40 audio.py:48 audio.py:74
|
||||
#: audio.py:47 audio.py:55 audio.py:81
|
||||
msgid "No item"
|
||||
msgstr "无对应项目"
|
||||
|
||||
#: audio.py:40
|
||||
#: audio.py:47
|
||||
msgid "Choose other items"
|
||||
msgstr "选择其他项目"
|
||||
|
||||
#: audio.py:48
|
||||
#: audio.py:55
|
||||
msgid "Input item id"
|
||||
msgstr "输入项目ID"
|
||||
|
||||
#: audio.py:48
|
||||
#: audio.py:55
|
||||
msgid "Input track name"
|
||||
msgstr "输入标题"
|
||||
|
||||
#: audio.py:48
|
||||
#: audio.py:55
|
||||
msgid "Input album name"
|
||||
msgstr "输入专辑名称"
|
||||
|
||||
#: audio.py:50 audio.py:76
|
||||
#: audio.py:57 audio.py:83
|
||||
msgid "Choose in given choices"
|
||||
msgstr "从给出的选项中选择"
|
||||
|
||||
#: audio.py:51
|
||||
#: audio.py:58
|
||||
msgid "Please choose action: "
|
||||
msgstr "请选择方式:"
|
||||
|
||||
#: audio.py:64
|
||||
#: audio.py:71
|
||||
msgid "Please input item id:"
|
||||
msgstr "请输入项目ID:"
|
||||
|
||||
#: audio.py:69
|
||||
#: audio.py:76
|
||||
msgid "Item not found."
|
||||
msgstr "没有找到项目。"
|
||||
|
||||
#: audio.py:74
|
||||
#: audio.py:81
|
||||
msgid "Back"
|
||||
msgstr "返回"
|
||||
|
||||
#: audio.py:85
|
||||
#: audio.py:92
|
||||
msgid "Items not found."
|
||||
msgstr "没有找到项目。"
|
||||
|
||||
#: audio.py:89
|
||||
#: audio.py:96
|
||||
msgid "Please input track name:"
|
||||
msgstr "请输入标题:"
|
||||
|
||||
#: audio.py:94
|
||||
#: audio.py:101
|
||||
msgid "Please input album name:"
|
||||
msgstr "请输入专辑名称:"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Id"
|
||||
msgstr "ID"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Date"
|
||||
msgstr "日期"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Time"
|
||||
msgstr "时间"
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Name"
|
||||
msgstr "名称"
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Artists"
|
||||
msgstr "艺术家"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Album"
|
||||
msgstr "专辑"
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Album artists"
|
||||
msgstr "专辑艺术家"
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Duration"
|
||||
msgstr "时长"
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "(seconds)"
|
||||
msgstr "(秒)"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Original item id"
|
||||
msgstr "原项目ID"
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Item id"
|
||||
msgstr "项目ID"
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Play duration"
|
||||
msgstr "播放时长"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Record content"
|
||||
msgstr "记录内容"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Client name"
|
||||
msgstr "客户端名称"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Device name"
|
||||
msgstr "设备名称"
|
||||
|
||||
#: audio.py:240
|
||||
msgid "Playback method"
|
||||
msgstr "播放方式"
|
||||
|
||||
#: audio.py:240 audio.py:290
|
||||
msgid "Play count"
|
||||
msgstr "播放次数"
|
||||
|
||||
#: audio.py:290
|
||||
msgid "Record count"
|
||||
msgstr "记录次数"
|
||||
|
||||
#: audio.py:290
|
||||
msgid "Year"
|
||||
msgstr "年份"
|
||||
|
||||
#: audio.py:290
|
||||
msgid "Publish date"
|
||||
msgstr "发布日期"
|
||||
|
||||
#: audio.py:290
|
||||
msgid "Publisher"
|
||||
msgstr "发布者"
|
||||
|
||||
#: cache.py:23
|
||||
msgid "Unsupported version: "
|
||||
msgstr "不支持的版本:"
|
||||
@@ -120,32 +208,37 @@ msgstr "不支持的版本:"
|
||||
msgid "Failed to load cache."
|
||||
msgstr "加载缓存失败。"
|
||||
|
||||
#: config.py:40 config.py:51
|
||||
#: config.py:40 config.py:51 config.py:69
|
||||
#, python-format
|
||||
msgid "%s not set."
|
||||
msgstr "%s 未设置。"
|
||||
|
||||
#: utils.py:6
|
||||
#: utils.py:11
|
||||
msgid "Please choose: "
|
||||
msgstr "请选择:"
|
||||
|
||||
#: utils.py:23
|
||||
#: utils.py:28
|
||||
#, python-format
|
||||
msgid "Page %i/%i"
|
||||
msgstr "第%i/%i页"
|
||||
|
||||
#: utils.py:31
|
||||
#: utils.py:36
|
||||
msgid "First page"
|
||||
msgstr "第一页"
|
||||
|
||||
#: utils.py:33
|
||||
#: utils.py:38
|
||||
msgid "Previous page"
|
||||
msgstr "上一页"
|
||||
|
||||
#: utils.py:36
|
||||
#: utils.py:41
|
||||
msgid "Next page"
|
||||
msgstr "下一页"
|
||||
|
||||
#: utils.py:38
|
||||
#: utils.py:43
|
||||
msgid "Last page"
|
||||
msgstr "最后一页"
|
||||
|
||||
#: utils.py:97
|
||||
#, python-format
|
||||
msgid "%i day"
|
||||
msgstr "%i 天"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from math import ceil
|
||||
from math import ceil, floor
|
||||
from datetime import datetime, timezone
|
||||
from re import compile
|
||||
from . import _
|
||||
@@ -87,3 +87,19 @@ def parse_time(time: str) -> float:
|
||||
def convert_uid(uid: str) -> str:
|
||||
t = uid.upper()
|
||||
return f"{t[:8]}-{t[8:12]}-{t[12:16]}-{t[16:20]}-{t[20:]}"
|
||||
|
||||
|
||||
def format_duration(duration: float | None) -> str:
|
||||
if duration is None:
|
||||
return ''
|
||||
duration = round(duration)
|
||||
re = ''
|
||||
if duration >= 86400:
|
||||
re += _("%i day") % (floor(duration / 86400)) + " "
|
||||
duration %= 86400
|
||||
if duration >= 3600:
|
||||
re += str(floor(duration / 3600)).rjust(2, "0") + ":"
|
||||
duration %= 3600
|
||||
min = str(floor(duration / 60)).rjust(2, "0")
|
||||
sec = str(duration % 60).rjust(2, "0")
|
||||
return f"{re}{min}:{sec}"
|
||||
|
||||
Reference in New Issue
Block a user