Skip to content

Conversation

@Daveson217
Copy link

Closes #711

This PR adds the ability to upload custom thumbnails to playlists via edit_playlist.

Changes:

  1. Implemented a new helper method _upload_playlist_thumbnail in PlaylistsMixin. This replicates the resumable upload protocol (handshake + binary upload) used elsewhere in the codebase for song uploads, but adapted for the playlist image endpoint.
  2. Updated edit_playlist to accept a thumbnail argument (file path).
  3. Added logic to upload the image first, retrieve the encryptedBlobId, and append the ACTION_SET_CUSTOM_THUMBNAIL action to the request body.

Testing:

  1. Verified locally by uploading a JPG image to a personal playlist.
  2. Confirmed the thumbnail updated successfully on the YouTube Music web interface.

Test used:
yt.edit_playlist(playlistId="...", thumbnail="cover.jpg")

P.S.: I am happy to add a unit test for _upload_playlist_thumbnail if you could point me to an example of how you prefer to mock upload requests.

@codecov
Copy link

codecov bot commented Feb 1, 2026

Codecov Report

❌ Patch coverage is 8.57143% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.33%. Comparing base (9efd4ac) to head (6e34e26).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
ytmusicapi/mixins/playlists.py 8.57% 32 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #866      +/-   ##
==========================================
- Coverage   95.55%   94.33%   -1.22%     
==========================================
  Files          46       46              
  Lines        2543     2578      +35     
==========================================
+ Hits         2430     2432       +2     
- Misses        113      146      +33     
Flag Coverage Δ
unittests 94.33% <8.57%> (-1.22%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

moveItem: str | tuple[str, str] | None = None,
addPlaylistId: str | None = None,
addToTop: bool | None = None,
thumbnail: str | None = None,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use a pathlib.Path for this?

response = self._send_request(endpoint, body)
return response["status"] if "status" in response else response

def _upload_playlist_thumbnail(self, filepath: str) -> str | JsonDict:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for implementing the protocol! Could you add a test as well?

You could for example use one of the existing owned playlists on the test account and use an image that you add to the test data.

The action is idempotent, so you can simply keep reuploading the same image during the test.


headers = self.headers.copy()
# Get upload_url by sending an empty request to the upload endpoint
upload_url = "https://music.youtube.com/playlist_image_upload/playlist_custom_thumbnail"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- Updated  and  to use  for file handling.
- Replaced hardcoded URL with  constant.
- Added  to  to verify the full upload flow.
- Added  fixture for live testing.
- The  endpoint rejects binary uploads if the  is set to .
- Removed the header before the second request (binary upload) to fix the 400 Bad Request error in integration tests.
@Daveson217
Copy link
Author

@sigma67 here's what I have done so far:

  1. I added a test_edit_playlist_thumbnail function

  2. Refactored upload_url to use YTM_DOMAIN

  3. Refactored edit_playlist method definition parameter, thumbnail, to be a Path from pathlib.

  4. Added a test image in tests/data/mock_playlist_image.jpg

  5. Changed Content-Type header for thumbnail binary upload. The [music.youtube.com](http://music.youtube.com/) endpoint seems to reject (400 Bad Request error) binary uploads if the Content-Type is set to application/x-www-form-urlencoded. I then used mimetypes to determine the type of the image (e.g., image/jpeg).

Lastly, YoutubeMusic requires an image with a minimum dimension of 360x360. I couldn't find a straightforward way to implement image size checking, so I didn't add this check.

For the most recent build, I had tested the test_playlists.py file, and it passed locally but failed here. I will try to find out what's happening.

@Daveson217
Copy link
Author

@sigma67 I fixed the mypy and ruff issues.
The tests pass on my end locally.
Testing with yt.edit_playlist(playlistId="...", thumbnail="cover.jpg") also works fine locally.

What do you suggest?

@sigma67
Copy link
Owner

sigma67 commented Feb 4, 2026

I'm getting the same error locally, so not sure how I can help you here

Server returned HTTP 403: Forbidden.

@sigma67
Copy link
Owner

sigma67 commented Feb 5, 2026

If you suspect it's related to the brand account, you can also try using a different fixture like yt_auth. Although in the end it should also work with the brand account

@Daveson217
Copy link
Author

@sigma67 Thanks. I tried yt_oauth, but I ran into another error (build 9d2a842).

I am now trying to backtrack to see why it works fine on my PC but fails on CI and locally at your end.

I am trying to understand more: for the CI tests and prolly locally at your end, do you use oauth or browser auth?

@Daveson217
Copy link
Author

Daveson217 commented Feb 5, 2026

I now recall something else @sigma67 . To be able to add custom playlist thumbnails at all, you need to first go to the playlist and enable the function by verifying your phone number.

Do you think this could be the cause of the 403 error?

 ytmusicapi.exceptions.YTMusicServerError: Server returned HTTP 403: Forbidden.
 The caller does not have permission

@sigma67
Copy link
Owner

sigma67 commented Feb 9, 2026

My account has a verified phone number. I can change the image just fine on the web UI.

@sigma67
Copy link
Owner

sigma67 commented Feb 9, 2026

You should double check that you are using the same account as with the edit_playlist test - there are multiple accounts here, only the one that created it will be able to edit it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

edit_playlist: add playlist image

2 participants