Skip to content

Commit

Permalink
Add YoutubeMusic MusicProvider (#397)
Browse files Browse the repository at this point in the history
Co-authored-by: Marvin Schenkel <marvin@MacBook-Pro.local>
Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
  • Loading branch information
3 people committed Jul 7, 2022
1 parent 9f98c7e commit a211eae
Show file tree
Hide file tree
Showing 9 changed files with 769 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
"python.linting.flake8Enabled": true,
"python.linting.flake8Args": ["--config=${workspaceFolder}/setup.cfg"],
"python.linting.mypyEnabled": false,
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
}
27 changes: 23 additions & 4 deletions examples/full.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@
required=False,
help="Directory on disk for local music library",
)
parser.add_argument(
"--ytmusic-username",
required=False,
help="YoutubeMusic username",
)
parser.add_argument(
"--ytmusic-cookie",
required=False,
help="YoutubeMusic cookie",
)
parser.add_argument(
"--debug",
action="store_true",
Expand Down Expand Up @@ -102,6 +112,15 @@
username=args.tunein_username,
)
)

if args.ytmusic_username and args.ytmusic_cookie:
mass_conf.providers.append(
MusicProviderConfig(
ProviderType.YTMUSIC,
username=args.ytmusic_username,
password=args.ytmusic_cookie,
)
)
if args.musicdir:
mass_conf.providers.append(
MusicProviderConfig(type=ProviderType.FILESYSTEM_LOCAL, path=args.musicdir)
Expand Down Expand Up @@ -188,8 +207,8 @@ async def main():
print(f"Got {track_count} tracks ({track_count_lib} in library)")
radio_count = await mass.music.radio.count(True)
print(f"Got {radio_count} radio stations in library")
playlist_count = await mass.music.playlists.db_items(True)
print(f"Got {len(playlist_count)} playlists in library")
playlists = await mass.music.playlists.db_items(True)
print(f"Got {len(playlists)} playlists in library")
# register a player
test_player1 = TestPlayer("test1")
test_player2 = TestPlayer("test2")
Expand All @@ -204,8 +223,8 @@ async def main():
# we can also send an uri, such as spotify://track/abcdfefgh
# or database://playlist/1
# or a list of items
artist = await mass.music.artists.get("2", ProviderType.DATABASE)
await test_player1.active_queue.play_media(artist)
if len(playlists) > 0:
await test_player1.active_queue.play_media(playlists[0])

await asyncio.sleep(3600)

Expand Down
2 changes: 1 addition & 1 deletion music_assistant/controllers/metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ async def get_playlist_metadata(self, playlist: Playlist) -> None:
):
if track.metadata.genres:
playlist.metadata.genres.update(track.metadata.genres)
elif track.album.metadata.genres:
elif track.album and track.album.metadata.genres:
playlist.metadata.genres.update(track.album.metadata.genres)
# TODO: create mosaic thumb/fanart from playlist tracks
playlist.metadata.last_refresh = int(time())
Expand Down
2 changes: 2 additions & 0 deletions music_assistant/controllers/music/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from music_assistant.music_providers.tunein import TuneInProvider
from music_assistant.music_providers.url import PROVIDER_CONFIG as URL_CONFIG
from music_assistant.music_providers.url import URLProvider
from music_assistant.music_providers.ytmusic import YoutubeMusicProvider

if TYPE_CHECKING:
from music_assistant.mass import MusicAssistant
Expand All @@ -46,6 +47,7 @@
ProviderType.SPOTIFY: SpotifyProvider,
ProviderType.QOBUZ: QobuzProvider,
ProviderType.TUNEIN: TuneInProvider,
ProviderType.YTMUSIC: YoutubeMusicProvider,
}


Expand Down
2 changes: 1 addition & 1 deletion music_assistant/controllers/music/artists.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ async def add_db_item(
self, item: Artist, overwrite_existing: bool = False
) -> Artist:
"""Add a new item record to the database."""
assert item.provider_ids, "Album is missing provider id(s)"
assert item.provider_ids, "Artist is missing provider id(s)"
# always try to grab existing item by musicbrainz_id
cur_item = None
if item.musicbrainz_id:
Expand Down
21 changes: 13 additions & 8 deletions music_assistant/models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class AlbumType(Enum):
ALBUM = "album"
SINGLE = "single"
COMPILATION = "compilation"
EP = "ep"
UNKNOWN = "unknown"


Expand Down Expand Up @@ -96,17 +97,20 @@ class ContentType(Enum):
def try_parse(cls: "ContentType", string: str) -> "ContentType":
"""Try to parse ContentType from (url)string/extension."""
tempstr = string.lower()
if "." in tempstr:
tempstr = tempstr.split(".")[-1]
if "," in tempstr:
for val in tempstr.split(","):
try:
return cls(val.strip())
except ValueError:
pass
if "audio/" in tempstr:
tempstr = tempstr.split("/")[1]
for splitter in (".", ","):
if splitter in tempstr:
for val in tempstr.split(splitter):
try:
return cls(val.strip())
except ValueError:
pass

tempstr = tempstr.split("?")[0]
tempstr = tempstr.split("&")[0]
tempstr = tempstr.split(";")[0]
tempstr = tempstr.replace("mp4", "m4a")
try:
return cls(tempstr)
except ValueError:
Expand Down Expand Up @@ -209,6 +213,7 @@ class ProviderType(Enum):
SPOTIFY = "spotify"
QOBUZ = "qobuz"
TUNEIN = "tunein"
YTMUSIC = "ytmusic"
DATABASE = "database" # internal only
URL = "url" # internal only

Expand Down
1 change: 1 addition & 0 deletions music_assistant/models/music_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ async def sync_library(
)
if not db_item:
# dump the item in the db, rich metadata is lazy loaded later
print(prov_item)
db_item = await controller.add_db_item(prov_item)
elif (
db_item.metadata.checksum and prov_item.metadata.checksum
Expand Down

0 comments on commit a211eae

Please sign in to comment.