Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add YoutubeMusic MusicProvider #397

Merged
merged 46 commits into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c5879a9
Update settings
Jun 30, 2022
2b1ff23
Can query albums and tracks
MarvinSchenkel Jul 1, 2022
9956711
Add url parsing for playback
MarvinSchenkel Jul 1, 2022
5da0716
Generate valid stream urls
MarvinSchenkel Jul 2, 2022
0924725
Parse artist, album and track
MarvinSchenkel Jul 2, 2022
d90a093
Add serach for artist and album
MarvinSchenkel Jul 2, 2022
5efd176
Add get_album_tracks and get_playlist_tracks
MarvinSchenkel Jul 3, 2022
81c4a32
precommit fixes
MarvinSchenkel Jul 5, 2022
61bafe9
Add library_artist and library_album
MarvinSchenkel Jul 5, 2022
2c0ccc1
Add authentication from config
MarvinSchenkel Jul 6, 2022
c2cd62f
Add library playlist, library songs and artist albums
MarvinSchenkel Jul 6, 2022
c82e1b4
Update settings
Jun 30, 2022
4c0eb68
Can query albums and tracks
MarvinSchenkel Jul 1, 2022
67d1b2c
Add url parsing for playback
MarvinSchenkel Jul 1, 2022
e0712ce
Generate valid stream urls
MarvinSchenkel Jul 2, 2022
297811d
Parse artist, album and track
MarvinSchenkel Jul 2, 2022
8e4eeaf
Add serach for artist and album
MarvinSchenkel Jul 2, 2022
b6a3448
Add get_album_tracks and get_playlist_tracks
MarvinSchenkel Jul 3, 2022
7b2b8c2
precommit fixes
MarvinSchenkel Jul 5, 2022
99573b7
Add library_artist and library_album
MarvinSchenkel Jul 5, 2022
e9e279d
Add authentication from config
MarvinSchenkel Jul 6, 2022
84fba16
Add library playlist, library songs and artist albums
MarvinSchenkel Jul 6, 2022
31f0a95
Add library playlist, library songs and artist albums
MarvinSchenkel Jul 6, 2022
ac4814a
Add library playlist, library songs and artist albums
MarvinSchenkel Jul 6, 2022
8152e95
Merge branch 'music-assistant:master' into master
MarvinSchenkel Jul 6, 2022
dc98eeb
update example
marcelveldt Jul 6, 2022
cab585d
Update artists.py
marcelveldt Jul 6, 2022
09d0cf9
Update artists.py
marcelveldt Jul 6, 2022
ec0ad07
adjust example
marcelveldt Jul 6, 2022
01c1210
Update full.py
marcelveldt Jul 6, 2022
5d01114
Add artist to track when possible
MarvinSchenkel Jul 6, 2022
9a04b98
Merge branch 'master' of https://github.com/MarvinSchenkel/music-assi…
MarvinSchenkel Jul 6, 2022
c4a732e
fix streaming
marcelveldt Jul 6, 2022
1dda6a5
Merge branch 'master' of https://github.com/MarvinSchenkel/music-assi…
marcelveldt Jul 6, 2022
9731666
parse contenttype
marcelveldt Jul 6, 2022
43ab57c
Fix parse tracks
MarvinSchenkel Jul 6, 2022
cd3b14d
Merge branch 'master' of https://github.com/MarvinSchenkel/music-assi…
MarvinSchenkel Jul 6, 2022
aafe581
guard missing album
marcelveldt Jul 6, 2022
5b5cf9c
lint
marcelveldt Jul 6, 2022
ade2488
Merge branch 'master' into pr/397
marcelveldt Jul 6, 2022
fe72c05
Various prasing fixes
MarvinSchenkel Jul 6, 2022
d3c41ec
run blocking call in executor
marcelveldt Jul 6, 2022
735938e
Fix track images
MarvinSchenkel Jul 6, 2022
b77af98
Merge branch 'master' of https://github.com/MarvinSchenkel/music-assi…
MarvinSchenkel Jul 6, 2022
6a9e782
Add artist top tracks
MarvinSchenkel Jul 7, 2022
a6e6cb7
Remove ytmusic example
MarvinSchenkel Jul 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading