aboutsummaryrefslogtreecommitdiff
path: root/youtube_dl
diff options
context:
space:
mode:
authorTithen-Firion <tithen.firion.0@gmail.com>2017-04-25 01:06:14 +0200
committerTithen-Firion <tithen.firion.0@gmail.com>2017-04-25 01:06:14 +0200
commitda57ebaf84225240b356530cdf02d12596f0dce8 (patch)
tree513a92dbb17fb6af7b2ee8a74fee4f193b5f2339 /youtube_dl
parent47e0cef46e9a76e589a2b1cde1b2dfa8bcf01d8e (diff)
[openload] separate PhantomJS code from extractor
Diffstat (limited to 'youtube_dl')
-rw-r--r--youtube_dl/extractor/openload.py78
-rw-r--r--youtube_dl/utils.py141
2 files changed, 157 insertions, 62 deletions
diff --git a/youtube_dl/extractor/openload.py b/youtube_dl/extractor/openload.py
index 789bf997e..ac5e0bb08 100644
--- a/youtube_dl/extractor/openload.py
+++ b/youtube_dl/extractor/openload.py
@@ -1,17 +1,14 @@
# coding: utf-8
from __future__ import unicode_literals
-import os
import re
-import subprocess
-import tempfile
from .common import InfoExtractor
from ..utils import (
- check_executable,
determine_ext,
- encodeArgument,
ExtractorError,
+ get_element_by_id,
+ PhantomJSwrapper,
)
@@ -62,38 +59,7 @@ class OpenloadIE(InfoExtractor):
'only_matching': True,
}]
- _PHANTOMJS_SCRIPT = r'''
- phantom.onError = function(msg, trace) {
- var msgStack = ['PHANTOM ERROR: ' + msg];
- if(trace && trace.length) {
- msgStack.push('TRACE:');
- trace.forEach(function(t) {
- msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line
- + (t.function ? ' (in function ' + t.function +')' : ''));
- });
- }
- console.error(msgStack.join('\n'));
- phantom.exit(1);
- };
- var page = require('webpage').create();
- page.settings.resourceTimeout = 10000;
- page.onInitialized = function() {
- page.evaluate(function() {
- delete window._phantom;
- delete window.callPhantom;
- });
- };
- page.open('https://openload.co/embed/%s/', function(status) {
- var info = page.evaluate(function() {
- return {
- decoded_id: document.getElementById('streamurl').innerHTML,
- title: document.querySelector('meta[name="og:title"],'
- + 'meta[name=description]').content
- };
- });
- console.log(info.decoded_id + ' ' + info.title);
- phantom.exit();
- });'''
+ _USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
@staticmethod
def _extract_urls(webpage):
@@ -102,40 +68,27 @@ class OpenloadIE(InfoExtractor):
webpage)
def _real_extract(self, url):
- exe = check_executable('phantomjs', ['-v'])
- if not exe:
- raise ExtractorError('PhantomJS executable not found in PATH, '
- 'download it from http://phantomjs.org',
- expected=True)
-
video_id = self._match_id(url)
url = 'https://openload.co/embed/%s/' % video_id
- webpage = self._download_webpage(url, video_id)
+ headers = {
+ 'User-Agent': self._USER_AGENT,
+ }
+
+ phantom = PhantomJSwrapper(self)
+ webpage, _ = phantom.get(url, video_id=video_id, headers=headers)
if 'File not found' in webpage or 'deleted by the owner' in webpage:
raise ExtractorError('File not found', expected=True, video_id=video_id)
- script_file = tempfile.NamedTemporaryFile(mode='w', delete=False)
-
- # write JS script to file and close it
- with script_file:
- script_file.write(self._PHANTOMJS_SCRIPT % video_id)
-
- self.to_screen('%s: Decoding video ID with PhantomJS' % video_id)
-
- p = subprocess.Popen([exe, '--ssl-protocol=any', script_file.name],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output, err = p.communicate()
- if p.returncode != 0:
- raise ExtractorError('Decoding failed\n:'
- + encodeArgument(err))
- else:
- decoded_id, title = encodeArgument(output).strip().split(' ', 1)
-
- os.remove(script_file.name)
+ decoded_id = get_element_by_id('streamurl', webpage)
video_url = 'https://openload.co/stream/%s?mime=true' % decoded_id
+ title = self._og_search_title(webpage, default=None) or self._search_regex(
+ r'<span[^>]+class=["\']title["\'][^>]*>([^<]+)', webpage,
+ 'title', default=None) or self._html_search_meta(
+ 'description', webpage, 'title', fatal=True)
+
entries = self._parse_html5_media_entries(url, webpage, video_id)
entry = entries[0] if entries else {}
subtitles = entry.get('subtitles')
@@ -148,5 +101,6 @@ class OpenloadIE(InfoExtractor):
# Seems all videos have extensions in their titles
'ext': determine_ext(title, 'mp4'),
'subtitles': subtitles,
+ 'http_headers': headers,
}
return info_dict
diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py
index 2340bc306..94e1b07a6 100644
--- a/youtube_dl/utils.py
+++ b/youtube_dl/utils.py
@@ -3652,3 +3652,144 @@ def write_xattr(path, key, value):
"Couldn't find a tool to set the xattrs. "
"Install either the python 'xattr' module, "
"or the 'xattr' binary.")
+
+
+class PhantomJSwrapper(object):
+ """PhantomJS wrapper class"""
+
+ _TEMPLATE = r'''
+ phantom.onError = function(msg, trace) {{
+ var msgStack = ['PHANTOM ERROR: ' + msg];
+ if(trace && trace.length) {{
+ msgStack.push('TRACE:');
+ trace.forEach(function(t) {{
+ msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line
+ + (t.function ? ' (in function ' + t.function +')' : ''));
+ }});
+ }}
+ console.error(msgStack.join('\n'));
+ phantom.exit(1);
+ }};
+ var page = require('webpage').create();
+ var fs = require('fs');
+ var read = {{ mode: 'r', charset: 'utf-8' }};
+ var write = {{ mode: 'w', charset: 'utf-8' }};
+ page.settings.resourceTimeout = {timeout};
+ page.settings.userAgent = "{ua}";
+ page.onLoadStarted = function() {{
+ page.evaluate(function() {{
+ delete window._phantom;
+ delete window.callPhantom;
+ }});
+ }};
+ var saveAndExit = function() {{
+ fs.write("{html}", page.content, write);
+ phantom.exit();
+ }};
+ page.onLoadFinished = function(status) {{
+ if(page.url === "") {{
+ page.setContent(fs.read("{html}", read), "{url}");
+ }}
+ else {{
+ {jscode}
+ }}
+ }};
+ page.open("");
+ '''
+
+ _TMP_FILE_NAMES = ['script', 'html']
+
+ def __init__(self, extractor, timeout=10000):
+ self.exe = check_executable('phantomjs', ['-v'])
+ if not self.exe:
+ raise ExtractorError('PhantomJS executable not found in PATH, '
+ 'download it from http://phantomjs.org',
+ expected=True)
+ self.extractor = extractor
+ self.options = {
+ 'timeout': timeout,
+ }
+ self._TMP_FILES = {}
+ for name in self._TMP_FILE_NAMES:
+ tmp = tempfile.NamedTemporaryFile(delete=False)
+ tmp.close()
+ self._TMP_FILES[name] = tmp
+
+ def __del__(self):
+ for name in self._TMP_FILE_NAMES:
+ try:
+ os.remove(self._TMP_FILES[name].name)
+ except:
+ pass
+
+ def get(self, url, html=None, video_id=None, note=None, note2='Executing JS on webpage', headers={}, jscode='saveAndExit();'):
+ """
+ Downloads webpage (if needed) and executes JS
+
+ Params:
+ url: website url
+ html: optional, html code of website
+ video_id: video id
+ note: optional, displayed when downloading webpage
+ note2: optional, displayed when executing JS
+ headers: custom http headers
+ jscode: code to be executed when page is loaded
+
+ Returns tuple with:
+ * downloaded website (after JS execution)
+ * anything you print with `console.log` (but not inside `page.execute`!)
+
+ In most cases you don't need to add any `jscode`.
+ It is executed in `page.onLoadFinished`.
+ `saveAndExit();` is mandatory, use it instead of `phantom.exit()`
+ It is possible to wait for some element on the webpage, for example:
+ var check = function() {
+ var elementFound = page.evaluate(function() {
+ return document.querySelector('#b.done') !== null;
+ });
+ if(elementFound)
+ saveAndExit();
+ else
+ window.setTimeout(check, 500);
+ }
+
+ page.evaluate(function(){
+ document.querySelector('#a').click();
+ });
+ check();
+ """
+ if 'saveAndExit();' not in jscode:
+ raise ExtractorError('`saveAndExit();` not found in `jscode`')
+ if not html:
+ html = self.extractor._download_webpage(url, video_id, note=note, headers=headers)
+ with open(self._TMP_FILES['html'].name, 'wb') as f:
+ f.write(html.encode('utf-8'))
+
+ replaces = self.options
+ replaces['url'] = url
+ user_agent = headers.get('User-Agent') or std_headers['User-Agent']
+ replaces['ua'] = user_agent.replace('"', '\\"')
+ replaces['jscode'] = jscode
+
+ for x in self._TMP_FILE_NAMES:
+ replaces[x] = self._TMP_FILES[x].name.replace('\\', '\\\\').replace('"', '\\"')
+
+ with open(self._TMP_FILES['script'].name, 'wb') as f:
+ f.write(self._TEMPLATE.format(**replaces).encode('utf-8'))
+
+ if video_id is None:
+ self.extractor.to_screen('%s' % (note2,))
+ else:
+ self.extractor.to_screen('%s: %s' % (video_id, note2))
+
+ p = subprocess.Popen([self.exe, '--ssl-protocol=any',
+ self._TMP_FILES['script'].name], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, err = p.communicate()
+ if p.returncode != 0:
+ raise ExtractorError('Executing JS failed\n:'
+ + encodeArgument(err))
+ with open(self._TMP_FILES['html'].name, 'rb') as f:
+ html = f.read().decode('utf-8')
+ return (html, encodeArgument(out))
+