def create_sort_name(input_str: str) -> str:
"""Create sort name/title from string."""
input_str = input_str.lower().strip()
- for item in ["the ", "de ", "les ", "dj "]:
+ for item in ["the ", "de ", "les ", "dj ", ".", "-", "'", "`"]:
if input_str.startswith(item):
input_str = input_str.replace(item, "")
return input_str.strip()
def __hash__(self) -> int:
"""Return custom hash."""
- return hash((self.provider_instance, self.item_id.lower()))
+ return hash((self.provider_instance, self.item_id))
def __eq__(self, other: ProviderMapping) -> bool:
"""Check equality of two items."""
if not other:
return False
- return (
- self.provider_instance == other.provider_instance
- and self.item_id.lower() == other.item_id.lower()
- )
+ return self.provider_instance == other.provider_instance and self.item_id == other.item_id
@dataclass(frozen=True)
if self.media_type in (MediaType.ALBUM, MediaType.TRACK):
query_parts.append(
f"({self.db_table}.name LIKE :search "
+ f" OR {self.db_table}.sort_name LIKE :search"
f" OR {self.db_table}.artists LIKE :search)"
)
else:
import cchardet
import xmltodict
-from music_assistant.common.helpers.util import parse_title_and_version
+from music_assistant.common.helpers.util import create_sort_name, parse_title_and_version
from music_assistant.common.models.config_entries import (
ConfigEntry,
ConfigEntryType,
"""Lookup metadata in Artist folder."""
assert name or artist_path
if not artist_path:
- artist_path = name
+ # check if we have an existing item
+ sort_name = create_sort_name(name)
+ async for item in self.mass.music.artists.iter_library_items(search=sort_name):
+ if not compare_strings(sort_name, item.sort_name):
+ continue
+ for prov_mapping in item.provider_mappings:
+ if prov_mapping.provider_instance == self.instance_id:
+ artist_path = prov_mapping.url
+ break
+ if artist_path:
+ break
+ else:
+ # check if we have an artist folder for this artist at root level
+ if await self.exists(name):
+ artist_path = name
+ elif await self.exists(name.title()):
+ artist_path = name.title()
+ else:
+ # use fake artist path as item id which is just the name
+ artist_path = name
if not name:
name = artist_path.split(os.sep)[-1]
assert albumname or album_barcode
for searchartist in (
artistname,
- re.sub(LUCENE_SPECIAL, r"\\\1", create_sort_name(artistname)),
+ re.sub(LUCENE_SPECIAL, r"\\\1", artistname),
+ create_sort_name(artistname),
):
if album_barcode:
# search by album barcode (EAN or UPC)
from tidalapi import Track as TidalTrack
from tidalapi.media import Lyrics as TidalLyrics
-from music_assistant.common.helpers.uri import create_uri
-from music_assistant.common.helpers.util import create_sort_name
from music_assistant.common.models.config_entries import ConfigEntry, ConfigValueType
from music_assistant.common.models.enums import (
AlbumType,
item_id=key,
provider=self.instance_id,
name=name,
- uri=create_uri(media_type, self.instance_id, key),
- sort_name=create_sort_name(self.name),
)
async def _get_tidal_session(self) -> TidalSession:
import pytube
-from music_assistant.common.helpers.uri import create_uri
-from music_assistant.common.helpers.util import create_sort_name
from music_assistant.common.models.config_entries import ConfigEntry, ConfigValueType
from music_assistant.common.models.enums import ConfigEntryType, ProviderFeature
from music_assistant.common.models.errors import (
def _get_item_mapping(self, media_type: MediaType, key: str, name: str) -> ItemMapping:
return ItemMapping(
- media_type,
- key,
- self.instance_id,
- name,
- create_uri(media_type, self.instance_id, key),
- create_sort_name(self.name),
+ media_type=media_type,
+ item_id=key,
+ provider=self.instance_id,
+ name=name,
)
def _get_artist_item_mapping(self, artist_obj: dict) -> ItemMapping: