# Buggy code
def generate_youtube_url(raw_song, meta_tags, tries_remaining=5):
    """Search for the song on YouTube and generate a URL to its video."""
    # prevents an infinite loop but allows for a few retries
    if tries_remaining == 0:
        log.debug("No tries left. I quit.")
        return

    query = {"part": "snippet", "maxResults": 50, "type": "video"}

    if const.args.music_videos_only:
        query["videoCategoryId"] = "10"

    if not meta_tags:
        song = raw_song
        query["q"] = song
    else:
        song = "{0} - {1}".format(meta_tags["artists"][0]["name"], meta_tags["name"])
        query["q"] = song
    log.debug("query: {0}".format(query))

    data = pafy.call_gdata("search", query)
    data["items"] = list(
        filter(lambda x: x["id"].get("videoId") is not None, data["items"])
    )
    query_results = {
        "part": "contentDetails,snippet,statistics",
        "maxResults": 50,
        "id": ",".join(i["id"]["videoId"] for i in data["items"]),
    }
    log.debug("query_results: {0}".format(query_results))

    vdata = pafy.call_gdata("videos", query_results)

    videos = []
    for x in vdata["items"]:
        duration_s = pafy.playlist.parseISO8591(x["contentDetails"]["duration"])
        youtubedetails = {
            "link": x["id"],
            "title": x["snippet"]["title"],
            "videotime": internals.videotime_from_seconds(duration_s),
            "seconds": duration_s,
        }
        videos.append(youtubedetails)
        if not meta_tags:
            break

    if not videos:
        return None

    if const.args.manual:
        log.info(song)
        log.info("0. Skip downloading this song.\n")
        # fetch all video links on first page on YouTube
        for i, v in enumerate(videos):
            log.info(
                "{0}. {1} {2} {3}".format(
                    i + 1,
                    v["title"],
                    v["videotime"],
                    "http://youtube.com/watch?v=" + v["link"],
                )
            )
        # let user select the song to download
        result = internals.input_link(videos)
        if not result:
            return None
    else:
        if not meta_tags:
            # if the metadata could not be acquired, take the first result
            # from Youtube because the proper song length is unknown
            result = videos[0]
            log.debug("Since no metadata found on Spotify, going with the first result")
        else:
            # filter out videos that do not have a similar length to the Spotify song
            duration_tolerance = 10
            max_duration_tolerance = 20
            possible_videos_by_duration = list()

            """
            start with a reasonable duration_tolerance, and increment duration_tolerance
            until one of the Youtube results falls within the correct duration or
            the duration_tolerance has reached the max_duration_tolerance
            """
            while len(possible_videos_by_duration) == 0:
                possible_videos_by_duration = list(
                    filter(
                        lambda x: abs(x["seconds"] - meta_tags["duration"])
                        <= duration_tolerance,
                        videos,
                    )
                )
                duration_tolerance += 1
                if duration_tolerance > max_duration_tolerance:
                    log.error(
                        "{0} by {1} was not found.\n".format(
                            meta_tags["name"], meta_tags["artists"][0]["name"]
                        )
                    )
                    return None

            result = possible_videos_by_duration[0]

    if result:
        url = "http://youtube.com/watch?v=" + result["link"]
    else:
        url = None

    return url


# Traceback (urllib.error.HTTPError)
$ python ./spotdl.py -l ./playlist.txt -f /d/Music\ 02/ --log-level DEBUG

DEBUG: Python version: 3.6.1 |Anaconda 4.4.0 (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]
DEBUG: Platform: Windows-10-10.0.14393-SP0
DEBUG: {'album': None,
'avconv': False,
'config': None,
'download_only_metadata': False,
'dry_run': False,
'file_format': '{artist} - {track_name}',
'folder': 'D:/Music 02/',
'input_ext': '.m4a',
'list': './playlist.txt',
'log_level': 10,
'manual': False,
'music_videos_only': False,
'no_metadata': False,
'no_spaces': False,
'output_ext': '.mp3',
'overwrite': 'prompt',
'playlist': None,
'song': None,
'username': None}
INFO: Preparing to download 3 songs

DEBUG: Fetching metadata for given track URL
DEBUG: Fetching lyrics
<<(Truncated Meta Output)>>
DEBUG: query: {'part': 'snippet', 'maxResults': 50, 'type': 'video', 'q': 'Arctic Monkeys - R U Mine?'}
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\pafy\util.py", line 34, in call_gdata
data = g.opener.open(url).read().decode('utf-8')
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 532, in open
response = meth(req, response)
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 642, in http_response
'http', request, response, code, msg, hdrs)
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 570, in error
return self._call_chain(*args)
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 504, in _call_chain
result = func(*args)
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 650, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "./spotdl.py", line 185, in <module>
download_list(text_file=const.args.list)
File "./spotdl.py", line 79, in download_list
download_single(raw_song, number=number)
File "./spotdl.py", line 116, in download_single
content = youtube_tools.go_pafy(raw_song, meta_tags)
File "C:\Users\Jason Cemra\Downloads\spotify-downloader-master\core\youtube_tools.py", line 22, in go_pafy
track_url = generate_youtube_url(raw_song, meta_tags)
File "C:\Users\Jason Cemra\Downloads\spotify-downloader-master\core\youtube_tools.py", line 84, in generate_youtube_url
data = pafy.call_gdata('search', query)
File "C:\ProgramData\Anaconda3\lib\site-packages\pafy\util.py", line 42, in call_gdata
raise GdataError(errmsg)
pafy.util.GdataError: Youtube Error 403: The request cannot be completed because you have exceeded your <a href="/youtube/v3/getting-started#quota">quota</a>.

# Fixed code
def generate_youtube_url(raw_song, meta_tags):
    url_fetch = GenerateYouTubeURL(raw_song, meta_tags)
    if const.args.youtube_api_key:
        url = url_fetch.api()
    else:
        url = url_fetch.scrape()
    return url