Compare commits
76 Commits
2013.03.29
...
2013.04.22
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cb94542f4 | ||
|
|
c681a03918 | ||
|
|
74e3452b9e | ||
|
|
9e1cf0c200 | ||
|
|
e11eb11906 | ||
|
|
c04bca6f60 | ||
|
|
41a6eb949a | ||
|
|
f17ce13a92 | ||
|
|
8c416ad29a | ||
|
|
c72938240e | ||
|
|
e905b6f80e | ||
|
|
6de8f1afb7 | ||
|
|
9341212642 | ||
|
|
f7a9721e16 | ||
|
|
089e843b0f | ||
|
|
c8056d866a | ||
|
|
49da66e459 | ||
|
|
fb6c319904 | ||
|
|
5a8d13199c | ||
|
|
dce9027045 | ||
|
|
feba604e92 | ||
|
|
d22f65413a | ||
|
|
0599ef8c08 | ||
|
|
bfdf469295 | ||
|
|
32c96387c1 | ||
|
|
c8c5443bb5 | ||
|
|
a60b854d90 | ||
|
|
d281274bf2 | ||
|
|
b625bc2c31 | ||
|
|
f4381ab88a | ||
|
|
744435f2a4 | ||
|
|
855703e55e | ||
|
|
927c8c4924 | ||
|
|
0ba994e9e3 | ||
|
|
af9ad45cd4 | ||
|
|
e0fee250c3 | ||
|
|
72ca05016d | ||
|
|
844d1f9fa1 | ||
|
|
213c31ae16 | ||
|
|
04f3d551a0 | ||
|
|
e8600d69fd | ||
|
|
b03d65c237 | ||
|
|
8743974189 | ||
|
|
dc36bc9434 | ||
|
|
bce878a7c1 | ||
|
|
532d797824 | ||
|
|
146c12a2da | ||
|
|
d39919c03e | ||
|
|
df2dedeefb | ||
|
|
adb029ed81 | ||
|
|
43ff1a347d | ||
|
|
14294236bf | ||
|
|
c2b293ba30 | ||
|
|
37cd9f522f | ||
|
|
f33154cd39 | ||
|
|
bafeed9f5d | ||
|
|
ef767f9fd5 | ||
|
|
bc97f6d60c | ||
|
|
90a99c1b5e | ||
|
|
f375d4b7de | ||
|
|
fa41fbd318 | ||
|
|
6a205c8876 | ||
|
|
0fb3756409 | ||
|
|
fbbdf475b1 | ||
|
|
c238be3e3a | ||
|
|
7eab8dc750 | ||
|
|
d2c690828a | ||
|
|
cfa90f4adc | ||
|
|
a0d6fe7b92 | ||
|
|
8a38a194fb | ||
|
|
6ac7f082c4 | ||
|
|
f6e6da9525 | ||
|
|
597cc8a455 | ||
|
|
3370abd509 | ||
|
|
631f73978c | ||
|
|
df8db1aa21 |
@@ -8,6 +8,7 @@ notifications:
|
||||
email:
|
||||
- filippo.valsorda@gmail.com
|
||||
- phihag@phihag.de
|
||||
- jaime.marquinez.ferrandiz+travis@gmail.com
|
||||
# irc:
|
||||
# channels:
|
||||
# - "irc.freenode.org#youtube-dl"
|
||||
|
||||
212
README.md
212
README.md
@@ -14,119 +14,127 @@ your Unix box, on Windows or on Mac OS X. It is released to the public domain,
|
||||
which means you can modify it, redistribute it or use it however you like.
|
||||
|
||||
# OPTIONS
|
||||
-h, --help print this help text and exit
|
||||
--version print program version and exit
|
||||
-U, --update update this program to latest version
|
||||
-i, --ignore-errors continue on download errors
|
||||
-r, --rate-limit LIMIT maximum download rate (e.g. 50k or 44.6m)
|
||||
-R, --retries RETRIES number of retries (default is 10)
|
||||
--buffer-size SIZE size of download buffer (e.g. 1024 or 16k) (default
|
||||
is 1024)
|
||||
--no-resize-buffer do not automatically adjust the buffer size. By
|
||||
default, the buffer size is automatically resized
|
||||
from an initial value of SIZE.
|
||||
--dump-user-agent display the current browser identification
|
||||
--user-agent UA specify a custom user agent
|
||||
--list-extractors List all supported extractors and the URLs they
|
||||
would handle
|
||||
-h, --help print this help text and exit
|
||||
--version print program version and exit
|
||||
-U, --update update this program to latest version
|
||||
-i, --ignore-errors continue on download errors
|
||||
-r, --rate-limit LIMIT maximum download rate (e.g. 50k or 44.6m)
|
||||
-R, --retries RETRIES number of retries (default is 10)
|
||||
--buffer-size SIZE size of download buffer (e.g. 1024 or 16k)
|
||||
(default is 1024)
|
||||
--no-resize-buffer do not automatically adjust the buffer size. By
|
||||
default, the buffer size is automatically resized
|
||||
from an initial value of SIZE.
|
||||
--dump-user-agent display the current browser identification
|
||||
--user-agent UA specify a custom user agent
|
||||
--list-extractors List all supported extractors and the URLs they
|
||||
would handle
|
||||
|
||||
## Video Selection:
|
||||
--playlist-start NUMBER playlist video to start at (default is 1)
|
||||
--playlist-end NUMBER playlist video to end at (default is last)
|
||||
--match-title REGEX download only matching titles (regex or caseless
|
||||
sub-string)
|
||||
--reject-title REGEX skip download for matching titles (regex or
|
||||
caseless sub-string)
|
||||
--max-downloads NUMBER Abort after downloading NUMBER files
|
||||
--min-filesize SIZE Do not download any videos smaller than SIZE (e.g.
|
||||
50k or 44.6m)
|
||||
--max-filesize SIZE Do not download any videos larger than SIZE (e.g.
|
||||
50k or 44.6m)
|
||||
--playlist-start NUMBER playlist video to start at (default is 1)
|
||||
--playlist-end NUMBER playlist video to end at (default is last)
|
||||
--match-title REGEX download only matching titles (regex or caseless
|
||||
sub-string)
|
||||
--reject-title REGEX skip download for matching titles (regex or
|
||||
caseless sub-string)
|
||||
--max-downloads NUMBER Abort after downloading NUMBER files
|
||||
--min-filesize SIZE Do not download any videos smaller than SIZE
|
||||
(e.g. 50k or 44.6m)
|
||||
--max-filesize SIZE Do not download any videos larger than SIZE (e.g.
|
||||
50k or 44.6m)
|
||||
|
||||
## Filesystem Options:
|
||||
-t, --title use title in file name
|
||||
--id use video ID in file name
|
||||
-l, --literal [deprecated] alias of --title
|
||||
-A, --auto-number number downloaded files starting from 00000
|
||||
-o, --output TEMPLATE output filename template. Use %(title)s to get the
|
||||
title, %(uploader)s for the uploader name,
|
||||
%(uploader_id)s for the uploader nickname if
|
||||
different, %(autonumber)s to get an automatically
|
||||
incremented number, %(ext)s for the filename
|
||||
extension, %(upload_date)s for the upload date
|
||||
(YYYYMMDD), %(extractor)s for the provider
|
||||
(youtube, metacafe, etc), %(id)s for the video id
|
||||
and %% for a literal percent. Use - to output to
|
||||
stdout. Can also be used to download to a different
|
||||
directory, for example with -o '/my/downloads/%(upl
|
||||
oader)s/%(title)s-%(id)s.%(ext)s' .
|
||||
--restrict-filenames Restrict filenames to only ASCII characters, and
|
||||
avoid "&" and spaces in filenames
|
||||
-a, --batch-file FILE file containing URLs to download ('-' for stdin)
|
||||
-w, --no-overwrites do not overwrite files
|
||||
-c, --continue resume partially downloaded files
|
||||
--no-continue do not resume partially downloaded files (restart
|
||||
from beginning)
|
||||
--cookies FILE file to read cookies from and dump cookie jar in
|
||||
--no-part do not use .part files
|
||||
--no-mtime do not use the Last-modified header to set the file
|
||||
modification time
|
||||
--write-description write video description to a .description file
|
||||
--write-info-json write video metadata to a .info.json file
|
||||
-t, --title use title in file name
|
||||
--id use video ID in file name
|
||||
-l, --literal [deprecated] alias of --title
|
||||
-A, --auto-number number downloaded files starting from 00000
|
||||
-o, --output TEMPLATE output filename template. Use %(title)s to get
|
||||
the title, %(uploader)s for the uploader name,
|
||||
%(uploader_id)s for the uploader nickname if
|
||||
different, %(autonumber)s to get an automatically
|
||||
incremented number, %(ext)s for the filename
|
||||
extension, %(upload_date)s for the upload date
|
||||
(YYYYMMDD), %(extractor)s for the provider
|
||||
(youtube, metacafe, etc), %(id)s for the video id
|
||||
, %(playlist)s for the playlist the video is in,
|
||||
%(playlist_index)s for the position in the
|
||||
playlist and %% for a literal percent. Use - to
|
||||
output to stdout. Can also be used to download to
|
||||
a different directory, for example with -o '/my/d
|
||||
ownloads/%(uploader)s/%(title)s-%(id)s.%(ext)s' .
|
||||
--autonumber-size NUMBER Specifies the number of digits in %(autonumber)s
|
||||
when it is present in output filename template or
|
||||
--autonumber option is given
|
||||
--restrict-filenames Restrict filenames to only ASCII characters, and
|
||||
avoid "&" and spaces in filenames
|
||||
-a, --batch-file FILE file containing URLs to download ('-' for stdin)
|
||||
-w, --no-overwrites do not overwrite files
|
||||
-c, --continue resume partially downloaded files
|
||||
--no-continue do not resume partially downloaded files (restart
|
||||
from beginning)
|
||||
--cookies FILE file to read cookies from and dump cookie jar in
|
||||
--no-part do not use .part files
|
||||
--no-mtime do not use the Last-modified header to set the
|
||||
file modification time
|
||||
--write-description write video description to a .description file
|
||||
--write-info-json write video metadata to a .info.json file
|
||||
|
||||
## Verbosity / Simulation Options:
|
||||
-q, --quiet activates quiet mode
|
||||
-s, --simulate do not download the video and do not write anything
|
||||
to disk
|
||||
--skip-download do not download the video
|
||||
-g, --get-url simulate, quiet but print URL
|
||||
-e, --get-title simulate, quiet but print title
|
||||
--get-thumbnail simulate, quiet but print thumbnail URL
|
||||
--get-description simulate, quiet but print video description
|
||||
--get-filename simulate, quiet but print output filename
|
||||
--get-format simulate, quiet but print output format
|
||||
--newline output progress bar as new lines
|
||||
--no-progress do not print progress bar
|
||||
--console-title display progress in console titlebar
|
||||
-v, --verbose print various debugging information
|
||||
-q, --quiet activates quiet mode
|
||||
-s, --simulate do not download the video and do not write
|
||||
anything to disk
|
||||
--skip-download do not download the video
|
||||
-g, --get-url simulate, quiet but print URL
|
||||
-e, --get-title simulate, quiet but print title
|
||||
--get-thumbnail simulate, quiet but print thumbnail URL
|
||||
--get-description simulate, quiet but print video description
|
||||
--get-filename simulate, quiet but print output filename
|
||||
--get-format simulate, quiet but print output format
|
||||
--newline output progress bar as new lines
|
||||
--no-progress do not print progress bar
|
||||
--console-title display progress in console titlebar
|
||||
-v, --verbose print various debugging information
|
||||
--dump-intermediate-pages print downloaded pages to debug problems(very
|
||||
verbose)
|
||||
|
||||
## Video Format Options:
|
||||
-f, --format FORMAT video format code
|
||||
--all-formats download all available video formats
|
||||
--prefer-free-formats prefer free video formats unless a specific one is
|
||||
requested
|
||||
--max-quality FORMAT highest quality format to download
|
||||
-F, --list-formats list all available formats (currently youtube only)
|
||||
--write-sub write subtitle file (currently youtube only)
|
||||
--only-sub downloads only the subtitles (no video)
|
||||
--all-subs downloads all the available subtitles of the video
|
||||
(currently youtube only)
|
||||
--list-subs lists all available subtitles for the video
|
||||
(currently youtube only)
|
||||
--sub-format LANG subtitle format [srt/sbv] (default=srt) (currently
|
||||
youtube only)
|
||||
--sub-lang LANG language of the subtitles to download (optional)
|
||||
use IETF language tags like 'en'
|
||||
-f, --format FORMAT video format code
|
||||
--all-formats download all available video formats
|
||||
--prefer-free-formats prefer free video formats unless a specific one
|
||||
is requested
|
||||
--max-quality FORMAT highest quality format to download
|
||||
-F, --list-formats list all available formats (currently youtube
|
||||
only)
|
||||
--write-sub write subtitle file (currently youtube only)
|
||||
--only-sub downloads only the subtitles (no video)
|
||||
--all-subs downloads all the available subtitles of the
|
||||
video (currently youtube only)
|
||||
--list-subs lists all available subtitles for the video
|
||||
(currently youtube only)
|
||||
--sub-format LANG subtitle format [srt/sbv] (default=srt)
|
||||
(currently youtube only)
|
||||
--sub-lang LANG language of the subtitles to download (optional)
|
||||
use IETF language tags like 'en'
|
||||
|
||||
## Authentication Options:
|
||||
-u, --username USERNAME account username
|
||||
-p, --password PASSWORD account password
|
||||
-n, --netrc use .netrc authentication data
|
||||
-u, --username USERNAME account username
|
||||
-p, --password PASSWORD account password
|
||||
-n, --netrc use .netrc authentication data
|
||||
|
||||
## Post-processing Options:
|
||||
-x, --extract-audio convert video files to audio-only files (requires
|
||||
ffmpeg or avconv and ffprobe or avprobe)
|
||||
--audio-format FORMAT "best", "aac", "vorbis", "mp3", "m4a", "opus", or
|
||||
"wav"; best by default
|
||||
--audio-quality QUALITY ffmpeg/avconv audio quality specification, insert a
|
||||
value between 0 (better) and 9 (worse) for VBR or a
|
||||
specific bitrate like 128K (default 5)
|
||||
--recode-video FORMAT Encode the video to another format if necessary
|
||||
(currently supported: mp4|flv|ogg|webm)
|
||||
-k, --keep-video keeps the video file on disk after the post-
|
||||
processing; the video is erased by default
|
||||
--no-post-overwrites do not overwrite post-processed files; the post-
|
||||
processed files are overwritten by default
|
||||
-x, --extract-audio convert video files to audio-only files (requires
|
||||
ffmpeg or avconv and ffprobe or avprobe)
|
||||
--audio-format FORMAT "best", "aac", "vorbis", "mp3", "m4a", "opus", or
|
||||
"wav"; best by default
|
||||
--audio-quality QUALITY ffmpeg/avconv audio quality specification, insert
|
||||
a value between 0 (better) and 9 (worse) for VBR
|
||||
or a specific bitrate like 128K (default 5)
|
||||
--recode-video FORMAT Encode the video to another format if necessary
|
||||
(currently supported: mp4|flv|ogg|webm)
|
||||
-k, --keep-video keeps the video file on disk after the post-
|
||||
processing; the video is erased by default
|
||||
--no-post-overwrites do not overwrite post-processed files; the post-
|
||||
processed files are overwritten by default
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
@@ -144,6 +152,8 @@ The `-o` option allows users to indicate a template for the output file names. T
|
||||
- `ext`: The sequence will be replaced by the appropriate extension (like flv or mp4).
|
||||
- `epoch`: The sequence will be replaced by the Unix epoch when creating the file.
|
||||
- `autonumber`: The sequence will be replaced by a five-digit number that will be increased with each download, starting at zero.
|
||||
- `playlist`: The name or the id of the playlist that contains the video.
|
||||
- `playlist_index`: The index of the video in the playlist, a five-digit number.
|
||||
|
||||
The current default template is `%(id)s.%(ext)s`, but that will be switchted to `%(title)s-%(id)s.%(ext)s` (which can be requested with `-t` at the moment).
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import json
|
||||
|
||||
atom_template=textwrap.dedent("""\
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<atom:subtitle>Updates feed.</atom:subtitle>
|
||||
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<atom:title>youtube-dl releases</atom:title>
|
||||
<atom:id>youtube-dl-updates-feed</atom:id>
|
||||
<atom:updated>@TIMESTAMP@</atom:updated>
|
||||
@ENTRIES@
|
||||
@@ -19,7 +19,7 @@ entry_template=textwrap.dedent("""
|
||||
<atom:entry>
|
||||
<atom:id>youtube-dl-@VERSION@</atom:id>
|
||||
<atom:title>New version @VERSION@</atom:title>
|
||||
<atom:link href="http://rg3.github.com/youtube-dl" />
|
||||
<atom:link href="http://rg3.github.io/youtube-dl" />
|
||||
<atom:content type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
Downloads available at <a href="http://youtube-dl.org/downloads/@VERSION@/">http://youtube-dl.org/downloads/@VERSION@/</a>
|
||||
@@ -51,7 +51,7 @@ for v in versions:
|
||||
entries_str = textwrap.indent(''.join(entries), '\t')
|
||||
atom_template = atom_template.replace('@ENTRIES@', entries_str)
|
||||
|
||||
with open('update/atom.atom','w',encoding='utf-8') as atom_file:
|
||||
with open('update/releases.atom','w',encoding='utf-8') as atom_file:
|
||||
atom_file.write(atom_template)
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ raw_input()
|
||||
|
||||
filename = sys.argv[0]
|
||||
|
||||
UPDATE_URL = "http://rg3.github.com/youtube-dl/update/"
|
||||
UPDATE_URL = "http://rg3.github.io/youtube-dl/update/"
|
||||
VERSION_URL = UPDATE_URL + 'LATEST_VERSION'
|
||||
JSON_URL = UPDATE_URL + 'versions.json'
|
||||
UPDATES_RSA_KEY = (0x9d60ee4d8f805312fdb15a62f87b95bd66177b91df176765d13514a0f1754bcd2057295c5b6f1d35daa6742c3ffc9a82d3e118861c207995a8031e151d863c9927e304576bc80692bc8e094896fcf11b66f3e29e04e3a71e9a11558558acea1840aec37fc396fb6b65dc81a1c4144e03bd1c011de62e3f1357b327d08426fe93, 65537)
|
||||
|
||||
@@ -7,7 +7,7 @@ import unittest
|
||||
import os
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from youtube_dl.InfoExtractors import YoutubeIE, YoutubePlaylistIE
|
||||
from youtube_dl.InfoExtractors import YoutubeIE, YoutubePlaylistIE, YoutubeChannelIE
|
||||
|
||||
class TestAllURLsMatching(unittest.TestCase):
|
||||
def test_youtube_playlist_matching(self):
|
||||
@@ -24,6 +24,11 @@ class TestAllURLsMatching(unittest.TestCase):
|
||||
self.assertTrue(YoutubeIE.suitable(u'PLtS2H6bU1M'))
|
||||
self.assertFalse(YoutubeIE.suitable(u'https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')) #668
|
||||
|
||||
def test_youtube_channel_matching(self):
|
||||
self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM'))
|
||||
self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM?feature=gb_ch_rec'))
|
||||
self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM/videos'))
|
||||
|
||||
def test_youtube_extract(self):
|
||||
self.assertEqual(YoutubeIE()._extract_id('http://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||
self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||
|
||||
@@ -58,6 +58,7 @@ with io.open(PARAMETERS_FILE, encoding='utf-8') as pf:
|
||||
|
||||
|
||||
class TestDownload(unittest.TestCase):
|
||||
maxDiff = None
|
||||
def setUp(self):
|
||||
self.parameters = parameters
|
||||
self.defs = defs
|
||||
@@ -66,7 +67,7 @@ class TestDownload(unittest.TestCase):
|
||||
def generator(test_case):
|
||||
|
||||
def test_template(self):
|
||||
ie = getattr(youtube_dl.InfoExtractors, test_case['name'] + 'IE')
|
||||
ie = youtube_dl.InfoExtractors.get_info_extractor(test_case['name'])#getattr(youtube_dl.InfoExtractors, test_case['name'] + 'IE')
|
||||
if not ie._WORKING:
|
||||
print('Skipping: IE marked as not _WORKING')
|
||||
return
|
||||
@@ -81,9 +82,8 @@ def generator(test_case):
|
||||
params.update(test_case.get('params', {}))
|
||||
|
||||
fd = FileDownloader(params)
|
||||
fd.add_info_extractor(ie())
|
||||
for ien in test_case.get('add_ie', []):
|
||||
fd.add_info_extractor(getattr(youtube_dl.InfoExtractors, ien + 'IE')())
|
||||
for ie in youtube_dl.InfoExtractors.gen_extractors():
|
||||
fd.add_info_extractor(ie)
|
||||
finished_hook_called = set()
|
||||
def _hook(status):
|
||||
if status['status'] == 'finished':
|
||||
@@ -103,7 +103,7 @@ def generator(test_case):
|
||||
if retry == RETRIES: raise
|
||||
|
||||
# Check if the exception is not a network related one
|
||||
if not err.exc_info[0] in (ZeroDivisionError, compat_urllib_error.URLError, socket.timeout):
|
||||
if not err.exc_info[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError):
|
||||
raise
|
||||
|
||||
print('Retrying: {0} failed tries\n\n##########\n\n'.format(retry))
|
||||
|
||||
@@ -8,8 +8,9 @@ import json
|
||||
import os
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from youtube_dl.InfoExtractors import YoutubeUserIE, YoutubePlaylistIE, YoutubeIE
|
||||
from youtube_dl.InfoExtractors import YoutubeUserIE, YoutubePlaylistIE, YoutubeIE, YoutubeChannelIE
|
||||
from youtube_dl.utils import *
|
||||
from youtube_dl.FileDownloader import FileDownloader
|
||||
|
||||
PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "parameters.json")
|
||||
with io.open(PARAMETERS_FILE, encoding='utf-8') as pf:
|
||||
@@ -22,7 +23,7 @@ proxy_handler = compat_urllib_request.ProxyHandler()
|
||||
opener = compat_urllib_request.build_opener(proxy_handler, cookie_processor, YoutubeDLHandler())
|
||||
compat_urllib_request.install_opener(opener)
|
||||
|
||||
class FakeDownloader(object):
|
||||
class FakeDownloader(FileDownloader):
|
||||
def __init__(self):
|
||||
self.result = []
|
||||
self.params = parameters
|
||||
@@ -30,35 +31,44 @@ class FakeDownloader(object):
|
||||
print(s)
|
||||
def trouble(self, s):
|
||||
raise Exception(s)
|
||||
def download(self, x):
|
||||
self.result.append(x)
|
||||
def extract_info(self, url):
|
||||
self.result.append(url)
|
||||
return url
|
||||
|
||||
class TestYoutubeLists(unittest.TestCase):
|
||||
def assertIsPlaylist(self,info):
|
||||
"""Make sure the info has '_type' set to 'playlist'"""
|
||||
self.assertEqual(info['_type'], 'playlist')
|
||||
|
||||
def test_youtube_playlist(self):
|
||||
dl = FakeDownloader()
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
ie.extract('https://www.youtube.com/playlist?list=PLwiyx1dc3P2JR9N8gQaQN_BCvlSlap7re')
|
||||
ytie_results = [YoutubeIE()._extract_id(r[0]) for r in dl.result]
|
||||
result = ie.extract('https://www.youtube.com/playlist?list=PLwiyx1dc3P2JR9N8gQaQN_BCvlSlap7re')[0]
|
||||
self.assertIsPlaylist(result)
|
||||
self.assertEqual(result['title'], 'ytdl test PL')
|
||||
ytie_results = [YoutubeIE()._extract_id(url['url']) for url in result['entries']]
|
||||
self.assertEqual(ytie_results, [ 'bV9L5Ht9LgY', 'FXxLjLQi3Fg', 'tU3Bgo5qJZE'])
|
||||
|
||||
def test_issue_673(self):
|
||||
dl = FakeDownloader()
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
ie.extract('PLBB231211A4F62143')
|
||||
self.assertTrue(len(dl.result) > 40)
|
||||
result = ie.extract('PLBB231211A4F62143')[0]
|
||||
self.assertEqual(result['title'], 'Team Fortress 2')
|
||||
self.assertTrue(len(result['entries']) > 40)
|
||||
|
||||
def test_youtube_playlist_long(self):
|
||||
dl = FakeDownloader()
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
ie.extract('https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')
|
||||
self.assertTrue(len(dl.result) >= 799)
|
||||
result = ie.extract('https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')[0]
|
||||
self.assertIsPlaylist(result)
|
||||
self.assertTrue(len(result['entries']) >= 799)
|
||||
|
||||
def test_youtube_playlist_with_deleted(self):
|
||||
#651
|
||||
dl = FakeDownloader()
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
ie.extract('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')
|
||||
ytie_results = [YoutubeIE()._extract_id(r[0]) for r in dl.result]
|
||||
result = ie.extract('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')[0]
|
||||
ytie_results = [YoutubeIE()._extract_id(url['url']) for url in result['entries']]
|
||||
self.assertFalse('pElCt5oNDuI' in ytie_results)
|
||||
self.assertFalse('KdPEApIVdWM' in ytie_results)
|
||||
|
||||
@@ -66,20 +76,27 @@ class TestYoutubeLists(unittest.TestCase):
|
||||
dl = FakeDownloader()
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
# TODO find a > 100 (paginating?) videos course
|
||||
ie.extract('https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
||||
self.assertEqual(YoutubeIE()._extract_id(dl.result[0][0]), 'j9WZyLZCBzs')
|
||||
self.assertEqual(len(dl.result), 25)
|
||||
self.assertEqual(YoutubeIE()._extract_id(dl.result[-1][0]), 'rYefUsYuEp0')
|
||||
result = ie.extract('https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')[0]
|
||||
entries = result['entries']
|
||||
self.assertEqual(YoutubeIE()._extract_id(entries[0]['url']), 'j9WZyLZCBzs')
|
||||
self.assertEqual(len(entries), 25)
|
||||
self.assertEqual(YoutubeIE()._extract_id(entries[-1]['url']), 'rYefUsYuEp0')
|
||||
|
||||
def test_youtube_channel(self):
|
||||
# I give up, please find a channel that does paginate and test this like test_youtube_playlist_long
|
||||
pass # TODO
|
||||
dl = FakeDownloader()
|
||||
ie = YoutubeChannelIE(dl)
|
||||
#test paginated channel
|
||||
result = ie.extract('https://www.youtube.com/channel/UCKfVa3S1e4PHvxWcwyMMg8w')[0]
|
||||
self.assertTrue(len(result['entries']) > 90)
|
||||
#test autogenerated channel
|
||||
result = ie.extract('https://www.youtube.com/channel/HCtnHdj3df7iM/videos')[0]
|
||||
self.assertTrue(len(result['entries']) > 20)
|
||||
|
||||
def test_youtube_user(self):
|
||||
dl = FakeDownloader()
|
||||
ie = YoutubeUserIE(dl)
|
||||
ie.extract('https://www.youtube.com/user/TheLinuxFoundation')
|
||||
self.assertTrue(len(dl.result) >= 320)
|
||||
result = ie.extract('https://www.youtube.com/user/TheLinuxFoundation')[0]
|
||||
self.assertTrue(len(result['entries']) >= 320)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -80,7 +80,7 @@ class TestYoutubeSubtitles(unittest.TestCase):
|
||||
IE = YoutubeIE(DL)
|
||||
info_dict = IE.extract('QRS8MkLhQmM')
|
||||
subtitles = info_dict[0]['subtitles']
|
||||
self.assertEqual(len(subtitles), 12)
|
||||
self.assertEqual(len(subtitles), 13)
|
||||
def test_youtube_subtitles_format(self):
|
||||
DL = FakeDownloader()
|
||||
DL.params['writesubtitles'] = True
|
||||
|
||||
@@ -76,8 +76,7 @@
|
||||
"name": "StanfordOpenClassroom",
|
||||
"md5": "544a9468546059d4e80d76265b0443b8",
|
||||
"url": "http://openclassroom.stanford.edu/MainFolder/VideoPage.php?course=PracticalUnix&video=intro-environment&speed=100",
|
||||
"file": "PracticalUnix_intro-environment.mp4",
|
||||
"skip": "Currently offline"
|
||||
"file": "PracticalUnix_intro-environment.mp4"
|
||||
},
|
||||
{
|
||||
"name": "XNXX",
|
||||
@@ -328,5 +327,16 @@
|
||||
"info_dict": {
|
||||
"title": "Video: KO Of The Week: MMA Fighter Gets Knocked Out By Swift Head Kick! "
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ARD",
|
||||
"url": "http://www.ardmediathek.de/das-erste/tagesschau-in-100-sek?documentId=14077640",
|
||||
"file": "14077640.mp4",
|
||||
"md5": "6ca8824255460c787376353f9e20bbd8",
|
||||
"info_dict": {
|
||||
"title": "11.04.2013 09:23 Uhr - Tagesschau in 100 Sekunden"
|
||||
},
|
||||
"skip": "Requires rtmpdump"
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
BIN
youtube-dl
BIN
youtube-dl
Binary file not shown.
@@ -17,6 +17,7 @@ if os.name == 'nt':
|
||||
import ctypes
|
||||
|
||||
from .utils import *
|
||||
from .InfoExtractors import get_info_extractor
|
||||
|
||||
|
||||
class FileDownloader(object):
|
||||
@@ -388,7 +389,13 @@ class FileDownloader(object):
|
||||
template_dict = dict(info_dict)
|
||||
|
||||
template_dict['epoch'] = int(time.time())
|
||||
template_dict['autonumber'] = u'%05d' % self._num_downloads
|
||||
autonumber_size = self.params.get('autonumber_size')
|
||||
if autonumber_size is None:
|
||||
autonumber_size = 5
|
||||
autonumber_templ = u'%0' + str(autonumber_size) + u'd'
|
||||
template_dict['autonumber'] = autonumber_templ % self._num_downloads
|
||||
if template_dict['playlist_index'] is not None:
|
||||
template_dict['playlist_index'] = u'%05d' % template_dict['playlist_index']
|
||||
|
||||
sanitize = lambda k,v: sanitize_filename(
|
||||
u'NA' if v is None else compat_str(v),
|
||||
@@ -418,10 +425,126 @@ class FileDownloader(object):
|
||||
if re.search(rejecttitle, title, re.IGNORECASE):
|
||||
return u'"' + title + '" title matched reject pattern "' + rejecttitle + '"'
|
||||
return None
|
||||
|
||||
def extract_info(self, url, download = True, ie_name = None):
|
||||
'''
|
||||
Returns a list with a dictionary for each video we find.
|
||||
If 'download', also downloads the videos.
|
||||
'''
|
||||
suitable_found = False
|
||||
|
||||
#We copy the original list
|
||||
ies = list(self._ies)
|
||||
|
||||
if ie_name is not None:
|
||||
#We put in the first place the given info extractor
|
||||
first_ie = get_info_extractor(ie_name)()
|
||||
first_ie.set_downloader(self)
|
||||
ies.insert(0, first_ie)
|
||||
|
||||
for ie in ies:
|
||||
# Go to next InfoExtractor if not suitable
|
||||
if not ie.suitable(url):
|
||||
continue
|
||||
|
||||
# Warn if the _WORKING attribute is False
|
||||
if not ie.working():
|
||||
self.to_stderr(u'WARNING: the program functionality for this site has been marked as broken, '
|
||||
u'and will probably not work. If you want to go on, use the -i option.')
|
||||
|
||||
# Suitable InfoExtractor found
|
||||
suitable_found = True
|
||||
|
||||
# Extract information from URL and process it
|
||||
try:
|
||||
ie_results = ie.extract(url)
|
||||
if ie_results is None: # Finished already (backwards compatibility; listformats and friends should be moved here)
|
||||
break
|
||||
results = []
|
||||
for ie_result in ie_results:
|
||||
if not 'extractor' in ie_result:
|
||||
#The extractor has already been set somewhere else
|
||||
ie_result['extractor'] = ie.IE_NAME
|
||||
results.append(self.process_ie_result(ie_result, download))
|
||||
return results
|
||||
except ExtractorError as de: # An error we somewhat expected
|
||||
self.trouble(u'ERROR: ' + compat_str(de), de.format_traceback())
|
||||
break
|
||||
except Exception as e:
|
||||
if self.params.get('ignoreerrors', False):
|
||||
self.trouble(u'ERROR: ' + compat_str(e), tb=compat_str(traceback.format_exc()))
|
||||
break
|
||||
else:
|
||||
raise
|
||||
if not suitable_found:
|
||||
self.trouble(u'ERROR: no suitable InfoExtractor: %s' % url)
|
||||
|
||||
def process_ie_result(self, ie_result, download = True):
|
||||
"""
|
||||
Take the result of the ie and return a list of videos.
|
||||
For url elements it will search the suitable ie and get the videos
|
||||
For playlist elements it will process each of the elements of the 'entries' key
|
||||
|
||||
It will also download the videos if 'download'.
|
||||
"""
|
||||
result_type = ie_result.get('_type', 'video') #If not given we suppose it's a video, support the dafault old system
|
||||
if result_type == 'video':
|
||||
if 'playlist' not in ie_result:
|
||||
#It isn't part of a playlist
|
||||
ie_result['playlist'] = None
|
||||
ie_result['playlist_index'] = None
|
||||
if download:
|
||||
#Do the download:
|
||||
self.process_info(ie_result)
|
||||
return ie_result
|
||||
elif result_type == 'url':
|
||||
#We get the video pointed by the url
|
||||
result = self.extract_info(ie_result['url'], download, ie_name = ie_result['ie_key'])[0]
|
||||
return result
|
||||
elif result_type == 'playlist':
|
||||
#We process each entry in the playlist
|
||||
playlist = ie_result.get('title', None) or ie_result.get('id', None)
|
||||
self.to_screen(u'[download] Downloading playlist: %s' % playlist)
|
||||
|
||||
playlist_results = []
|
||||
|
||||
n_all_entries = len(ie_result['entries'])
|
||||
playliststart = self.params.get('playliststart', 1) - 1
|
||||
playlistend = self.params.get('playlistend', -1)
|
||||
|
||||
if playlistend == -1:
|
||||
entries = ie_result['entries'][playliststart:]
|
||||
else:
|
||||
entries = ie_result['entries'][playliststart:playlistend]
|
||||
|
||||
n_entries = len(entries)
|
||||
|
||||
self.to_screen(u"[%s] playlist '%s': Collected %d video ids (downloading %d of them)" %
|
||||
(ie_result['extractor'], playlist, n_all_entries, n_entries))
|
||||
|
||||
for i,entry in enumerate(entries,1):
|
||||
self.to_screen(u'[download] Downloading video #%s of %s' %(i, n_entries))
|
||||
entry_result = self.process_ie_result(entry, False)
|
||||
entry_result['playlist'] = playlist
|
||||
entry_result['playlist_index'] = i + playliststart
|
||||
#We must do the download here to correctly set the 'playlist' key
|
||||
if download:
|
||||
self.process_info(entry_result)
|
||||
playlist_results.append(entry_result)
|
||||
result = ie_result.copy()
|
||||
result['entries'] = playlist_results
|
||||
return result
|
||||
|
||||
def process_info(self, info_dict):
|
||||
"""Process a single dictionary returned by an InfoExtractor."""
|
||||
|
||||
#We increment the download the download count here to match the previous behaviour.
|
||||
self.increment_downloads()
|
||||
|
||||
info_dict['fulltitle'] = info_dict['title']
|
||||
if len(info_dict['title']) > 200:
|
||||
info_dict['title'] = info_dict['title'][:197] + u'...'
|
||||
|
||||
# Keep for backwards compatibility
|
||||
info_dict['stitle'] = info_dict['title']
|
||||
|
||||
@@ -485,14 +608,17 @@ class FileDownloader(object):
|
||||
subtitle = info_dict['subtitles'][0]
|
||||
(sub_error, sub_lang, sub) = subtitle
|
||||
sub_format = self.params.get('subtitlesformat')
|
||||
try:
|
||||
sub_filename = filename.rsplit('.', 1)[0] + u'.' + sub_lang + u'.' + sub_format
|
||||
self.report_writesubtitles(sub_filename)
|
||||
with io.open(encodeFilename(sub_filename), 'w', encoding='utf-8') as subfile:
|
||||
subfile.write(sub)
|
||||
except (OSError, IOError):
|
||||
self.report_error(u'Cannot write subtitles file ' + descfn)
|
||||
return
|
||||
if sub_error:
|
||||
self.report_warning("Some error while getting the subtitles")
|
||||
else:
|
||||
try:
|
||||
sub_filename = filename.rsplit('.', 1)[0] + u'.' + sub_lang + u'.' + sub_format
|
||||
self.report_writesubtitles(sub_filename)
|
||||
with io.open(encodeFilename(sub_filename), 'w', encoding='utf-8') as subfile:
|
||||
subfile.write(sub)
|
||||
except (OSError, IOError):
|
||||
self.report_error(u'Cannot write subtitles file ' + descfn)
|
||||
return
|
||||
if self.params.get('onlysubtitles', False):
|
||||
return
|
||||
|
||||
@@ -501,14 +627,17 @@ class FileDownloader(object):
|
||||
sub_format = self.params.get('subtitlesformat')
|
||||
for subtitle in subtitles:
|
||||
(sub_error, sub_lang, sub) = subtitle
|
||||
try:
|
||||
sub_filename = filename.rsplit('.', 1)[0] + u'.' + sub_lang + u'.' + sub_format
|
||||
self.report_writesubtitles(sub_filename)
|
||||
with io.open(encodeFilename(sub_filename), 'w', encoding='utf-8') as subfile:
|
||||
subfile.write(sub)
|
||||
except (OSError, IOError):
|
||||
self.trouble(u'ERROR: Cannot write subtitles file ' + descfn)
|
||||
return
|
||||
if sub_error:
|
||||
self.report_warning("Some error while getting the subtitles")
|
||||
else:
|
||||
try:
|
||||
sub_filename = filename.rsplit('.', 1)[0] + u'.' + sub_lang + u'.' + sub_format
|
||||
self.report_writesubtitles(sub_filename)
|
||||
with io.open(encodeFilename(sub_filename), 'w', encoding='utf-8') as subfile:
|
||||
subfile.write(sub)
|
||||
except (OSError, IOError):
|
||||
self.trouble(u'ERROR: Cannot write subtitles file ' + descfn)
|
||||
return
|
||||
if self.params.get('onlysubtitles', False):
|
||||
return
|
||||
|
||||
@@ -550,53 +679,14 @@ class FileDownloader(object):
|
||||
raise SameFileError(self.params['outtmpl'])
|
||||
|
||||
for url in url_list:
|
||||
suitable_found = False
|
||||
for ie in self._ies:
|
||||
# Go to next InfoExtractor if not suitable
|
||||
if not ie.suitable(url):
|
||||
continue
|
||||
|
||||
# Warn if the _WORKING attribute is False
|
||||
if not ie.working():
|
||||
self.report_warning(u'the program functionality for this site has been marked as broken, '
|
||||
u'and will probably not work. If you want to go on, use the -i option.')
|
||||
|
||||
# Suitable InfoExtractor found
|
||||
suitable_found = True
|
||||
|
||||
# Extract information from URL and process it
|
||||
try:
|
||||
videos = ie.extract(url)
|
||||
except ExtractorError as de: # An error we somewhat expected
|
||||
self.trouble(u'ERROR: ' + compat_str(de), de.format_traceback())
|
||||
break
|
||||
except MaxDownloadsReached:
|
||||
self.to_screen(u'[info] Maximum number of downloaded files reached.')
|
||||
raise
|
||||
except Exception as e:
|
||||
if self.params.get('ignoreerrors', False):
|
||||
self.report_error(u'' + compat_str(e), tb=compat_str(traceback.format_exc()))
|
||||
break
|
||||
else:
|
||||
raise
|
||||
|
||||
if len(videos or []) > 1 and self.fixed_template():
|
||||
raise SameFileError(self.params['outtmpl'])
|
||||
|
||||
for video in videos or []:
|
||||
video['extractor'] = ie.IE_NAME
|
||||
try:
|
||||
self.increment_downloads()
|
||||
self.process_info(video)
|
||||
except UnavailableVideoError:
|
||||
self.to_stderr(u"\n")
|
||||
self.report_error(u'unable to download video')
|
||||
|
||||
# Suitable InfoExtractor had been found; go to next URL
|
||||
break
|
||||
|
||||
if not suitable_found:
|
||||
self.report_error(u'no suitable InfoExtractor: %s' % url)
|
||||
try:
|
||||
#It also downloads the videos
|
||||
videos = self.extract_info(url)
|
||||
except UnavailableVideoError:
|
||||
self.trouble(u'\nERROR: unable to download video')
|
||||
except MaxDownloadsReached:
|
||||
self.to_screen(u'[info] Maximum number of downloaded files reached.')
|
||||
raise
|
||||
|
||||
return self._download_retcode
|
||||
|
||||
@@ -623,7 +713,7 @@ class FileDownloader(object):
|
||||
except (IOError, OSError):
|
||||
self.report_warning(u'Unable to remove downloaded video file')
|
||||
|
||||
def _download_with_rtmpdump(self, filename, url, player_url, page_url):
|
||||
def _download_with_rtmpdump(self, filename, url, player_url, page_url, play_path):
|
||||
self.report_destination(filename)
|
||||
tmpfilename = self.temp_name(filename)
|
||||
|
||||
@@ -642,6 +732,8 @@ class FileDownloader(object):
|
||||
basic_args += ['-W', player_url]
|
||||
if page_url is not None:
|
||||
basic_args += ['--pageUrl', page_url]
|
||||
if play_path is not None:
|
||||
basic_args += ['-y', play_path]
|
||||
args = basic_args + [[], ['-e', '-k', '1']][self.params.get('continuedl', False)]
|
||||
if self.params.get('verbose', False):
|
||||
try:
|
||||
@@ -696,7 +788,8 @@ class FileDownloader(object):
|
||||
if url.startswith('rtmp'):
|
||||
return self._download_with_rtmpdump(filename, url,
|
||||
info_dict.get('player_url', None),
|
||||
info_dict.get('page_url', None))
|
||||
info_dict.get('page_url', None),
|
||||
info_dict.get('play_path', None))
|
||||
|
||||
tmpfilename = self.temp_name(filename)
|
||||
stream = None
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@ __authors__ = (
|
||||
'Jaime Marquínez Ferrándiz',
|
||||
'Jeff Crouse',
|
||||
'Osama Khalid',
|
||||
'Michael Walter',
|
||||
)
|
||||
|
||||
__license__ = 'Public Domain'
|
||||
@@ -223,6 +224,9 @@ def parseOpts():
|
||||
help='display progress in console titlebar', default=False)
|
||||
verbosity.add_option('-v', '--verbose',
|
||||
action='store_true', dest='verbose', help='print various debugging information', default=False)
|
||||
verbosity.add_option('--dump-intermediate-pages',
|
||||
action='store_true', dest='dump_intermediate_pages', default=False,
|
||||
help='print downloaded pages to debug problems(very verbose)')
|
||||
|
||||
filesystem.add_option('-t', '--title',
|
||||
action='store_true', dest='usetitle', help='use title in file name', default=False)
|
||||
@@ -234,7 +238,19 @@ def parseOpts():
|
||||
action='store_true', dest='autonumber',
|
||||
help='number downloaded files starting from 00000', default=False)
|
||||
filesystem.add_option('-o', '--output',
|
||||
dest='outtmpl', metavar='TEMPLATE', help='output filename template. Use %(title)s to get the title, %(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, %(autonumber)s to get an automatically incremented number, %(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), %(extractor)s for the provider (youtube, metacafe, etc), %(id)s for the video id and %% for a literal percent. Use - to output to stdout. Can also be used to download to a different directory, for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .')
|
||||
dest='outtmpl', metavar='TEMPLATE',
|
||||
help=('output filename template. Use %(title)s to get the title, '
|
||||
'%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
|
||||
'%(autonumber)s to get an automatically incremented number, '
|
||||
'%(ext)s for the filename extension, %(upload_date)s for the upload date (YYYYMMDD), '
|
||||
'%(extractor)s for the provider (youtube, metacafe, etc), '
|
||||
'%(id)s for the video id , %(playlist)s for the playlist the video is in, '
|
||||
'%(playlist_index)s for the position in the playlist and %% for a literal percent. '
|
||||
'Use - to output to stdout. Can also be used to download to a different directory, '
|
||||
'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
|
||||
filesystem.add_option('--autonumber-size',
|
||||
dest='autonumber_size', metavar='NUMBER',
|
||||
help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --autonumber option is given')
|
||||
filesystem.add_option('--restrict-filenames',
|
||||
action='store_true', dest='restrictfilenames',
|
||||
help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
|
||||
@@ -451,6 +467,7 @@ def _real_main():
|
||||
'format_limit': opts.format_limit,
|
||||
'listformats': opts.listformats,
|
||||
'outtmpl': outtmpl,
|
||||
'autonumber_size': opts.autonumber_size,
|
||||
'restrictfilenames': opts.restrictfilenames,
|
||||
'ignoreerrors': opts.ignoreerrors,
|
||||
'ratelimit': opts.ratelimit,
|
||||
@@ -480,6 +497,7 @@ def _real_main():
|
||||
'max_downloads': opts.max_downloads,
|
||||
'prefer_free_formats': opts.prefer_free_formats,
|
||||
'verbose': opts.verbose,
|
||||
'dump_intermediate_pages': opts.dump_intermediate_pages,
|
||||
'test': opts.test,
|
||||
'keepvideo': opts.keepvideo,
|
||||
'min_filesize': opts.min_filesize,
|
||||
|
||||
@@ -9,7 +9,8 @@ import sys
|
||||
if __package__ is None and not hasattr(sys, "frozen"):
|
||||
# direct call of __main__.py
|
||||
import os.path
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
path = os.path.realpath(os.path.abspath(__file__))
|
||||
sys.path.append(os.path.dirname(os.path.dirname(path)))
|
||||
|
||||
import youtube_dl
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ def rsa_verify(message, signature, key):
|
||||
def update_self(to_screen, verbose, filename):
|
||||
"""Update the program file with the latest version from the repository"""
|
||||
|
||||
UPDATE_URL = "http://rg3.github.com/youtube-dl/update/"
|
||||
UPDATE_URL = "http://rg3.github.io/youtube-dl/update/"
|
||||
VERSION_URL = UPDATE_URL + 'LATEST_VERSION'
|
||||
JSON_URL = UPDATE_URL + 'versions.json'
|
||||
UPDATES_RSA_KEY = (0x9d60ee4d8f805312fdb15a62f87b95bd66177b91df176765d13514a0f1754bcd2057295c5b6f1d35daa6742c3ffc9a82d3e118861c207995a8031e151d863c9927e304576bc80692bc8e094896fcf11b66f3e29e04e3a71e9a11558558acea1840aec37fc396fb6b65dc81a1c4144e03bd1c011de62e3f1357b327d08426fe93, 65537)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
|
||||
__version__ = '2013.03.29'
|
||||
__version__ = '2013.04.22'
|
||||
|
||||
Reference in New Issue
Block a user