##// END OF EJS Templates
Allow youtube links without "www."
neko259 -
r1490:c93d62e4 default
parent child Browse files
Show More
@@ -1,69 +1,69 b''
1 import os
1 import os
2 import re
2 import re
3
3
4 from django.core.files.uploadedfile import SimpleUploadedFile, \
4 from django.core.files.uploadedfile import SimpleUploadedFile, \
5 TemporaryUploadedFile
5 TemporaryUploadedFile
6 from pytube import YouTube
6 from pytube import YouTube
7 import requests
7 import requests
8
8
9 from boards.utils import validate_file_size
9 from boards.utils import validate_file_size
10
10
11 YOUTUBE_VIDEO_FORMAT = 'webm'
11 YOUTUBE_VIDEO_FORMAT = 'webm'
12
12
13 HTTP_RESULT_OK = 200
13 HTTP_RESULT_OK = 200
14
14
15 HEADER_CONTENT_LENGTH = 'content-length'
15 HEADER_CONTENT_LENGTH = 'content-length'
16 HEADER_CONTENT_TYPE = 'content-type'
16 HEADER_CONTENT_TYPE = 'content-type'
17
17
18 FILE_DOWNLOAD_CHUNK_BYTES = 200000
18 FILE_DOWNLOAD_CHUNK_BYTES = 200000
19
19
20 YOUTUBE_URL = re.compile(r'https?://(www\.youtube\.com/watch\?v=|youtu.be/)\w+')
20 YOUTUBE_URL = re.compile(r'https?://((www\.)?youtube\.com/watch\?v=|youtu.be/)\w+')
21
21
22
22
23 class Downloader:
23 class Downloader:
24 @staticmethod
24 @staticmethod
25 def handles(url: str) -> bool:
25 def handles(url: str) -> bool:
26 return False
26 return False
27
27
28 @staticmethod
28 @staticmethod
29 def download(url: str):
29 def download(url: str):
30 # Verify content headers
30 # Verify content headers
31 response_head = requests.head(url, verify=False)
31 response_head = requests.head(url, verify=False)
32 content_type = response_head.headers[HEADER_CONTENT_TYPE].split(';')[0]
32 content_type = response_head.headers[HEADER_CONTENT_TYPE].split(';')[0]
33 length_header = response_head.headers.get(HEADER_CONTENT_LENGTH)
33 length_header = response_head.headers.get(HEADER_CONTENT_LENGTH)
34 if length_header:
34 if length_header:
35 length = int(length_header)
35 length = int(length_header)
36 validate_file_size(length)
36 validate_file_size(length)
37 # Get the actual content into memory
37 # Get the actual content into memory
38 response = requests.get(url, verify=False, stream=True)
38 response = requests.get(url, verify=False, stream=True)
39
39
40 # Download file, stop if the size exceeds limit
40 # Download file, stop if the size exceeds limit
41 size = 0
41 size = 0
42
42
43 # Set a dummy file name that will be replaced
43 # Set a dummy file name that will be replaced
44 # anyway, just keep the valid extension
44 # anyway, just keep the valid extension
45 filename = 'file.' + content_type.split('/')[1]
45 filename = 'file.' + content_type.split('/')[1]
46
46
47 file = TemporaryUploadedFile(filename, content_type, 0, None, None)
47 file = TemporaryUploadedFile(filename, content_type, 0, None, None)
48 for chunk in response.iter_content(FILE_DOWNLOAD_CHUNK_BYTES):
48 for chunk in response.iter_content(FILE_DOWNLOAD_CHUNK_BYTES):
49 size += len(chunk)
49 size += len(chunk)
50 validate_file_size(size)
50 validate_file_size(size)
51 file.write(chunk)
51 file.write(chunk)
52
52
53 if response.status_code == HTTP_RESULT_OK:
53 if response.status_code == HTTP_RESULT_OK:
54 return file
54 return file
55
55
56
56
57 class YouTubeDownloader(Downloader):
57 class YouTubeDownloader(Downloader):
58 @staticmethod
58 @staticmethod
59 def download(url: str):
59 def download(url: str):
60 yt = YouTube()
60 yt = YouTube()
61 yt.from_url(url)
61 yt.from_url(url)
62 videos = yt.filter(YOUTUBE_VIDEO_FORMAT)
62 videos = yt.filter(YOUTUBE_VIDEO_FORMAT)
63 if len(videos) > 0:
63 if len(videos) > 0:
64 video = videos[0]
64 video = videos[0]
65 return Downloader.download(video.url)
65 return Downloader.download(video.url)
66
66
67 @staticmethod
67 @staticmethod
68 def handles(url: str) -> bool:
68 def handles(url: str) -> bool:
69 return YOUTUBE_URL.match(url)
69 return YOUTUBE_URL.match(url)
General Comments 0
You need to be logged in to leave comments. Login now