tombulled / python-youtube-music

Python 3 YouTube Music Web API Client
GNU General Public License v3.0
64 stars 13 forks source link

Wrong track id for album #6

Closed AndreasWidmer closed 3 years ago

AndreasWidmer commented 4 years ago

Hi again,

I'm not quite sure, if I understand the procedure for the YoutubeMusicDL correctly.

If I query an album, for example:

Album Id: 'OLAK5uy_lnq0cJODsQmIMi2jWRhi7P4Cnv7SbLD2k' https://music.youtube.com/playlist?list=OLAK5uy_lnq0cJODsQmIMi2jWRhi7P4Cnv7SbLD2k

I receive the following tracks (id + name) via api.album (or YouTubeMusicDL.download_album:

7appuMrrn7U Let It Sleep b1RKaRgVFKk The Black VX0Bu_klgvo I Won't Give In Bb4IBCQtd_M Sometimes It Ends C8vCl9jLe8Q The Lost Souls DKh-Ba0Y9UE Just A Slave To Rock n' Roll csryP0sYlh8 Send Me Home dI68HmO5G4I We'll Be OK ypQMbgXYOHA Here I Am 1xH2VmHYz4M Gone BdtnCTZ8yxM Undivided IM_zSxjS6v8 Circled By The Wolves

Let's pick VX0Bu_klgvo I Won't Give In because for this, you will get an live version of the song: this id leads to the YouTube video of the song https://www.youtube.com/watch?v=VX0Bu_klgvo

If I go to the album page https://music.youtube.com/playlist?list=OLAK5uy_lnq0cJODsQmIMi2jWRhi7P4Cnv7SbLD2k and use 'share' to display the url of the song I Won't Give In - I get the following url: https://music.youtube.com/watch?v=lvQf2sOlEgM&feature=share

So the correct Id would be lvQf2sOlEgM, which also gives me the right track via YouTubeMusicDL.download_song.

Am I doing something wrong? Thanks for the help

tombulled commented 4 years ago

Hi, I believe I understand what's happening here.

Just to check, if I may:

The 'free' access to YouTube Music which is allowed unauthenticated appears to be designed to show you the video instead of allowing you to listen to the audio version. This is to encourage you to sign-up for premium access.

I am not currently on a premium subscription, therefore upon attempting to access the url https://music.youtube.com/playlist?list=OLAK5uy_lnq0cJODsQmIMi2jWRhi7P4Cnv7SbLD2k I get redirected to https://music.youtube.com/playlist?list=OLAK5uy_kn8idCYpELuTEmHJ2R2NynjqSC6A04vv0. Thus the share url for me only ever shows the Live version's Id.

I have found a way to get around this, however it is less than a desirable solution. I'll keep looking for a better solution, however hopefully the code below will help you out for now:

import ytm

api   = ytm.YouTubeMusic()
ytmdl = ytm.YouTubeMusicDL(api)

artist = api.artist('UCkyUNKOAUdE7niWatpfXSpQ') # Asking Alexandria

songs = api.playlist(artist['songs']['playlist_id'])

albums = {}

for song in songs['tracks']:
    albums.setdefault(song['album']['name'], []).append(song)

the_black = albums['The Black']

for song in the_black:
    print('Song:', song['name'])

    while True:
        try:
            info = ytmdl.download_song(song['id'])

            print('\t', 'Downloaded!')

            break
        except Exception as error:
            print('\t', 'Error:', error, '(trying again)')
AndreasWidmer commented 4 years ago

Ah makes perfect sense. Yes, I am signed in with a premium subscription.

Did you tried your solution? For me it looks like songs = api.playlist(artist['songs']['playlist_id']) does not include song['album']['name'].

Or does this occur because I'm not on the last commit? Looks like there is something broken ;)

api.artist('UC8Yu1_yfN5qPh601Y4btsYw') Traceback (most recent call last): File "", line 1, in File "/Users/andreas/Projects/ytm/ytm/decorators/_enforce.py", line 117, in wrapper raise TypeError \ TypeError: Expected return value to be of type 'dict' not 'NoneType'

tombulled commented 4 years ago

You're very right, I've done some for research into the matter and requesting the Artist's Songs playlist seems to be the only viable solution to this.

The code above works fine for me, and I would definitely recommend staying up to date with the latest commits. As the library is still under development, things might break slightly before a stable v1.0 is released.

That specific issue raised is on my todo list and should become a more informative exception soon. Now that I know how to acquire audio only albums, I can update the code for YouTubeMusicDL to include the album metadata as well.

AndreasWidmer commented 4 years ago

Nice to hear ,thanks for taking care of it. Sorry if I misspoke, I tried your solution with the latest commit and I am still getting the error:

Traceback (most recent call last): File "test.py", line 6, in artist = api.artist('UCkyUNKOAUdE7niWatpfXSpQ') # Asking Alexandria File "/Users/andreas/Projects/ytm/ytm/decorators/_enforce.py", line 117, in wrapper raise TypeError \ TypeError: Expected return value to be of type 'dict' not 'NoneType'

tombulled commented 4 years ago

Ah no worries, I've just pushed a commit to make the exception more verbose. I believe it's generating an invalid shelf identifier.

With the latest commit, does the exception change?

I'm going to re-code all of the parsers at some point, so I'm happy to prioritise the artist() parser first.

AndreasWidmer commented 4 years ago

Yes, the exception does change:

Traceback (most recent call last): File "test.py", line 6, in artist = api.artist('UCkyUNKOAUdE7niWatpfXSpQ') # Asking Alexandria File "/Users/andreas/Projects/ytm/ytm/decorators/_enforce.py", line 112, in wrapper resp = func(*args, kwargs) File "/Users/andreas/Projects/ytm/ytm/decorators/enforce_return_value.py", line 52, in wrapper return func(*args, *kwargs) File "/Users/andreas/Projects/ytm/ytm/decorators/parse.py", line 53, in wrapper return parser(func(args, kwargs)) File "/Users/andreas/Projects/ytm/ytm/decorators/_enforce.py", line 112, in wrapper resp = func(*args, *kwargs) File "/Users/andreas/Projects/ytm/ytm/decorators/enforce_parameters.py", line 52, in wrapper return func(args, **kwargs) File "/Users/andreas/Projects/ytm/ytm/parsers/decorators/catch.py", line 56, in wrapper raise exceptions.ParserError \ ParserError: artist() encountered an error: Unrecognised sheld identifier: 'alben'

tombulled commented 4 years ago

Very interesting! This looks to be a language issue.

I recently changed the API to use the clients regional information instead of using a static 'en-GB'. This seems to be a side effect of that change.

I'll update the code to enforce an English response and will test with a VPN to check the issue above doesn't appear to be present.

AndreasWidmer commented 4 years ago

Is there a way to get in touch with you more directly? E.g. twitter or something? Maybe I can give you some assistance

tombulled commented 4 years ago

Some assistance would be greatly appreciated. Discord is probably the easiest way I can think of to communicate.

I've set up a Discord Server for the project here: https://discord.gg/vemXm5C

Please let me know if you have trouble joining or if Discord isn't the best solution for you. Thanks!