ytmusicapi: Unofficial API for YouTube Music
********************************************

The purpose of this library is to automate interactions with YouTube
Music, such as retrieving your library content, managing playlists and
uploading songs. To achieve this, it emulates web requests that would
occur if you performed the same actions in your web browser.

**This project is not supported nor endorsed by Google**


Features
========

   **Browsing**:

* search (including all filters) and suggestions

* get artist information and releases (songs, videos, albums, singles,
  related artists)

* get user information (videos, playlists)

* get albums

* get song metadata

* get watch playlists (next songs when you press play/radio/shuffle in
  YouTube Music)

* get song lyrics

   **Exploring music**:

* get moods and genres playlists

* get latest charts (globally and per country)

   **Library management**:

* get library contents: playlists, songs, artists, albums and
  subscriptions, podcasts, channels

* add/remove library content: rate songs, albums and playlists,
  subscribe/unsubscribe artists

* get and modify play history

   **Playlists**:

* create and delete playlists

* modify playlists: edit metadata, add/move/remove tracks

* get playlist contents

* get playlist suggestions

   **Podcasts**:

* get podcasts

* get episodes

* get channels

* get episodes playlists

   **Uploads**:

* upload songs and remove them again

* list uploaded songs, artists and albums

   **Localization**:

* all regions are supported (see locations FAQ

* 16 languages are supported (see languages FAQ

If you find something missing or broken, check the FAQ or feel free to
create an issue.


Requirements
============

* Python 3.10 or higher - https://www.python.org


Setup
=====

See the Documentation for detailed instructions


Usage
=====

   from ytmusicapi import YTMusic

   yt = YTMusic('oauth.json')
   playlistId = yt.create_playlist('test', 'test description')
   search_results = yt.search('Oasis Wonderwall')
   yt.add_playlist_items(playlistId, [search_results[0]['videoId']])

The tests are also a great source of usage examples.

To **get started**, read the setup instructions.

For a **complete documentation** of available functions, see the
Reference.


Contents
========

* Setup

  * OAuth authentication

  * Browser authentication

    * Copy authentication headers

    * Using the headers in your project

    * Manual file creation

* Usage

  * Unauthenticated

  * Authenticated

    * Brand accounts

* Reference

  * YTMusic

    * "YTMusic"

    * "YTMusic.__init__()"

  * Setup

    * "setup()"

    * "setup_oauth()"

  * Search

    * "YTMusic.search()"

    * "YTMusic.get_search_suggestions()"

    * "YTMusic.remove_search_suggestions()"

  * Browsing

    * "YTMusic.get_home()"

    * "YTMusic.get_artist()"

    * "YTMusic.get_artist_albums()"

    * "YTMusic.get_album()"

    * "YTMusic.get_album_browse_id()"

    * "YTMusic.get_user()"

    * "YTMusic.get_user_playlists()"

    * "YTMusic.get_user_videos()"

    * "YTMusic.get_song()"

    * "YTMusic.get_song_related()"

    * "YTMusic.get_lyrics()"

    * "YTMusic.get_tasteprofile()"

    * "YTMusic.set_tasteprofile()"

    * "YTMusic.get_song_credits()"

  * Explore

    * "YTMusic.get_mood_categories()"

    * "YTMusic.get_mood_playlists()"

    * "YTMusic.get_charts()"

  * Watch

    * "YTMusic.get_watch_playlist()"

  * Library

    * "YTMusic.get_library_playlists()"

    * "YTMusic.get_library_songs()"

    * "YTMusic.get_library_albums()"

    * "YTMusic.get_library_artists()"

    * "YTMusic.get_library_subscriptions()"

    * "YTMusic.get_library_podcasts()"

    * "YTMusic.get_library_channels()"

    * "YTMusic.get_liked_songs()"

    * "YTMusic.get_saved_episodes()"

    * "YTMusic.get_history()"

    * "YTMusic.add_history_item()"

    * "YTMusic.remove_history_items()"

    * "YTMusic.rate_song()"

    * "YTMusic.edit_song_library_status()"

    * "YTMusic.rate_playlist()"

    * "YTMusic.subscribe_artists()"

    * "YTMusic.unsubscribe_artists()"

    * "YTMusic.get_account_info()"

  * Playlists

    * "YTMusic.get_playlist()"

    * "YTMusic.create_playlist()"

    * "YTMusic.join_collaborative_playlist()"

    * "YTMusic.edit_playlist()"

    * "YTMusic.delete_playlist()"

    * "YTMusic.add_playlist_items()"

    * "YTMusic.remove_playlist_items()"

  * Podcasts

    * "YTMusic.get_channel()"

    * "YTMusic.get_channel_episodes()"

    * "YTMusic.get_podcast()"

    * "YTMusic.get_episode()"

    * "YTMusic.get_episodes_playlist()"

  * Uploads

    * "YTMusic.get_library_upload_songs()"

    * "YTMusic.get_library_upload_artists()"

    * "YTMusic.get_library_upload_albums()"

    * "YTMusic.get_library_upload_artist()"

    * "YTMusic.get_library_upload_album()"

    * "YTMusic.upload_song()"

    * "YTMusic.delete_upload_entity()"

  * ytmusicapi

    * ytmusicapi package

      * Subpackages

        * ytmusicapi.auth package

          * Subpackages

            * ytmusicapi.auth.oauth package

              * Submodules

              * ytmusicapi.auth.oauth.credentials module

                * "Credentials"

                  * "Credentials.client_id"

                  * "Credentials.client_secret"

                  * "Credentials.get_code()"

                  * "Credentials.refresh_token()"

                  * "Credentials.token_from_code()"

                * "OAuthCredentials"

                  * "OAuthCredentials.client_id"

                  * "OAuthCredentials.client_secret"

                  * "OAuthCredentials.get_code()"

                  * "OAuthCredentials.refresh_token()"

                  * "OAuthCredentials.token_from_code()"

              * ytmusicapi.auth.oauth.exceptions module

                * "BadOAuthClient"

                * "UnauthorizedOAuthClient"

              * ytmusicapi.auth.oauth.models module

                * "AuthCodeDict"

                  * "AuthCodeDict.device_code"

                  * "AuthCodeDict.expires_in"

                  * "AuthCodeDict.interval"

                  * "AuthCodeDict.user_code"

                  * "AuthCodeDict.verification_url"

                * "BaseTokenDict"

                  * "BaseTokenDict.access_token"

                  * "BaseTokenDict.expires_in"

                  * "BaseTokenDict.scope"

                  * "BaseTokenDict.token_type"

                * "RefreshableTokenDict"

                  * "RefreshableTokenDict.expires_at"

                  * "RefreshableTokenDict.refresh_token"

                  * "RefreshableTokenDict.refresh_token_expires_in"

              * ytmusicapi.auth.oauth.token module

                * "OAuthToken"

                  * "OAuthToken.from_json()"

                  * "OAuthToken.is_expiring"

                  * "OAuthToken.is_oauth()"

                  * "OAuthToken.update()"

                * "RefreshingToken"

                  * "RefreshingToken.credentials"

                  * "RefreshingToken.local_cache"

                  * "RefreshingToken.prompt_for_token()"

                  * "RefreshingToken.store_token()"

                * "Token"

                  * "Token.access_token"

                  * "Token.as_auth()"

                  * "Token.as_dict()"

                  * "Token.as_json()"

                  * "Token.expires_at"

                  * "Token.expires_in"

                  * "Token.is_expiring"

                  * "Token.members()"

                  * "Token.refresh_token"

                  * "Token.scope"

                  * "Token.token_type"

              * Module contents

                * "OAuthCredentials"

                  * "OAuthCredentials.client_id"

                  * "OAuthCredentials.client_secret"

                  * "OAuthCredentials.get_code()"

                  * "OAuthCredentials.refresh_token()"

                  * "OAuthCredentials.token_from_code()"

                * "OAuthToken"

                  * "OAuthToken.from_json()"

                  * "OAuthToken.is_expiring"

                  * "OAuthToken.is_oauth()"

                  * "OAuthToken.update()"

                * "RefreshingToken"

                  * "RefreshingToken.credentials"

                  * "RefreshingToken.local_cache"

                  * "RefreshingToken.prompt_for_token()"

                  * "RefreshingToken.store_token()"

          * Submodules

          * ytmusicapi.auth.auth_parse module

            * "determine_auth_type()"

            * "parse_auth_str()"

          * ytmusicapi.auth.browser module

            * "is_browser()"

            * "setup_browser()"

          * ytmusicapi.auth.types module

            * "AuthType"

              * "AuthType.BROWSER"

              * "AuthType.OAUTH_CUSTOM_CLIENT"

              * "AuthType.OAUTH_CUSTOM_FULL"

              * "AuthType.UNAUTHORIZED"

          * Module contents

        * ytmusicapi.mixins package

          * Submodules

          * ytmusicapi.mixins.browsing module

            * "BrowsingMixin"

              * "BrowsingMixin.ArtistOrderType"

              * "BrowsingMixin.get_album()"

              * "BrowsingMixin.get_album_browse_id()"

              * "BrowsingMixin.get_artist()"

              * "BrowsingMixin.get_artist_albums()"

              * "BrowsingMixin.get_basejs_url()"

              * "BrowsingMixin.get_home()"

              * "BrowsingMixin.get_lyrics()"

              * "BrowsingMixin.get_signatureTimestamp()"

              * "BrowsingMixin.get_song()"

              * "BrowsingMixin.get_song_credits()"

              * "BrowsingMixin.get_song_related()"

              * "BrowsingMixin.get_tasteprofile()"

              * "BrowsingMixin.get_user()"

              * "BrowsingMixin.get_user_playlists()"

              * "BrowsingMixin.get_user_videos()"

              * "BrowsingMixin.set_tasteprofile()"

          * ytmusicapi.mixins.charts module

            * "ChartsMixin"

              * "ChartsMixin.get_charts()"

          * ytmusicapi.mixins.explore module

            * "ExploreMixin"

              * "ExploreMixin.get_explore()"

              * "ExploreMixin.get_mood_categories()"

              * "ExploreMixin.get_mood_playlists()"

          * ytmusicapi.mixins.library module

            * "LibraryMixin"

              * "LibraryMixin.add_history_item()"

              * "LibraryMixin.edit_song_library_status()"

              * "LibraryMixin.get_account_info()"

              * "LibraryMixin.get_history()"

              * "LibraryMixin.get_library_albums()"

              * "LibraryMixin.get_library_artists()"

              * "LibraryMixin.get_library_channels()"

              * "LibraryMixin.get_library_playlists()"

              * "LibraryMixin.get_library_podcasts()"

              * "LibraryMixin.get_library_songs()"

              * "LibraryMixin.get_library_subscriptions()"

              * "LibraryMixin.rate_playlist()"

              * "LibraryMixin.rate_song()"

              * "LibraryMixin.remove_history_items()"

              * "LibraryMixin.subscribe_artists()"

              * "LibraryMixin.unsubscribe_artists()"

          * ytmusicapi.mixins.playlists module

            * "PlaylistsMixin"

              * "PlaylistsMixin.add_playlist_items()"

              * "PlaylistsMixin.create_playlist()"

              * "PlaylistsMixin.delete_playlist()"

              * "PlaylistsMixin.edit_playlist()"

              * "PlaylistsMixin.get_liked_songs()"

              * "PlaylistsMixin.get_playlist()"

              * "PlaylistsMixin.get_saved_episodes()"

              * "PlaylistsMixin.join_collaborative_playlist()"

              * "PlaylistsMixin.remove_playlist_items()"

          * ytmusicapi.mixins.podcasts module

            * "PodcastsMixin"

              * "PodcastsMixin.get_channel()"

              * "PodcastsMixin.get_channel_episodes()"

              * "PodcastsMixin.get_episode()"

              * "PodcastsMixin.get_episodes_playlist()"

              * "PodcastsMixin.get_podcast()"

          * ytmusicapi.mixins.search module

            * "SearchMixin"

              * "SearchMixin.get_search_suggestions()"

              * "SearchMixin.remove_search_suggestions()"

              * "SearchMixin.search()"

          * ytmusicapi.mixins.uploads module

            * "UploadsMixin"

              * "UploadsMixin.delete_upload_entity()"

              * "UploadsMixin.get_library_upload_album()"

              * "UploadsMixin.get_library_upload_albums()"

              * "UploadsMixin.get_library_upload_artist()"

              * "UploadsMixin.get_library_upload_artists()"

              * "UploadsMixin.get_library_upload_songs()"

              * "UploadsMixin.upload_song()"

          * ytmusicapi.mixins.watch module

            * "WatchMixin"

              * "WatchMixin.get_watch_playlist()"

          * Module contents

        * ytmusicapi.models package

          * Subpackages

            * ytmusicapi.models.content package

              * Submodules

              * ytmusicapi.models.content.TextRun module

                * "HyperLink"

                  * "HyperLink.text"

                  * "HyperLink.url"

                * "PlainText"

                  * "PlainText.text"

              * ytmusicapi.models.content.enums module

                * "LikeStatus"

                  * "LikeStatus.DISLIKE"

                  * "LikeStatus.INDIFFERENT"

                  * "LikeStatus.LIKE"

                * "PlaylistSortOrder"

                  * "PlaylistSortOrder.MANUAL"

                  * "PlaylistSortOrder.NEWEST_FIRST"

                  * "PlaylistSortOrder.NEWEST_LAST"

                  * "PlaylistSortOrder.TOP_VOTED"

                * "PlaylistVoteEditOptions"

                  * "PlaylistVoteEditOptions.COLLABORATORS_ONLY"

                  * "PlaylistVoteEditOptions.EVERYONE_CAN_VOTE"

                  * "PlaylistVoteEditOptions.OFF"

                  * "PlaylistVoteEditOptions.get_argument_for_request(
                    )"

                * "PrivacyStatus"

                  * "PrivacyStatus.PRIVATE"

                  * "PrivacyStatus.PUBLIC"

                  * "PrivacyStatus.UNLISTED"

                * "VideoType"

                  * "VideoType.ATV"

                  * "VideoType.OFFICIAL_SOURCE_MUSIC"

                  * "VideoType.OMV"

                  * "VideoType.UGC"

                * "VoteStatus"

                  * "VoteStatus.DOWNVOTED"

                  * "VoteStatus.UNSPECIFIED"

                  * "VoteStatus.UPVOTED"

              * Module contents

          * Submodules

          * ytmusicapi.models.lyrics module

            * "LyricLine"

              * "LyricLine.end_time"

              * "LyricLine.from_raw()"

              * "LyricLine.id"

              * "LyricLine.start_time"

              * "LyricLine.text"

            * "Lyrics"

              * "Lyrics.hasTimestamps"

              * "Lyrics.lyrics"

              * "Lyrics.source"

            * "TimedLyrics"

              * "TimedLyrics.hasTimestamps"

              * "TimedLyrics.lyrics"

              * "TimedLyrics.source"

          * Module contents

            * "LyricLine"

              * "LyricLine.end_time"

              * "LyricLine.from_raw()"

              * "LyricLine.id"

              * "LyricLine.start_time"

              * "LyricLine.text"

            * "Lyrics"

              * "Lyrics.hasTimestamps"

              * "Lyrics.lyrics"

              * "Lyrics.source"

            * "TimedLyrics"

              * "TimedLyrics.hasTimestamps"

              * "TimedLyrics.lyrics"

              * "TimedLyrics.source"

        * ytmusicapi.parsers package

          * Submodules

          * ytmusicapi.parsers.albums module

            * "parse_album_header()"

            * "parse_album_header_2024()"

            * "parse_album_playlistid_if_exists()"

          * ytmusicapi.parsers.artists module

            * "parse_artists_runs()"

          * ytmusicapi.parsers.browsing module

            * "parse_album()"

            * "parse_content_list()"

            * "parse_mixed_content()"

            * "parse_playlist()"

            * "parse_related_artist()"

            * "parse_single()"

            * "parse_song()"

            * "parse_song_flat()"

            * "parse_video()"

            * "parse_watch_playlist()"

          * ytmusicapi.parsers.constants module

          * ytmusicapi.parsers.explore module

            * "parse_chart_artist()"

            * "parse_chart_episode()"

            * "parse_chart_playlist()"

            * "parse_chart_song()"

            * "parse_ranking()"

            * "parse_trending_item()"

          * ytmusicapi.parsers.i18n module

            * "Parser"

              * "Parser.get_api_result_types()"

              * "Parser.get_search_result_types()"

              * "Parser.get_song_credit_section_map()"

              * "Parser.parse_channel_contents()"

          * ytmusicapi.parsers.library module

            * "get_library_contents()"

            * "parse_albums()"

            * "parse_artists()"

            * "parse_library_albums()"

            * "parse_library_artists()"

            * "parse_library_podcasts()"

            * "parse_library_songs()"

            * "pop_songs_random_mix()"

          * ytmusicapi.parsers.playlists module

            * "parse_audio_playlist()"

            * "parse_playlist_header()"

            * "parse_playlist_header_meta()"

            * "parse_playlist_item()"

            * "parse_playlist_items()"

            * "validate_playlist_id()"

          * ytmusicapi.parsers.podcasts module

            * "Description"

              * "Description.from_runs()"

              * "Description.text"

            * "DescriptionElement"

              * "DescriptionElement.text"

            * "Link"

              * "Link.url"

            * "Timestamp"

              * "Timestamp.seconds"

            * "parse_base_header()"

            * "parse_episode()"

            * "parse_episode_flat()"

            * "parse_episode_header()"

            * "parse_podcast()"

            * "parse_podcast_header()"

          * ytmusicapi.parsers.search module

            * "get_search_params()"

            * "get_search_result_type()"

            * "parse_search_result()"

            * "parse_search_results()"

            * "parse_search_suggestions()"

            * "parse_top_result()"

          * ytmusicapi.parsers.songs module

            * "parse_like_status()"

            * "parse_song_album()"

            * "parse_song_artists()"

            * "parse_song_menu_data()"

            * "parse_song_run()"

            * "parse_song_runs()"

          * ytmusicapi.parsers.uploads module

            * "parse_uploaded_items()"

          * ytmusicapi.parsers.watch module

            * "get_tab_browse_ids()"

            * "parse_watch_playlist()"

            * "parse_watch_track()"

          * Module contents

      * Submodules

      * ytmusicapi.constants module

      * ytmusicapi.continuations module

        * "get_continuation_contents()"

        * "get_continuation_params()"

        * "get_continuation_string()"

        * "get_continuation_token()"

        * "get_continuations()"

        * "get_continuations_2025()"

        * "get_parsed_continuation_items()"

        * "get_reloadable_continuation_params()"

        * "get_reloadable_continuations()"

        * "get_validated_continuations()"

        * "resend_request_until_parsed_response_is_valid()"

        * "validate_response()"

      * ytmusicapi.enums module

        * "ResponseStatus"

          * "ResponseStatus.SUCCEEDED"

      * ytmusicapi.exceptions module

        * "YTMusicError"

        * "YTMusicServerError"

        * "YTMusicUserError"

      * ytmusicapi.helpers module

        * "get_authorization()"

        * "get_visitor_id()"

        * "initialize_context()"

        * "initialize_headers()"

        * "parse_description_runs()"

        * "sapisid_from_cookie()"

        * "sum_total_duration()"

        * "to_int()"

      * ytmusicapi.navigation module

        * "find_object_by_key()"

        * "find_objects_by_key()"

        * "nav()"

      * ytmusicapi.setup module

        * "main()"

        * "parse_args()"

        * "setup()"

        * "setup_oauth()"

      * ytmusicapi.type_alias module

      * ytmusicapi.ytmusic module

        * "YTMusic"

        * "YTMusicBase"

          * "YTMusicBase.as_mobile()"

          * "YTMusicBase.base_headers"

          * "YTMusicBase.headers"

          * "YTMusicBase.proxies"

      * Module contents

        * "LikeStatus"

          * "LikeStatus.DISLIKE"

          * "LikeStatus.INDIFFERENT"

          * "LikeStatus.LIKE"

        * "OAuthCredentials"

          * "OAuthCredentials.client_id"

          * "OAuthCredentials.client_secret"

          * "OAuthCredentials.get_code()"

          * "OAuthCredentials.refresh_token()"

          * "OAuthCredentials.token_from_code()"

        * "YTMusic"

        * "setup()"

        * "setup_oauth()"

* FAQ

  * Setup

    * My library results are empty even though I set up my cookie
      correctly.

  * Usage

    * How do I add content to my library?

    * What are the different feedback tokens?

    * How can I get the radio playlist for a song, video, playlist or
      album?

    * How can I get the shuffle playlist for a playlist or album?

    * How can I get all my public playlists in a single request?

    * Can I download songs?

    * How do I package ytmusicapi with "pyinstaller"?

  * YouTube Music API Internals

    * Is there a difference between songs and videos?

    * Is there a rate limit?

    * What is a browseId?

    * Which videoTypes exist and what do they mean?

    * Why is ytmusicapi returning more results than requested with the
      limit parameter?

    * Which values can I use for languages?

    * Which values can I use for locations?
