save extra tags

+ port: streaming
This commit is contained in:
cwilvx
2024-06-24 20:48:13 +03:00
parent c42ec4dcde
commit 3593b205eb
6 changed files with 69 additions and 63 deletions
+4
View File
@@ -16,6 +16,10 @@
- Recreate album hash if featured artists are discover - Recreate album hash if featured artists are discover
- Implement checking if is clean install and skip migrations! - Implement checking if is clean install and skip migrations!
<!-- CHECKPOINT -->
<!-- ALBUM PAGE! -->
# DONE # DONE
- Support auth headers - Support auth headers
- Add recently played playlist - Add recently played playlist
+12 -54
View File
@@ -10,7 +10,8 @@ from pydantic import BaseModel, Field
from app.api.apischemas import TrackHashSchema from app.api.apischemas import TrackHashSchema
from app.lib.trackslib import get_silence_paddings from app.lib.trackslib import get_silence_paddings
from app.store.tracks import TrackStore # from app.store.tracks import TrackStore
from app.db import TrackTable
from app.utils.files import guess_mime_type from app.utils.files import guess_mime_type
bp_tag = Tag(name="File", description="Audio files") bp_tag = Tag(name="File", description="Audio files")
@@ -34,36 +35,12 @@ def send_track_file_legacy(path: TrackHashSchema, query: SendTrackFileQuery):
filepath = query.filepath filepath = query.filepath
msg = {"msg": "File Not Found"} msg = {"msg": "File Not Found"}
def get_mime(filename: str) -> str: track = TrackTable.get_track_by_trackhash(trackhash, filepath)
ext = filename.rsplit(".", maxsplit=1)[-1] track_exists = track is not None and os.path.exists(track.filepath)
return f"audio/{ext}"
# If filepath is provide, try to send that if track_exists:
if filepath is not None: audio_type = guess_mime_type(filepath)
try: return send_file(filepath, mimetype=audio_type, conditional=True)
track = TrackStore.get_tracks_by_filepaths([filepath])[0]
except IndexError:
track = None
track_exists = track is not None and os.path.exists(track.filepath)
if track_exists:
audio_type = get_mime(filepath)
return send_file(filepath, mimetype=audio_type, conditional=True)
# Else, find file by trackhash
tracks = TrackStore.get_tracks_by_trackhashes([trackhash])
for track in tracks:
if track is None:
return msg, 404
audio_type = get_mime(track.filepath)
try:
return send_file(track.filepath, mimetype=audio_type, conditional=True)
except (FileNotFoundError, OSError) as e:
return msg, 404
return msg, 404 return msg, 404
@@ -80,31 +57,12 @@ def send_track_file(path: TrackHashSchema, query: SendTrackFileQuery):
msg = {"msg": "File Not Found"} msg = {"msg": "File Not Found"}
# If filepath is provided, try to send that # If filepath is provided, try to send that
if filepath is not None: track = TrackTable.get_track_by_trackhash(trackhash, filepath)
try: track_exists = track is not None and os.path.exists(track.filepath)
track = TrackStore.get_tracks_by_filepaths([filepath])[0]
except IndexError:
track = None
track_exists = track is not None and os.path.exists(track.filepath) if track_exists:
audio_type = guess_mime_type(filepath)
if track_exists: return send_file_as_chunks(track.filepath, audio_type)
audio_type = guess_mime_type(filepath)
return send_file_as_chunks(track.filepath, audio_type)
# Else, find file by trackhash
tracks = TrackStore.get_tracks_by_trackhashes([trackhash])
for track in tracks:
if track is None:
return msg, 404
audio_type = guess_mime_type(track.filepath)
try:
return send_file_as_chunks(track.filepath, audio_type)
except (FileNotFoundError, OSError) as e:
return msg, 404
return msg, 404 return msg, 404
+35 -7
View File
@@ -9,6 +9,7 @@ from sqlalchemy import (
Row, Row,
String, String,
Tuple, Tuple,
and_,
create_engine, create_engine,
insert, insert,
select, select,
@@ -39,7 +40,8 @@ def todicts(tracks: list[Any]):
class DbManager: class DbManager:
def __init__(self): def __init__(self, commit: bool = False):
self.commit = commit
self.engine = create_engine(f"sqlite+pysqlite:///{fullpath}", echo=True) self.engine = create_engine(f"sqlite+pysqlite:///{fullpath}", echo=True)
self.conn = self.engine.connect() self.conn = self.engine.connect()
@@ -47,7 +49,8 @@ class DbManager:
return self.conn.execution_options(preserve_rowcount=True) return self.conn.execution_options(preserve_rowcount=True)
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
self.conn.commit() if self.commit:
self.conn.commit()
self.conn.close() self.conn.close()
@@ -57,7 +60,7 @@ class Base(MappedAsDataclass, DeclarativeBase):
""" """
Inserts multiple items into the database. Inserts multiple items into the database.
""" """
with DbManager() as conn: with DbManager(commit=True) as conn:
conn.execute(insert(cls).values(items)) conn.execute(insert(cls).values(items))
@classmethod @classmethod
@@ -177,6 +180,7 @@ class TrackTable(Base):
title: Mapped[str] = mapped_column(String()) title: Mapped[str] = mapped_column(String())
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)
extra: Mapped[Optional[dict[str, Any]]] = mapped_column(JSON())
@classmethod @classmethod
def get_tracks_by_filepaths(cls, filepaths: list[str]): def get_tracks_by_filepaths(cls, filepaths: list[str]):
@@ -209,23 +213,47 @@ class TrackTable(Base):
tracks = tracks_to_dataclasses(result.fetchall()) tracks = tracks_to_dataclasses(result.fetchall())
return remove_duplicates(tracks, is_album_tracks=True) return remove_duplicates(tracks, is_album_tracks=True)
@classmethod
def get_track_by_trackhash(cls, hash: str, filepath: str = ""):
with DbManager() as conn:
if filepath:
result = conn.execute(
select(TrackTable)
.where(
and_(
TrackTable.trackhash == hash,
TrackTable.filepath == filepath,
)
)
.order_by(TrackTable.bitrate.desc())
)
else:
result = conn.execute(
select(TrackTable).where(TrackTable.trackhash == hash)
)
track = result.fetchone()
if track:
return track_to_dataclass(track)
# SECTION: HELPER FUNCTIONS # SECTION: HELPER FUNCTIONS
def album_to_dataclass(album: Row[AlbumTable]): def album_to_dataclass(album: Any):
return AlbumModel(**album._asdict()) return AlbumModel(**album._asdict())
def albums_to_dataclasses(albums: list[Row[AlbumTable]]): def albums_to_dataclasses(albums: Any):
return [album_to_dataclass(album) for album in albums] return [album_to_dataclass(album) for album in albums]
def track_to_dataclass(track: Row[TrackTable]): def track_to_dataclass(track: Any):
return TrackModel(**track._asdict()) return TrackModel(**track._asdict())
def tracks_to_dataclasses(tracks: list[Row[TrackTable]]): def tracks_to_dataclasses(tracks: Any):
return [track_to_dataclass(track) for track in tracks] return [track_to_dataclass(track) for track in tracks]
+1 -1
View File
@@ -62,7 +62,7 @@ class IndexAlbums:
album["created_dates"].append(track.last_mod) album["created_dates"].append(track.last_mod)
if track.genre: if track.genre:
album["genres"].append(track.genre) album["genres"].extend(track.genre)
for album in albums.values(): for album in albums.values():
album["date"] = min(album["dates"]) album["date"] = min(album["dates"])
+16 -1
View File
@@ -2,7 +2,9 @@ from dataclasses import dataclass
import os import os
from io import BytesIO from io import BytesIO
from pathlib import Path from pathlib import Path
from pprint import pprint
import re import re
import sys
import pendulum import pendulum
from PIL import Image, UnidentifiedImageError from PIL import Image, UnidentifiedImageError
@@ -318,6 +320,20 @@ def get_tags(filepath: str):
*[a["name"] for a in tags.artists], tags.album, tags.title *[a["name"] for a in tags.artists], tags.album, tags.title
) )
more_extra = {
"audio_offset": tags.audio_offset,
"bitdepth": tags.bitdepth,
"composer": tags.composer,
"channels": tags.channels,
"comment": tags.comment,
"disc_total": tags.disc_total,
"filesize": tags.filesize,
"samplerate": tags.samplerate,
"track_total": tags.track_total,
}
tags.extra = {**tags.extra, **more_extra}
tags = tags.__dict__ tags = tags.__dict__
# delete all tag properties that start with _ (tinytag internals) # delete all tag properties that start with _ (tinytag internals)
@@ -332,7 +348,6 @@ def get_tags(filepath: str):
"comment", "comment",
"composer", "composer",
"disc_total", "disc_total",
"extra",
"samplerate", "samplerate",
"track_total", "track_total",
"year", "year",
+1
View File
@@ -42,6 +42,7 @@ class Track:
title: str title: str
track: int track: int
trackhash: str trackhash: str
extra: dict
_pos: int = 0 _pos: int = 0
_ati: str = "" _ati: str = ""