mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
store playcount and duration on the track table
+ allow sorting all items with those two + add methods to update scrobble info
This commit is contained in:
@@ -44,4 +44,6 @@
|
|||||||
- Move plugins to a config file
|
- Move plugins to a config file
|
||||||
- What about our migrations?
|
- What about our migrations?
|
||||||
- Add userid to queries
|
- Add userid to queries
|
||||||
- Remove duplicates on artist page (test with Hanson)
|
- Remove duplicates on artist page (test with Hanson)
|
||||||
|
- Test foreign keys on delete
|
||||||
|
- Map scrobble info on app start
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@ from app.api import (
|
|||||||
settings,
|
settings,
|
||||||
lyrics,
|
lyrics,
|
||||||
plugins,
|
plugins,
|
||||||
logger,
|
scrobble,
|
||||||
home,
|
home,
|
||||||
getall,
|
getall,
|
||||||
auth,
|
auth,
|
||||||
@@ -116,7 +116,7 @@ def create_api():
|
|||||||
app.register_api(lyrics_plugin.api)
|
app.register_api(lyrics_plugin.api)
|
||||||
|
|
||||||
# Logger
|
# Logger
|
||||||
app.register_api(logger.api)
|
app.register_api(scrobble.api)
|
||||||
|
|
||||||
# Home
|
# Home
|
||||||
app.register_api(home.api)
|
app.register_api(home.api)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from app.utils.dates import (
|
|||||||
create_new_date,
|
create_new_date,
|
||||||
date_string_to_time_passed,
|
date_string_to_time_passed,
|
||||||
seconds_to_time_string,
|
seconds_to_time_string,
|
||||||
|
timestamp_to_time_passed,
|
||||||
)
|
)
|
||||||
|
|
||||||
bp_tag = Tag(name="Get all", description="List all items")
|
bp_tag = Tag(name="Get all", description="List all items")
|
||||||
@@ -57,6 +58,13 @@ def get_all_items(path: GetAllItemsPath, query: GetAllItemsQuery):
|
|||||||
Get all items
|
Get all items
|
||||||
|
|
||||||
Used to show all albums or artists in the library
|
Used to show all albums or artists in the library
|
||||||
|
|
||||||
|
Sort keys:
|
||||||
|
-
|
||||||
|
Both albums and artists: `duration`, `created_date`, `playcount`, `playduration`, `lastplayed`, `trackcount`
|
||||||
|
|
||||||
|
Albums only: `title`, `albumartists`, `date`
|
||||||
|
Artists only: `name`, `albumcount`
|
||||||
"""
|
"""
|
||||||
is_albums = path.itemtype == "albums"
|
is_albums = path.itemtype == "albums"
|
||||||
is_artists = path.itemtype == "artists"
|
is_artists = path.itemtype == "artists"
|
||||||
@@ -76,6 +84,9 @@ def get_all_items(path: GetAllItemsPath, query: GetAllItemsQuery):
|
|||||||
sort_is_count = sort == "trackcount"
|
sort_is_count = sort == "trackcount"
|
||||||
sort_is_duration = sort == "duration"
|
sort_is_duration = sort == "duration"
|
||||||
sort_is_create_date = sort == "created_date"
|
sort_is_create_date = sort == "created_date"
|
||||||
|
sort_is_playcount = sort == "playcount"
|
||||||
|
sort_is_playduration = sort == "playduration"
|
||||||
|
sort_is_lastplayed = sort == "lastplayed"
|
||||||
|
|
||||||
sort_is_date = is_albums and sort == "date"
|
sort_is_date = is_albums and sort == "date"
|
||||||
sort_is_artist = is_albums and sort == "albumartists"
|
sort_is_artist = is_albums and sort == "albumartists"
|
||||||
@@ -94,7 +105,6 @@ def get_all_items(path: GetAllItemsPath, query: GetAllItemsQuery):
|
|||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
item_dict = serialize_album(item) if is_albums else serialize_artist(item)
|
item_dict = serialize_album(item) if is_albums else serialize_artist(item)
|
||||||
print(item_dict)
|
|
||||||
|
|
||||||
if sort_is_date:
|
if sort_is_date:
|
||||||
item_dict["help_text"] = item.date
|
item_dict["help_text"] = item.date
|
||||||
@@ -122,6 +132,20 @@ def get_all_items(path: GetAllItemsPath, query: GetAllItemsQuery):
|
|||||||
f"{format_number(item.albumcount)} album{'' if item.albumcount == 1 else 's'}"
|
f"{format_number(item.albumcount)} album{'' if item.albumcount == 1 else 's'}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if sort_is_playcount:
|
||||||
|
item_dict["help_text"] = (
|
||||||
|
f"{format_number(item.playcount)} play{'' if item.playcount == 1 else 's'}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if sort_is_lastplayed:
|
||||||
|
if item.playduration == 0:
|
||||||
|
item_dict["help_text"] = "Never played"
|
||||||
|
else:
|
||||||
|
item_dict["help_text"] = timestamp_to_time_passed(item.lastplayed)
|
||||||
|
|
||||||
|
if sort_is_playduration:
|
||||||
|
item_dict["help_text"] = seconds_to_time_string(item.playduration)
|
||||||
|
|
||||||
album_list.append(item_dict)
|
album_list.append(item_dict)
|
||||||
|
|
||||||
return {"items": album_list, "total": total}
|
return {"items": album_list, "total": total}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ from flask_openapi3 import APIBlueprint
|
|||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from app.api.apischemas import TrackHashSchema
|
from app.api.apischemas import TrackHashSchema
|
||||||
|
|
||||||
from app.db.sqlite.logger.tracks import SQLiteTrackLogger as db
|
from app.db.libdata import AlbumTable, ArtistTable, TrackTable
|
||||||
|
from app.db.userdata import ScrobbleTable
|
||||||
from app.settings import Defaults
|
from app.settings import Defaults
|
||||||
|
|
||||||
bp_tag = Tag(name="Logger", description="Log item plays")
|
bp_tag = Tag(name="Logger", description="Log item plays")
|
||||||
@@ -26,19 +27,20 @@ def log_track(body: LogTrackBody):
|
|||||||
"""
|
"""
|
||||||
Log a track play to the database.
|
Log a track play to the database.
|
||||||
"""
|
"""
|
||||||
trackhash = body.trackhash
|
|
||||||
timestamp = body.timestamp
|
timestamp = body.timestamp
|
||||||
duration = body.duration
|
duration = body.duration
|
||||||
source = body.source
|
|
||||||
|
|
||||||
if not timestamp or duration < 5:
|
if not timestamp or duration < 5:
|
||||||
return {"msg": "Invalid entry."}, 400
|
return {"msg": "Invalid entry."}, 400
|
||||||
|
|
||||||
last_row = db.insert_track(
|
track = TrackTable.get_track_by_trackhash(body.trackhash)
|
||||||
trackhash=trackhash,
|
|
||||||
timestamp=timestamp,
|
|
||||||
duration=duration,
|
|
||||||
source=source,
|
|
||||||
)
|
|
||||||
|
|
||||||
return {"total entries": last_row}
|
if track is None:
|
||||||
|
return {"msg": "Track not found."}, 404
|
||||||
|
|
||||||
|
ScrobbleTable.add(dict(body))
|
||||||
|
TrackTable.increment_playcount(body.trackhash, duration, timestamp)
|
||||||
|
AlbumTable.increment_playcount(track.albumhash, duration, timestamp)
|
||||||
|
ArtistTable.increment_playcount(track.artisthashes, duration, timestamp)
|
||||||
|
|
||||||
|
return {"msg": "recorded"}, 201
|
||||||
+1
-1
@@ -48,7 +48,7 @@ class DbManager:
|
|||||||
if self.commit:
|
if self.commit:
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
self.conn.close()
|
# self.conn.close()
|
||||||
|
|
||||||
|
|
||||||
class Base(MappedAsDataclass, DeclarativeBase):
|
class Base(MappedAsDataclass, DeclarativeBase):
|
||||||
|
|||||||
+60
-4
@@ -73,6 +73,21 @@ class Base(MasterBase, DeclarativeBase):
|
|||||||
|
|
||||||
conn.execute(stmt)
|
conn.execute(stmt)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def increment_scrobblecount(
|
||||||
|
cls, table: Any, field: Any, hash: str, duration: int, timestamp: int
|
||||||
|
):
|
||||||
|
cls.execute(
|
||||||
|
update(table)
|
||||||
|
.where(field == hash)
|
||||||
|
.values(
|
||||||
|
playcount=table.playcount + 1,
|
||||||
|
playduration=table.playduration + duration,
|
||||||
|
lastplayed=timestamp,
|
||||||
|
),
|
||||||
|
commit=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TrackTable(Base):
|
class TrackTable(Base):
|
||||||
__tablename__ = "track"
|
__tablename__ = "track"
|
||||||
@@ -99,8 +114,12 @@ class TrackTable(Base):
|
|||||||
track: Mapped[int] = mapped_column(Integer())
|
track: Mapped[int] = mapped_column(Integer())
|
||||||
trackhash: Mapped[str] = mapped_column(String(), index=True)
|
trackhash: Mapped[str] = mapped_column(String(), index=True)
|
||||||
is_favorite: Mapped[Optional[bool]] = mapped_column(Boolean())
|
is_favorite: Mapped[Optional[bool]] = mapped_column(Boolean())
|
||||||
playcount: Mapped[int] = mapped_column(Integer())
|
lastplayed: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
extra: Mapped[Optional[dict[str, Any]]] = mapped_column(JSON())
|
playcount: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
|
playduration: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
|
extra: Mapped[Optional[dict[str, Any]]] = mapped_column(
|
||||||
|
JSON(), default_factory=dict
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all(cls):
|
def get_all(cls):
|
||||||
@@ -180,6 +199,12 @@ class TrackTable(Base):
|
|||||||
with DbManager(commit=True) as conn:
|
with DbManager(commit=True) as conn:
|
||||||
conn.execute(delete(TrackTable).where(TrackTable.filepath.in_(filepaths)))
|
conn.execute(delete(TrackTable).where(TrackTable.filepath.in_(filepaths)))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def increment_playcount(cls, trackhash: str, duration: int, timestamp: int):
|
||||||
|
cls.increment_scrobblecount(
|
||||||
|
TrackTable, TrackTable.trackhash, trackhash, duration, timestamp
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AlbumTable(Base):
|
class AlbumTable(Base):
|
||||||
__tablename__ = "album"
|
__tablename__ = "album"
|
||||||
@@ -199,7 +224,12 @@ class AlbumTable(Base):
|
|||||||
title: Mapped[str] = mapped_column(String())
|
title: Mapped[str] = mapped_column(String())
|
||||||
trackcount: Mapped[int] = mapped_column(Integer())
|
trackcount: Mapped[int] = mapped_column(Integer())
|
||||||
is_favorite: Mapped[Optional[bool]] = mapped_column(Boolean())
|
is_favorite: Mapped[Optional[bool]] = mapped_column(Boolean())
|
||||||
extra: Mapped[Optional[dict[str, Any]]] = mapped_column(JSON())
|
lastplayed: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
|
playcount: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
|
playduration: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
|
extra: Mapped[Optional[dict[str, Any]]] = mapped_column(
|
||||||
|
JSON(), default_factory=dict
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all(cls):
|
def get_all(cls):
|
||||||
@@ -257,6 +287,12 @@ class AlbumTable(Base):
|
|||||||
)
|
)
|
||||||
return albums_to_dataclasses(result.all())
|
return albums_to_dataclasses(result.all())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def increment_playcount(cls, albumhash: str, duration: int, timestamp: int):
|
||||||
|
return cls.increment_scrobblecount(
|
||||||
|
AlbumTable, AlbumTable.albumhash, albumhash, duration, timestamp
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ArtistTable(Base):
|
class ArtistTable(Base):
|
||||||
__tablename__ = "artist"
|
__tablename__ = "artist"
|
||||||
@@ -272,7 +308,12 @@ class ArtistTable(Base):
|
|||||||
name: Mapped[str] = mapped_column(String(), index=True)
|
name: Mapped[str] = mapped_column(String(), index=True)
|
||||||
trackcount: Mapped[int] = mapped_column(Integer())
|
trackcount: Mapped[int] = mapped_column(Integer())
|
||||||
is_favorite: Mapped[Optional[bool]] = mapped_column(Boolean())
|
is_favorite: Mapped[Optional[bool]] = mapped_column(Boolean())
|
||||||
extra: Mapped[Optional[dict[str, Any]]] = mapped_column(JSON())
|
lastplayed: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
|
playcount: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
|
playduration: Mapped[int] = mapped_column(Integer(), default=0)
|
||||||
|
extra: Mapped[Optional[dict[str, Any]]] = mapped_column(
|
||||||
|
JSON(), default_factory=dict
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all(cls):
|
def get_all(cls):
|
||||||
@@ -310,3 +351,18 @@ class ArtistTable(Base):
|
|||||||
.limit(limit)
|
.limit(limit)
|
||||||
)
|
)
|
||||||
return artists_to_dataclasses(result.fetchall())
|
return artists_to_dataclasses(result.fetchall())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def increment_playcount(
|
||||||
|
cls, artisthashes: list[str], duration: int, timestamp: int
|
||||||
|
):
|
||||||
|
cls.execute(
|
||||||
|
update(cls)
|
||||||
|
.where(ArtistTable.artisthash.in_(artisthashes))
|
||||||
|
.values(
|
||||||
|
playcount=ArtistTable.playcount + 1,
|
||||||
|
playduration=ArtistTable.playduration + duration,
|
||||||
|
lastplayed=timestamp,
|
||||||
|
),
|
||||||
|
commit=True,
|
||||||
|
)
|
||||||
|
|||||||
+25
-4
@@ -31,7 +31,7 @@ from app.db.utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from app.db import Base, DbManager
|
from app.db import Base, DbManager
|
||||||
from app.utils.auth import hash_password
|
from app.utils.auth import get_current_userid, hash_password
|
||||||
|
|
||||||
|
|
||||||
class UserTable(Base):
|
class UserTable(Base):
|
||||||
@@ -160,7 +160,7 @@ class FavoritesTable(Base):
|
|||||||
type: Mapped[str] = mapped_column(String(), index=True)
|
type: Mapped[str] = mapped_column(String(), index=True)
|
||||||
timestamp: Mapped[int] = mapped_column(Integer(), index=True)
|
timestamp: Mapped[int] = mapped_column(Integer(), index=True)
|
||||||
userid: Mapped[int] = mapped_column(
|
userid: Mapped[int] = mapped_column(
|
||||||
Integer(), ForeignKey("user.id"), default=1, index=True
|
Integer(), ForeignKey("user.id", ondelete="cascade"), default=1, index=True
|
||||||
)
|
)
|
||||||
extra: Mapped[dict[str, Any]] = mapped_column(
|
extra: Mapped[dict[str, Any]] = mapped_column(
|
||||||
JSON(), nullable=True, default_factory=dict
|
JSON(), nullable=True, default_factory=dict
|
||||||
@@ -175,7 +175,7 @@ class FavoritesTable(Base):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def insert_item(cls, item: dict[str, Any]):
|
def insert_item(cls, item: dict[str, Any]):
|
||||||
item["timestamp"] = int(datetime.datetime.now().timestamp())
|
item["timestamp"] = int(datetime.datetime.now().timestamp())
|
||||||
item["userid"] = current_user["id"]
|
item["userid"] = get_current_userid()
|
||||||
|
|
||||||
with DbManager(commit=True) as conn:
|
with DbManager(commit=True) as conn:
|
||||||
conn.execute(insert(cls).values(item))
|
conn.execute(insert(cls).values(item))
|
||||||
@@ -199,7 +199,7 @@ class FavoritesTable(Base):
|
|||||||
result = cls.execute(
|
result = cls.execute(
|
||||||
select(table)
|
select(table)
|
||||||
.select_from(join(table, cls, field == cls.hash))
|
.select_from(join(table, cls, field == cls.hash))
|
||||||
.where(and_(cls.type == type, cls.userid == current_user["id"]))
|
.where(and_(cls.type == type, cls.userid == get_current_userid()))
|
||||||
.offset(start)
|
.offset(start)
|
||||||
# INFO: If start is 0, fetch all so we can get the total count
|
# INFO: If start is 0, fetch all so we can get the total count
|
||||||
.limit(limit if start != 0 else None)
|
.limit(limit if start != 0 else None)
|
||||||
@@ -238,3 +238,24 @@ class FavoritesTable(Base):
|
|||||||
ArtistTable, ArtistTable.artisthash, "artist", start, limit
|
ArtistTable, ArtistTable.artisthash, "artist", start, limit
|
||||||
)
|
)
|
||||||
return artists_to_dataclasses(result), total
|
return artists_to_dataclasses(result), total
|
||||||
|
|
||||||
|
|
||||||
|
class ScrobbleTable(Base):
|
||||||
|
__tablename__ = "scrobble"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
trackhash: Mapped[str] = mapped_column(String(), index=True)
|
||||||
|
duration: Mapped[int] = mapped_column(Integer())
|
||||||
|
timestamp: Mapped[int] = mapped_column(Integer())
|
||||||
|
source: Mapped[str] = mapped_column(String())
|
||||||
|
userid: Mapped[int] = mapped_column(
|
||||||
|
Integer(), ForeignKey("user.id", ondelete="cascade"), index=True
|
||||||
|
)
|
||||||
|
extra: Mapped[dict[str, Any]] = mapped_column(
|
||||||
|
JSON(), nullable=True, default_factory=dict
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add(cls, item: dict[str, Any]):
|
||||||
|
item["userid"] = get_current_userid()
|
||||||
|
return cls.insert_one(item)
|
||||||
|
|||||||
+20
-21
@@ -156,32 +156,32 @@ class IndexAlbums:
|
|||||||
"albumhash": track.albumhash,
|
"albumhash": track.albumhash,
|
||||||
"base_title": None,
|
"base_title": None,
|
||||||
"color": None,
|
"color": None,
|
||||||
"created_date": None,
|
"created_date": track.last_mod,
|
||||||
"date": None,
|
"date": track.date,
|
||||||
"duration": track.duration,
|
"duration": track.duration,
|
||||||
"genres": [*track.genres] if track.genres else [],
|
"genres": [*track.genres] if track.genres else [],
|
||||||
"og_title": track.og_album,
|
"og_title": track.og_album,
|
||||||
|
"lastplayed": track.lastplayed,
|
||||||
|
"playcount": track.playcount,
|
||||||
|
"playduration": track.playduration,
|
||||||
"title": track.album,
|
"title": track.album,
|
||||||
"trackcount": 1,
|
"trackcount": 1,
|
||||||
"dates": [track.date],
|
|
||||||
"created_dates": [track.last_mod],
|
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
album = albums[track.albumhash]
|
album = albums[track.albumhash]
|
||||||
album["trackcount"] += 1
|
album["trackcount"] += 1
|
||||||
|
album["playcount"] += track.playcount
|
||||||
|
album["playduration"] += track.playduration
|
||||||
|
album["lastplayed"] = max(album["lastplayed"], track.lastplayed)
|
||||||
album["duration"] += track.duration
|
album["duration"] += track.duration
|
||||||
album["dates"].append(track.date)
|
album["date"] = min(album["date"], track.date)
|
||||||
album["created_dates"].append(track.last_mod)
|
album["created_date"] = min(album["created_date"], track.last_mod)
|
||||||
|
|
||||||
if track.genres:
|
if track.genres:
|
||||||
album["genres"].extend(track.genres)
|
album["genres"].extend(track.genres)
|
||||||
|
|
||||||
for album in albums.values():
|
for album in albums.values():
|
||||||
album["date"] = min(album["dates"])
|
|
||||||
album["created_date"] = min(album["created_dates"])
|
|
||||||
|
|
||||||
genres = []
|
genres = []
|
||||||
|
|
||||||
for genre in album["genres"]:
|
for genre in album["genres"]:
|
||||||
if genre not in genres:
|
if genre not in genres:
|
||||||
genres.append(genre)
|
genres.append(genre)
|
||||||
@@ -190,8 +190,6 @@ class IndexAlbums:
|
|||||||
album["base_title"], _ = get_base_album_title(album["og_title"])
|
album["base_title"], _ = get_base_album_title(album["og_title"])
|
||||||
|
|
||||||
del genres
|
del genres
|
||||||
del album["dates"]
|
|
||||||
del album["created_dates"]
|
|
||||||
|
|
||||||
AlbumTable.remove_all()
|
AlbumTable.remove_all()
|
||||||
AlbumTable.insert_many(list(albums.values()))
|
AlbumTable.insert_many(list(albums.values()))
|
||||||
@@ -219,23 +217,28 @@ class IndexArtists:
|
|||||||
"albumcount": None,
|
"albumcount": None,
|
||||||
"albums": {track.albumhash},
|
"albums": {track.albumhash},
|
||||||
"artisthash": thisartist["artisthash"],
|
"artisthash": thisartist["artisthash"],
|
||||||
"created_dates": [track.last_mod],
|
"created_date": track.last_mod,
|
||||||
"dates": [track.date],
|
"date": track.date,
|
||||||
"date": None,
|
|
||||||
"duration": track.duration,
|
"duration": track.duration,
|
||||||
"genres": track.genres if track.genres else [],
|
"genres": track.genres if track.genres else [],
|
||||||
"name": None,
|
"name": None,
|
||||||
"names": {thisartist["name"]},
|
"names": {thisartist["name"]},
|
||||||
|
"lastplayed": track.lastplayed,
|
||||||
|
"playcount": track.playcount,
|
||||||
|
"playduration": track.playduration,
|
||||||
"trackcount": None,
|
"trackcount": None,
|
||||||
"tracks": {track.trackhash},
|
"tracks": {track.trackhash},
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
artist = artists[thisartist["artisthash"]]
|
artist = artists[thisartist["artisthash"]]
|
||||||
artist["duration"] += track.duration
|
artist["duration"] += track.duration
|
||||||
|
artist["playcount"] += track.playcount
|
||||||
|
artist["playduration"] += track.playduration
|
||||||
artist["albums"].add(track.albumhash)
|
artist["albums"].add(track.albumhash)
|
||||||
artist["tracks"].add(track.trackhash)
|
artist["tracks"].add(track.trackhash)
|
||||||
artist["dates"].append(track.date)
|
artist["date"] = min(artist["date"], track.date)
|
||||||
artist["created_dates"].append(track.last_mod)
|
artist["lastplayed"] = max(artist["lastplayed"], track.lastplayed)
|
||||||
|
artist["created_date"] = min(artist["created_date"], track.last_mod)
|
||||||
artist["names"].add(thisartist["name"])
|
artist["names"].add(thisartist["name"])
|
||||||
|
|
||||||
if track.genres:
|
if track.genres:
|
||||||
@@ -244,8 +247,6 @@ class IndexArtists:
|
|||||||
for artist in artists.values():
|
for artist in artists.values():
|
||||||
artist["albumcount"] = len(artist["albums"])
|
artist["albumcount"] = len(artist["albums"])
|
||||||
artist["trackcount"] = len(artist["tracks"])
|
artist["trackcount"] = len(artist["tracks"])
|
||||||
artist["date"] = min(artist["dates"])
|
|
||||||
artist["created_date"] = min(artist["created_dates"])
|
|
||||||
|
|
||||||
genres = []
|
genres = []
|
||||||
|
|
||||||
@@ -260,8 +261,6 @@ class IndexArtists:
|
|||||||
del artist["names"]
|
del artist["names"]
|
||||||
del artist["tracks"]
|
del artist["tracks"]
|
||||||
del artist["albums"]
|
del artist["albums"]
|
||||||
del artist["dates"]
|
|
||||||
del artist["created_dates"]
|
|
||||||
|
|
||||||
# INFO: Delete local variables
|
# INFO: Delete local variables
|
||||||
del genres
|
del genres
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ class Album:
|
|||||||
title: str
|
title: str
|
||||||
trackcount: int
|
trackcount: int
|
||||||
is_favorite: bool
|
is_favorite: bool
|
||||||
|
lastplayed: int
|
||||||
|
playcount: int
|
||||||
|
playduration: int
|
||||||
extra: dict
|
extra: dict
|
||||||
|
|
||||||
type: str = "album"
|
type: str = "album"
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ class Artist:
|
|||||||
name: str
|
name: str
|
||||||
trackcount: int
|
trackcount: int
|
||||||
is_favorite: bool
|
is_favorite: bool
|
||||||
|
lastplayed: int
|
||||||
|
playcount: int
|
||||||
|
playduration: int
|
||||||
extra: dict
|
extra: dict
|
||||||
|
|
||||||
image: str = ""
|
image: str = ""
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ class Track:
|
|||||||
track: int
|
track: int
|
||||||
trackhash: str
|
trackhash: str
|
||||||
extra: dict
|
extra: dict
|
||||||
|
lastplayed: int
|
||||||
|
playcount: int
|
||||||
|
playduration: int
|
||||||
|
|
||||||
is_favorite: bool = False
|
is_favorite: bool = False
|
||||||
_pos: int = 0
|
_pos: int = 0
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ def serialize_for_card(album: Album):
|
|||||||
"og_title",
|
"og_title",
|
||||||
"base_title",
|
"base_title",
|
||||||
"genres",
|
"genres",
|
||||||
|
"playcount"
|
||||||
}
|
}
|
||||||
|
|
||||||
return album_serializer(album, props_to_remove)
|
return album_serializer(album, props_to_remove)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ def serialize_for_card(artist: Artist):
|
|||||||
"trackcount",
|
"trackcount",
|
||||||
"duration",
|
"duration",
|
||||||
"albumcount",
|
"albumcount",
|
||||||
|
"playcount",
|
||||||
}
|
}
|
||||||
|
|
||||||
for key in props_to_remove:
|
for key in props_to_remove:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ def serialize_track(track: Track, to_remove: set = {}, remove_disc=True) -> dict
|
|||||||
"artist_hashes",
|
"artist_hashes",
|
||||||
"created_date",
|
"created_date",
|
||||||
"fav_userids",
|
"fav_userids",
|
||||||
|
"playcount",
|
||||||
}.union(to_remove)
|
}.union(to_remove)
|
||||||
|
|
||||||
if not remove_disc:
|
if not remove_disc:
|
||||||
|
|||||||
+1
-1
@@ -63,4 +63,4 @@ def seconds_to_time_string(seconds):
|
|||||||
if minutes > 0:
|
if minutes > 0:
|
||||||
return f"{minutes} minute{'s' if minutes > 1 else ''}"
|
return f"{minutes} minute{'s' if minutes > 1 else ''}"
|
||||||
|
|
||||||
return f"{remaining_seconds} second{'s' if remaining_seconds > 1 else ''}"
|
return f"{remaining_seconds} second{'' if remaining_seconds == 1 else 's'}"
|
||||||
|
|||||||
Reference in New Issue
Block a user