swingmusic/app/models.py
2023-02-17 20:44:21 +03:00

259 lines
6.5 KiB
Python

"""
Contains all the models for objects generation and typing.
"""
import dataclasses
import json
from dataclasses import dataclass
from app import utils, settings
@dataclass(slots=True)
class Artist:
"""
Artist class
"""
name: str
artisthash: str = ""
image: str = ""
trackcount: int = 0
albumcount: int = 0
duration: int = 0
colors: list[str] = dataclasses.field(default_factory=list)
is_favorite: bool = False
def __post_init__(self):
self.artisthash = utils.create_hash(self.name, decode=True)
self.image = self.artisthash + ".webp"
self.colors = json.loads(str(self.colors))
@dataclass(slots=True)
class Track:
"""
Track class
"""
album: str
albumartist: str | list[Artist]
albumhash: str
artist: str | list[Artist]
bitrate: int
copyright: str
date: str
disc: int
duration: int
filepath: str
folder: str
genre: str | list[str]
title: str
track: int
trackhash: str
filetype: str = ""
image: str = ""
artist_hashes: list[str] = dataclasses.field(default_factory=list)
is_favorite: bool = False
og_title: str = ""
def __post_init__(self):
self.og_title = self.title
if self.artist is not None:
artists = utils.split_artists(self.artist)
new_title = self.title
if settings.EXTRACT_FEAT:
featured, new_title = utils.parse_feat_from_title(self.title)
original_lower = "-".join([a.lower() for a in artists])
artists.extend([a for a in featured if a.lower() not in original_lower])
if settings.REMOVE_PROD:
new_title = utils.remove_prod(new_title)
# if track is a single
if self.og_title == self.album:
self.album = new_title
self.title = new_title
self.artist_hashes = [utils.create_hash(a, decode=True) for a in artists]
self.artist = [Artist(a) for a in artists]
albumartists = utils.split_artists(self.albumartist)
self.albumartist = [Artist(a) for a in albumartists]
self.filetype = self.filepath.rsplit(".", maxsplit=1)[-1]
self.image = self.albumhash + ".webp"
if self.genre is not None:
self.genre = str(self.genre).replace("/", ",").replace(";", ",")
self.genre = str(self.genre).lower().split(",")
self.genre = [g.strip() for g in self.genre]
@dataclass
class Album:
"""
Creates an album object
"""
albumhash: str
title: str
albumartists: list[Artist]
albumartisthash: str = ""
image: str = ""
count: int = 0
duration: int = 0
colors: list[str] = dataclasses.field(default_factory=list)
date: str = ""
is_soundtrack: bool = False
is_compilation: bool = False
is_single: bool = False
is_EP: bool = False
is_favorite: bool = False
is_live: bool = False
genres: list[str] = dataclasses.field(default_factory=list)
def __post_init__(self):
self.image = self.albumhash + ".webp"
self.albumartisthash = "-".join(a.artisthash for a in self.albumartists)
def set_colors(self, colors: list[str]):
self.colors = colors
def check_type(self):
"""
Runs all the checks to determine the type of album.
"""
self.is_soundtrack = self.check_is_soundtrack()
if self.is_soundtrack:
return
self.is_live = self.check_is_live_album()
if self.is_live:
return
self.is_compilation = self.check_is_compilation()
if self.is_compilation:
return
self.is_EP = self.check_is_ep()
def check_is_soundtrack(self) -> bool:
"""
Checks if the album is a soundtrack.
"""
keywords = ["motion picture", "soundtrack"]
for keyword in keywords:
if keyword in self.title.lower():
return True
return False
def check_is_compilation(self) -> bool:
"""
Checks if the album is a compilation.
"""
artists = [a.name for a in self.albumartists] # type: ignore
artists = "".join(artists).lower()
if "various artists" in artists:
return True
substrings = ["the essential", "best of", "greatest hits", "#1 hits", "number ones", "super hits",
"ultimate collection"]
for substring in substrings:
if substring in self.title.lower():
return True
return False
def check_is_live_album(self):
"""
Checks if the album is a live album.
"""
keywords = ["live from", "live at", "live in"]
for keyword in keywords:
if keyword in self.title.lower():
return True
return False
def check_is_ep(self) -> bool:
"""
Checks if the album is an EP.
"""
return self.title.strip().endswith(" EP")
def check_is_single(self, tracks: list[Track]):
"""
Checks if the album is a single.
"""
if (
len(tracks) == 1
and tracks[0].title == self.title
# and tracks[0].track == 1
# and tracks[0].disc == 1
# Todo: Are the above commented checks necessary?
):
self.is_single = True
def get_date_from_tracks(self, tracks: list[Track]):
for track in tracks:
if track.date != "Unknown":
self.date = track.date
break
@dataclass
class Playlist:
"""Creates playlist objects"""
id: int
artisthashes: str | list[str]
banner_pos: int
has_gif: str | bool
image: str
last_updated: str
name: str
trackhashes: str | list[str]
thumb: str = ""
count: int = 0
duration: int = 0
def __post_init__(self):
self.trackhashes = json.loads(str(self.trackhashes))
self.artisthashes = json.loads(str(self.artisthashes))
self.count = len(self.trackhashes)
self.has_gif = bool(int(self.has_gif))
if self.image is not None:
self.thumb = "thumb_" + self.image
else:
self.image = "None"
self.thumb = "None"
@dataclass
class Folder:
name: str
path: str
has_tracks: bool
is_sym: bool = False
path_hash: str = ""
class FavType:
"""Favorite types enum"""
track = "track"
album = "album"
artist = "artist"