##// END OF EJS Templates
Download youtube as videos, not always by links as html content
neko259 -
r1685:0fb0af80 default
parent child Browse files
Show More
@@ -1,95 +1,95 b''
1 1 import os
2 2 import re
3 3
4 4 from django.core.files.uploadedfile import SimpleUploadedFile, \
5 5 TemporaryUploadedFile
6 6 from pytube import YouTube
7 7 import requests
8 8
9 9 from boards.utils import validate_file_size
10 10
11 11 YOUTUBE_VIDEO_FORMAT = 'webm'
12 12
13 13 HTTP_RESULT_OK = 200
14 14
15 15 HEADER_CONTENT_LENGTH = 'content-length'
16 16 HEADER_CONTENT_TYPE = 'content-type'
17 17
18 18 FILE_DOWNLOAD_CHUNK_BYTES = 200000
19 19
20 20 YOUTUBE_URL = re.compile(r'https?://((www\.)?youtube\.com/watch\?v=|youtu.be/)[-\w]+')
21 21
22 22 TYPE_URL_ONLY = (
23 23 'application/xhtml+xml',
24 24 'text/html',
25 25 )
26 26
27 27
28 28 class Downloader:
29 29 @staticmethod
30 30 def handles(url: str) -> bool:
31 31 return False
32 32
33 33 @staticmethod
34 34 def download(url: str):
35 35 # Verify content headers
36 36 response_head = requests.head(url, verify=False)
37 37 content_type = response_head.headers[HEADER_CONTENT_TYPE].split(';')[0]
38 38 length_header = response_head.headers.get(HEADER_CONTENT_LENGTH)
39 39 if length_header:
40 40 length = int(length_header)
41 41 validate_file_size(length)
42 42 # Get the actual content into memory
43 43 response = requests.get(url, verify=False, stream=True)
44 44
45 45 # Download file, stop if the size exceeds limit
46 46 size = 0
47 47
48 48 # Set a dummy file name that will be replaced
49 49 # anyway, just keep the valid extension
50 50 filename = 'file.' + content_type.split('/')[1]
51 51
52 52 file = TemporaryUploadedFile(filename, content_type, 0, None, None)
53 53 for chunk in response.iter_content(FILE_DOWNLOAD_CHUNK_BYTES):
54 54 size += len(chunk)
55 55 validate_file_size(size)
56 56 file.write(chunk)
57 57
58 58 if response.status_code == HTTP_RESULT_OK:
59 59 return file
60 60
61 61
62 62 def download(url):
63 63 for downloader in Downloader.__subclasses__():
64 64 if downloader.handles(url):
65 65 return downloader.download(url)
66 66 # If nobody of the specific downloaders handles this, use generic
67 67 # one
68 68 return Downloader.download(url)
69 69
70 70
71 71 class YouTubeDownloader(Downloader):
72 72 @staticmethod
73 73 def download(url: str):
74 74 yt = YouTube()
75 75 yt.from_url(url)
76 76 videos = yt.filter(YOUTUBE_VIDEO_FORMAT)
77 77 if len(videos) > 0:
78 78 video = videos[0]
79 79 return Downloader.download(video.url)
80 80
81 81 @staticmethod
82 82 def handles(url: str) -> bool:
83 83 return YOUTUBE_URL.match(url)
84 84
85 85
86 86 class NothingDownloader(Downloader):
87 87 @staticmethod
88 88 def handles(url: str) -> bool:
89 89 response_head = requests.head(url, verify=False)
90 90 content_type = response_head.headers[HEADER_CONTENT_TYPE].split(';')[0]
91 return content_type in TYPE_URL_ONLY
91 return content_type in TYPE_URL_ONLY and not YOUTUBE_URL.match(url)
92 92
93 93 @staticmethod
94 94 def download(url: str):
95 95 return None
General Comments 0
You need to be logged in to leave comments. Login now