##// END OF EJS Templates
Download webm videos from youtube
neko259 -
r1328:3352da82 default
parent child Browse files
Show More
@@ -0,0 +1,83 b''
1 import os
2 import re
3
4 from django.core.files.uploadedfile import SimpleUploadedFile
5 from pytube import YouTube
6 import requests
7
8 from boards.utils import validate_file_size
9
10 YOUTUBE_VIDEO_FORMAT = 'webm'
11
12 HTTP_RESULT_OK = 200
13
14 HEADER_CONTENT_LENGTH = 'content-length'
15 HEADER_CONTENT_TYPE = 'content-type'
16
17 FILE_DOWNLOAD_CHUNK_BYTES = 100000
18
19 YOUTUBE_URL = re.compile(r'https?://www\.youtube\.com/watch\?v=\w+')
20
21
22 class Downloader:
23 @staticmethod
24 def handles(url: str) -> bool:
25 return False
26
27 @staticmethod
28 def download(url: str):
29 # Verify content headers
30 response_head = requests.head(url, verify=False)
31 content_type = response_head.headers[HEADER_CONTENT_TYPE].split(';')[0]
32 length_header = response_head.headers.get(HEADER_CONTENT_LENGTH)
33 if length_header:
34 length = int(length_header)
35 validate_file_size(length)
36 # Get the actual content into memory
37 response = requests.get(url, verify=False, stream=True)
38
39 # Download file, stop if the size exceeds limit
40 size = 0
41 content = b''
42 for chunk in response.iter_content(FILE_DOWNLOAD_CHUNK_BYTES):
43 size += len(chunk)
44 validate_file_size(size)
45 content += chunk
46
47 if response.status_code == HTTP_RESULT_OK and content:
48 # Set a dummy file name that will be replaced
49 # anyway, just keep the valid extension
50 filename = 'file.' + content_type.split('/')[1]
51 return SimpleUploadedFile(filename, content, content_type)
52
53
54 class YouTubeDownloader(Downloader):
55 @staticmethod
56 def download(url: str):
57 yt = YouTube()
58 yt.from_url(url)
59 videos = yt.filter(YOUTUBE_VIDEO_FORMAT)
60 if len(videos) > 0:
61 video = videos[0]
62 filename = '{}.{}'.format(video.filename, video.extension)
63 try:
64 video.download(on_progress=YouTubeDownloader.on_progress)
65
66 file = open(filename, 'rb')
67 content = file.read()
68 file.close()
69
70 os.remove(filename)
71 return SimpleUploadedFile(filename, content, video.extension)
72 except Exception as e:
73 if os.path.isfile(filename):
74 os.remove(filename)
75 raise e
76
77 @staticmethod
78 def handles(url: str) -> bool:
79 return YOUTUBE_URL.match(url)
80
81 @staticmethod
82 def on_progress(bytes, file_size, start):
83 validate_file_size(file_size)
@@ -8,18 +8,16 b' from django.core.files.uploadedfile impo'
8 8 from django.core.exceptions import ObjectDoesNotExist
9 9 from django.forms.util import ErrorList
10 10 from django.utils.translation import ugettext_lazy as _
11 import requests
12 11
13 12 from boards.mdx_neboard import formatters
13 from boards.models.attachment.downloaders import Downloader
14 14 from boards.models.post import TITLE_MAX_LENGTH
15 15 from boards.models import Tag, Post
16 from boards.utils import validate_file_size
16 17 from neboard import settings
17 18 import boards.settings as board_settings
18 19 import neboard
19 20
20 HEADER_CONTENT_LENGTH = 'content-length'
21 HEADER_CONTENT_TYPE = 'content-type'
22
23 21 REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE)
24 22
25 23 VETERAN_POSTING_DELAY = 5
@@ -41,10 +39,6 b" ERROR_SPEED = _('Please wait %s seconds "
41 39
42 40 TAG_MAX_LENGTH = 20
43 41
44 FILE_DOWNLOAD_CHUNK_BYTES = 100000
45
46 HTTP_RESULT_OK = 200
47
48 42 TEXTAREA_ROWS = 4
49 43
50 44
@@ -182,7 +176,7 b' class PostForm(NeboardForm):'
182 176 file = self.cleaned_data['file']
183 177
184 178 if file:
185 self.validate_file_size(file.size)
179 validate_file_size(file.size)
186 180
187 181 return file
188 182
@@ -196,7 +190,7 b' class PostForm(NeboardForm):'
196 190 if not file:
197 191 raise forms.ValidationError(_('Invalid URL'))
198 192 else:
199 self.validate_file_size(file.size)
193 validate_file_size(file.size)
200 194
201 195 return file
202 196
@@ -294,13 +288,6 b' class PostForm(NeboardForm):'
294 288 if can_post:
295 289 self.session[LAST_POST_TIME] = now
296 290
297 def validate_file_size(self, size: int):
298 max_size = board_settings.get_int('Forms', 'MaxFileSize')
299 if size > max_size:
300 raise forms.ValidationError(
301 _('File must be less than %s bytes')
302 % str(max_size))
303
304 291 def _get_file_from_url(self, url: str) -> SimpleUploadedFile:
305 292 """
306 293 Gets an file file from URL.
@@ -309,36 +296,18 b' class PostForm(NeboardForm):'
309 296 img_temp = None
310 297
311 298 try:
312 # Verify content headers
313 response_head = requests.head(url, verify=False)
314 content_type = response_head.headers[HEADER_CONTENT_TYPE].split(';')[0]
315 length_header = response_head.headers.get(HEADER_CONTENT_LENGTH)
316 if length_header:
317 length = int(length_header)
318 self.validate_file_size(length)
319 # Get the actual content into memory
320 response = requests.get(url, verify=False, stream=True)
321
322 # Download file, stop if the size exceeds limit
323 size = 0
324 content = b''
325 for chunk in response.iter_content(FILE_DOWNLOAD_CHUNK_BYTES):
326 size += len(chunk)
327 self.validate_file_size(size)
328 content += chunk
329
330 if response.status_code == HTTP_RESULT_OK and content:
331 # Set a dummy file name that will be replaced
332 # anyway, just keep the valid extension
333 filename = 'file.' + content_type.split('/')[1]
334 img_temp = SimpleUploadedFile(filename, content,
335 content_type)
299 for downloader in Downloader.__subclasses__():
300 if downloader.handles(url):
301 return downloader.download(url)
302 # If nobody of the specific downloaders handles this, use generic
303 # one
304 return Downloader.download(url)
305 except forms.ValidationError as e:
306 raise e
336 307 except Exception as e:
337 308 # Just return no file
338 309 pass
339 310
340 return img_temp
341
342 311
343 312 class ThreadForm(PostForm):
344 313
@@ -7,8 +7,11 b' import hmac'
7 7
8 8 from django.core.cache import cache
9 9 from django.db.models import Model
10 from django import forms
10 11
11 12 from django.utils import timezone
13 from django.utils.translation import ugettext_lazy as _
14 import boards
12 15
13 16 from neboard import settings
14 17
@@ -90,3 +93,11 b' def get_file_hash(file) -> str:'
90 93 for chunk in file.chunks():
91 94 md5.update(chunk)
92 95 return md5.hexdigest()
96
97
98 def validate_file_size(size: int):
99 max_size = boards.settings.get_int('Forms', 'MaxFileSize')
100 if size > max_size:
101 raise forms.ValidationError(
102 _('File must be less than %s bytes')
103 % str(max_size))
@@ -1,3 +1,4 b''
1 pytube
1 2 requests
2 3 adjacent
3 4 django-haystack
General Comments 0
You need to be logged in to leave comments. Login now