116 lines
3.4 KiB
Python
116 lines
3.4 KiB
Python
"""Module for search results."""
|
|
|
|
from __future__ import annotations
|
|
from dataclasses import dataclass
|
|
import os.path
|
|
from typing import Optional
|
|
|
|
|
|
@dataclass
|
|
class Result:
|
|
"""This models a search result.
|
|
|
|
:param ident: The identifier of the entry in the source
|
|
:type ident: str
|
|
:param source: The name of the source of the entry
|
|
:type source: str
|
|
:param title: The title of the song
|
|
:type title: str
|
|
:param artist: The artist of the song
|
|
:type artist: str
|
|
:param album: The name of the album or compilation, this particular
|
|
version is from.
|
|
:type album: str
|
|
"""
|
|
|
|
ident: str
|
|
source: str
|
|
title: str
|
|
artist: Optional[str]
|
|
album: Optional[str]
|
|
duration: Optional[str] = None
|
|
|
|
@classmethod
|
|
def from_filename(cls, filename: str, source: str) -> Result:
|
|
"""
|
|
Infer most attributes from the filename.
|
|
|
|
The filename must be in this form::
|
|
|
|
{artist} - {title} - {album}.ext
|
|
|
|
If parsing failes, the filename will be used as the title and the
|
|
artist and album will be set to "Unknown".
|
|
|
|
:param filename: The filename to parse
|
|
:type filename: str
|
|
:param source: The name of the source
|
|
:type source: str
|
|
:return: see above
|
|
:rtype: Optional[Result]
|
|
"""
|
|
basename = os.path.splitext(filename)[0]
|
|
try:
|
|
splitfile = os.path.basename(basename).split(" - ")
|
|
ident = filename
|
|
artist = splitfile[0].strip()
|
|
title = splitfile[1].strip()
|
|
album = splitfile[2].strip()
|
|
return cls(ident=ident, source=source, title=title, artist=artist, album=album)
|
|
except IndexError:
|
|
return cls(ident=filename, source=source, title=basename, artist=None, album=None)
|
|
|
|
@classmethod
|
|
def from_dict(cls, values: dict[str, str]) -> Result:
|
|
"""
|
|
Create a Result object from a dictionary.
|
|
|
|
The dictionary must have the following keys:
|
|
- ident (str)
|
|
- source (str)
|
|
- title (str)
|
|
- artist (str)
|
|
- album (str)
|
|
- duration (int, optional)
|
|
|
|
:param values: The dictionary with the values
|
|
:type values: dict[str, str]
|
|
:return: The Result object
|
|
:rtype: Result
|
|
"""
|
|
return cls(
|
|
ident=values["ident"],
|
|
source=values["source"],
|
|
title=values["title"],
|
|
artist=values["artist"],
|
|
album=values["album"],
|
|
duration=values.get("duration", None),
|
|
)
|
|
|
|
def to_dict(self) -> dict[str, str]:
|
|
"""
|
|
Convert the Result object to a dictionary.
|
|
|
|
The dictionary will have the following keys:
|
|
- ident (str)
|
|
- source (str)
|
|
- title (str)
|
|
- album (str, if available)
|
|
- artist (str, if available)
|
|
- duration (str, if available)
|
|
|
|
:return: The dictionary with the values
|
|
:rtype: dict[str, str]
|
|
"""
|
|
output: dict[str, str] = {
|
|
"ident": self.ident,
|
|
"source": self.source,
|
|
"title": self.title,
|
|
}
|
|
if self.album is not None:
|
|
output["album"] = self.album
|
|
if self.artist is not None:
|
|
output["artist"] = self.artist
|
|
if self.duration is not None:
|
|
output["duration"] = self.duration
|
|
return output
|