Skip to content

ytmusic

YTMusic module for downloading and searching songs.

YouTubeMusic(*args, **kwargs) ¤

Bases: AudioProvider

YouTube Music audio provider class

Arguments¤
  • args: Arguments passed to the AudioProvider class.
  • kwargs: Keyword arguments passed to the AudioProvider class.
Source code in spotdl/providers/audio/ytmusic.py
31
32
33
34
35
36
37
38
39
40
41
42
def __init__(self, *args: Any, **kwargs: Any) -> None:
    """
    Initialize the YouTube Music API

    ### Arguments
    - args: Arguments passed to the `AudioProvider` class.
    - kwargs: Keyword arguments passed to the `AudioProvider` class.
    """

    super().__init__(*args, **kwargs)

    self.client = self._create_client()

get_results(search_term, log_search_failures=True, **kwargs) ¤

Get results from YouTube Music API and simplify them

Arguments¤
  • search_term: The search term to search for.
  • log_search_failures: Whether to log when a search returns no usable results.
  • kwargs: other keyword arguments passed to the YTMusic.search method.
Returns¤
  • A list of simplified results (dicts)
Source code in spotdl/providers/audio/ytmusic.py
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def get_results(
    self, search_term: str, log_search_failures: bool = True, **kwargs
) -> List[Result]:
    """
    Get results from YouTube Music API and simplify them

    ### Arguments
    - search_term: The search term to search for.
    - log_search_failures: Whether to log when a search returns no usable results.
    - kwargs: other keyword arguments passed to the `YTMusic.search` method.

    ### Returns
    - A list of simplified results (dicts)
    """

    is_isrc_result = ISRC_REGEX.search(search_term) is not None
    # if is_isrc_result:
    #     print("FORCEFULLY SETTING FILTER TO SONGS")
    #     kwargs["filter"] = "songs"

    for attempt in range(self.SEARCH_ATTEMPTS):
        search_results = self.client.search(search_term, **kwargs)

        # Simplify results
        results = []
        for result in search_results:
            if (
                result is None
                or result.get("videoId") is None
                or result.get("artists") in [[], None]
            ):
                continue

            results.append(
                Result(
                    source=self.name,
                    url=(
                        f'https://{"music" if result["resultType"] == "song" else "www"}'
                        f".youtube.com/watch?v={result['videoId']}"
                    ),
                    verified=result.get("resultType") == "song",
                    name=result["title"],
                    result_id=result["videoId"],
                    author=result["artists"][0]["name"],
                    artists=tuple(map(lambda a: a["name"], result["artists"])),
                    duration=parse_duration(result.get("duration")),
                    isrc_search=is_isrc_result,
                    search_query=search_term,
                    explicit=result.get("isExplicit"),
                    album=(
                        result.get("album", {}).get("name")
                        if result.get("album")
                        else None
                    ),
                )
            )

        if results:
            return results

        if attempt == self.SEARCH_ATTEMPTS - 1:
            if not log_search_failures:
                return []

            logger.info(
                "YouTube Music returned no usable results for %s after %s attempts",
                search_term,
                self.SEARCH_ATTEMPTS,
            )
            return []

        if log_search_failures:
            logger.debug(
                "YouTube Music returned no usable results for %s on attempt %s/%s, "
                "retrying with a new client",
                search_term,
                attempt + 1,
                self.SEARCH_ATTEMPTS,
            )
        self.client = self._create_client()

    return []