5
\$\begingroup\$

This code takes a YouTube video and download it. It supports only non-copyrighted videos due to YouTube's new algorithms.

Any thoughts about the structure and the logic? I would like to learn from my mistakes, I've just started coding with python.

#!/usr/bin/env python3.5.2

import urllib.request, urllib.parse
import os


def main():
    """
    This code will download only non copyrighted youtube videos due to the new algorithms for accessing video files taht Youtube had changed. 
    Instead of "token" they now use "signature" variable, and "signature" seems to be dependent on either cookie-stored data or IP address of the client
    """
    print("\n                          * * * * * * * * * * * * * * *")
    print("                          *                           *")
    print("                          * Youtube Video Downloader! *")
    print("                          *                           *")
    print("                          * * * * * * * * * * * * * * *\n")
    # make sure to change directory path
    directory = r'C:\Users\SalahGfx\Desktop\DownloadedVideos'

    def get_sourcecode(url):
        return urllib.request.urlopen(url).read()

    def get_info():
        return urllib.parse.parse_qs(get_sourcecode(url).decode('unicode_escape'))

    def get_video_title_path():
        try:
            return os.path.join(directory, '{}.mp4'.format(get_info()['title'][0]))

        except KeyError:
            print('Parsing error, please rerun the code!')

    def get_stream_map():
        return get_info()['url']

    def get_stream_map_list():
        video_links = []
        for video_stream in get_stream_map():
            if "googlevideo" == video_stream.split('/')[2].split('.')[1]:
                video_links.append(video_stream)

            else:
                pass
        return video_links

    def validate_url(url):
        return url.startswith('https://www.youtube.com/')

    def download_video(k):
        return urllib.request.urlretrieve(get_stream_map_list()[k], get_video_title_path())

    def download_hq_video(quality):
        k = 0
        download_video(k)
        print("Downloading {} -----------> {} in {} quality.".format(get_stream_map_list()[k], get_video_title_path(),
                                                                     quality))

    def download_md_video(quality):
        k = 1
        download_video(k)
        print("Downloading {} -----------> {} in {} quality.".format(get_stream_map_list()[k], get_video_title_path(),
                                                                     quality))

    def download_sm_video(quality):
        k = 2
        download_video(k)
        print("Downloading {} -----------> {} in {} quality.".format(get_stream_map_list()[k], get_video_title_path(),
                                                                     quality))

    while True:
        try:
            url, quality = input(
                "Please type a youtube video url and its quality(choose between high, medium and small) and separate them with a space: ").split()

        except ValueError:
            print("Please type the right url and quality.");
            print("Make sure the url start with 'https://www.youtube.com/'");
            print("high - for downloading high quality video");
            print("medium - for downloading medium quality video");
            print("small - for downloading small quality video");
            continue

        if validate_url(url) and quality == 'high':
            get_sourcecode(url)
            download_hq_video(quality)
            break

        elif validate_url(url) and quality == 'medium':
            get_sourcecode(url)
            download_md_video(quality)
            break

        elif validate_url(url) and quality == 'small':
            get_sourcecode(url)
            download_sm_video(quality)
            break

        else:
            break

if __name__ == '__main__':
    main()
\$\endgroup\$
  • \$\begingroup\$ If anyone know how to download the copyrighted one please let me know! Really?! This code could work: google.com/search?q=is+it+legal+to+download+copyrighted+movies \$\endgroup\$ – Igor Soloydenko May 4 '17 at 23:08
  • \$\begingroup\$ You are talking about copyrighted videos. It doesn't matter whether it's YouTube or any other service. \$\endgroup\$ – Igor Soloydenko May 4 '17 at 23:11
  • 1
    \$\begingroup\$ You could always use youtube-dl \$\endgroup\$ – Peilonrayz May 4 '17 at 23:14
  • 3
    \$\begingroup\$ @IgorSoloydenko Your Google search tells me that downloading copyrighted videos from YouTube is legal at my location. It is an interesting technical question, albeit out of scope for codereview.stackexchange.com. \$\endgroup\$ – le_m May 5 '17 at 0:04
  • \$\begingroup\$ quick review: remove directory = r'C:\Users\SalahGfx\Desktop\DownloadedVideos' to the script current directory and '{}.mp4'.format(get_info()['title'][0]) process this to skip the spaces and unwanted characters from the file name. \$\endgroup\$ – arsho May 5 '17 at 9:29
1
\$\begingroup\$

I don't see why you want/need three functions to download the different quality videos. There is a bunch of repeated logic both in the functions and in the main loop.

Then, I would move all of the main specific code into the __name__ == __main__ section because that's the purpose of that section.

#!/usr/bin/env python3.5.2

import urllib.request, urllib.parse
import os

def get_sourcecode(url):
    return urllib.request.urlopen(url).read()

def get_info():
    return urllib.parse.parse_qs(get_sourcecode(url).decode('unicode_escape'))

def get_video_title_path():
    try:
        return os.path.join(directory, '{}.mp4'.format(get_info()['title'][0]))
    except KeyError:
        print('Parsing error, please rerun the code!')

def get_stream_map_list():
    video_links = []
    for video_stream in get_info()['url']:
        if "googlevideo" == video_stream.split('/')[2].split('.')[1]:
            video_links.append(video_stream)
    return video_links

quality_map = {'small': 0, 'medium': 1, 'high': 2}

def download_video(quality='medium'):
    k = quality_map.get(quality)
    map_list = get_stream_map_list()[k]
    title_path = get_video_title_path()

    print("Downloading {} -----------> {} in {} quality.".format(map_list, title_path, quality))
    return urllib.request.urlretrieve(map_list, title_path)


if __name__ == '__main__':
    print("\n                          * * * * * * * * * * * * * * *")
    print("                          *                           *")
    print("                          * Youtube Video Downloader! *")
    print("                          *                           *")
    print("                          * * * * * * * * * * * * * * *\n")
    # make sure to change directory path
    directory = r'C:\Users\SalahGfx\Desktop\DownloadedVideos'

    while True:
        try:
            url, quality = input(
                "Please type a youtube video url and its quality(choose between high, medium and small) and separate them with a space: ").split()

        except ValueError:
            print("Please type the right url and quality.");
            print("Make sure the url start with 'https://www.youtube.com/'");
            print("high - for downloading high quality video");
            print("medium - for downloading medium quality video");
            print("small - for downloading small quality video");
            continue

        if url.startswith('https://www.youtube.com/') and quality in quality_map:
            get_sourcecode(url)
            download_video(quality)
            break
\$\endgroup\$
  • \$\begingroup\$ it's the first time I came across the get method in a dictionary I should've just used the dict[key] that I already know,you did a good job in finding a solution instead of 3 functions 1 can do the same, thank you Sir I learned a lot. \$\endgroup\$ – Salah Eddine May 6 '17 at 11:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.