Merge remote-tracking branch 'upstream/master' into upstream

This commit is contained in:
gongqijian 2013-03-26 21:00:06 +08:00
commit 81a06ca282
8 changed files with 170 additions and 80 deletions

View File

@ -1,6 +1,16 @@
Changelog Changelog
========= =========
0.3.6
-----
*Date: 2013-03-22*
* Add support for:
- Vine
* Fix issue for:
- YouTube
0.3.5 0.3.5
----- -----

View File

@ -19,6 +19,7 @@ Fork me on GitHub: <https://github.com/soimort/you-get>
* Facebook <http://facebook.com> * Facebook <http://facebook.com>
* Google+ <http://plus.google.com> * Google+ <http://plus.google.com>
* Tumblr <http://www.tumblr.com> * Tumblr <http://www.tumblr.com>
* Vine <http://vine.co>
* SoundCloud <http://soundcloud.com> * SoundCloud <http://soundcloud.com>
* Mixcloud <http://www.mixcloud.com> * Mixcloud <http://www.mixcloud.com>
* JPopsuki <http://jpopsuki.tv> * JPopsuki <http://jpopsuki.tv>
@ -107,7 +108,13 @@ Fork me on GitHub: <https://github.com/soimort/you-get>
Click [here](https://aur.archlinux.org/packages.php\?ID=62576). Click [here](https://aur.archlinux.org/packages.php\?ID=62576).
### FAQ (For Windows Users) ### Upgrading:
Using Pip:
$ pip install --upgrade you-get
### FAQ (For Windows Users):
* Q: I don't know how to install it on Windows. * Q: I don't know how to install it on Windows.
@ -117,26 +124,6 @@ Fork me on GitHub: <https://github.com/soimort/you-get>
* A: Run `set PYTHONIOENCODING=utf-8`. * A: Run `set PYTHONIOENCODING=utf-8`.
## Upgrading
Using Pip:
$ pip install --upgrade you-get
### Error When Upgrading from Pip
If you see this error:
```
File "/usr/lib/python3.3/site-packages/pip-1.2.1-py3.3.egg/pip/backwardcompat.py", line 44, in u
return s.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 68: invalid start byte
```
This is an existing bug in Pip 1.2.1. However, this does not affect your upgrading.
In Pip 1.3+, this should be already fixed.
## Examples (For End-Users) ## Examples (For End-Users)
Display the information of the video without downloading: Display the information of the video without downloading:
@ -243,6 +230,7 @@ You-Get基于优酷下载脚本[iambus/youku-lixian](https://github.com/iambus/y
* Facebook <http://facebook.com> * Facebook <http://facebook.com>
* Google+ <http://plus.google.com> * Google+ <http://plus.google.com>
* Tumblr <http://www.tumblr.com> * Tumblr <http://www.tumblr.com>
* Vine <http://vine.co>
* SoundCloud <http://soundcloud.com> * SoundCloud <http://soundcloud.com>
* Mixcloud <http://www.mixcloud.com> * Mixcloud <http://www.mixcloud.com>
* JPopsuki <http://jpopsuki.tv> * JPopsuki <http://jpopsuki.tv>
@ -333,7 +321,13 @@ You-Get基于优酷下载脚本[iambus/youku-lixian](https://github.com/iambus/y
点击[这里](https://aur.archlinux.org/packages.php\?ID=62576)。 点击[这里](https://aur.archlinux.org/packages.php\?ID=62576)。
### FAQ针对Windows用户) ### 升级:
使用Pip
$ pip install --upgrade you-get
### FAQ针对Windows用户)
* Q我不知道该如何在Windows下安装。 * Q我不知道该如何在Windows下安装。
@ -343,26 +337,6 @@ You-Get基于优酷下载脚本[iambus/youku-lixian](https://github.com/iambus/y
* A执行`set PYTHONIOENCODING=utf-8`。 * A执行`set PYTHONIOENCODING=utf-8`。
## 升级
使用Pip
$ pip install --upgrade you-get
### 从Pip升级时可能的错误
若出现以下错误提示:
```
File "/usr/lib/python3.3/site-packages/pip-1.2.1-py3.3.egg/pip/backwardcompat.py", line 44, in u
return s.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 68: invalid start byte
```
这被证实是Pip 1.2.1的一个bug。不过它并不影响到正常的升级。
这在Pip 1.3+中应当已经被修复。
## 使用方法示例 ## 使用方法示例
### 如何下载视频 ### 如何下载视频

View File

@ -22,6 +22,7 @@ Supported Sites (As of Now)
* Facebook http://facebook.com * Facebook http://facebook.com
* Google+ http://plus.google.com * Google+ http://plus.google.com
* Tumblr http://www.tumblr.com * Tumblr http://www.tumblr.com
* Vine http://vine.co
* SoundCloud http://soundcloud.com * SoundCloud http://soundcloud.com
* Mixcloud http://www.mixcloud.com * Mixcloud http://www.mixcloud.com
* JPopsuki http://jpopsuki.tv * JPopsuki http://jpopsuki.tv

View File

@ -48,6 +48,7 @@ def url_to_module(url):
'tumblr': tumblr, 'tumblr': tumblr,
'vid48': vid48, 'vid48': vid48,
'vimeo': vimeo, 'vimeo': vimeo,
'vine': vine,
'xiami': xiami, 'xiami': xiami,
'yinyuetai': yinyuetai, 'yinyuetai': yinyuetai,
'youku': youku, 'youku': youku,

View File

@ -26,6 +26,7 @@ from .tudou import *
from .tumblr import * from .tumblr import *
from .vid48 import * from .vid48 import *
from .vimeo import * from .vimeo import *
from .vine import *
from .w56 import * from .w56 import *
from .xiami import * from .xiami import *
from .yinyuetai import * from .yinyuetai import *

View File

@ -0,0 +1,20 @@
#!/usr/bin/env python
__all__ = ['vine_download']
from ..common import *
def vine_download(url, output_dir = '.', merge = True, info_only = False):
html = get_html(url)
title = r1(r'<meta property="og:title" content="([^"]*)"', html)
url = r1(r'<source src="([^"]*)"', html)
type, ext, size = url_info(url)
print_info(site_info, title, type, size)
if not info_only:
download_urls([url], title, ext, size, output_dir, merge = merge)
site_info = "Vine.co"
download = vine_download
download_playlist = playlist_not_supported('vine')

View File

@ -4,13 +4,99 @@ __all__ = ['youtube_download', 'youtube_download_by_id']
from ..common import * from ..common import *
import json # YouTube media encoding options, in descending quality order.
# taken from http://en.wikipedia.org/wiki/YouTube#Quality_and_codecs, 3/22/2013.
youtube_codecs = [
{'itag': 38, 'container': 'MP4', 'video_resolution': '3072p', 'video_encoding': 'H.264', 'video_profile': 'High', 'video_bitrate': '3.5-5', 'audio_encoding': 'AAC', 'audio_bitrate': '192'},
{'itag': 46, 'container': 'WebM', 'video_resolution': '1080p', 'video_encoding': 'VP8', 'video_profile': '', 'video_bitrate': '', 'audio_encoding': 'Vorbis', 'audio_bitrate': '192'},
{'itag': 37, 'container': 'MP4', 'video_resolution': '1080p', 'video_encoding': 'H.264', 'video_profile': 'High', 'video_bitrate': '3-4.3', 'audio_encoding': 'AAC', 'audio_bitrate': '192'},
{'itag': 102, 'container': '', 'video_resolution': '', 'video_encoding': 'VP8', 'video_profile': '', 'video_bitrate': '2', 'audio_encoding': 'Vorbis', 'audio_bitrate': '192'},
{'itag': 45, 'container': 'WebM', 'video_resolution': '720p', 'video_encoding': '', 'video_profile': '', 'video_bitrate': '', 'audio_encoding': '', 'audio_bitrate': ''},
{'itag': 22, 'container': 'MP4', 'video_resolution': '720p', 'video_encoding': 'H.264', 'video_profile': 'High', 'video_bitrate': '2-2.9', 'audio_encoding': 'AAC', 'audio_bitrate': '192'},
{'itag': 84, 'container': 'MP4', 'video_resolution': '720p', 'video_encoding': 'H.264', 'video_profile': '3D', 'video_bitrate': '2-2.9', 'audio_encoding': 'AAC', 'audio_bitrate': '152'},
{'itag': 120, 'container': 'FLV', 'video_resolution': '720p', 'video_encoding': 'AVC', 'video_profile': 'Main@L3.1', 'video_bitrate': '2', 'audio_encoding': 'AAC', 'audio_bitrate': '128'},
{'itag': 85, 'container': 'MP4', 'video_resolution': '520p', 'video_encoding': 'H.264', 'video_profile': '3D', 'video_bitrate': '2-2.9', 'audio_encoding': 'AAC', 'audio_bitrate': '152'},
{'itag': 44, 'container': 'WebM', 'video_resolution': '480p', 'video_encoding': 'VP8', 'video_profile': '', 'video_bitrate': '1', 'audio_encoding': 'Vorbis', 'audio_bitrate': '128'},
{'itag': 35, 'container': 'FLV', 'video_resolution': '480p', 'video_encoding': 'H.264', 'video_profile': 'Main', 'video_bitrate': '0.8-1', 'audio_encoding': 'AAC', 'audio_bitrate': '128'},
{'itag': 101, 'container': 'WebM', 'video_resolution': '360p', 'video_encoding': 'VP8', 'video_profile': '3D', 'video_bitrate': '', 'audio_encoding': 'Vorbis', 'audio_bitrate': '192'},
{'itag': 100, 'container': 'WebM', 'video_resolution': '360p', 'video_encoding': 'VP8', 'video_profile': '3D', 'video_bitrate': '', 'audio_encoding': 'Vorbis', 'audio_bitrate': '128'},
{'itag': 43, 'container': 'WebM', 'video_resolution': '360p', 'video_encoding': 'VP8', 'video_profile': '', 'video_bitrate': '0.5', 'audio_encoding': 'Vorbis', 'audio_bitrate': '128'},
{'itag': 34, 'container': 'FLV', 'video_resolution': '360p', 'video_encoding': 'H.264', 'video_profile': 'Main', 'video_bitrate': '0.5', 'audio_encoding': 'AAC', 'audio_bitrate': '128'},
{'itag': 82, 'container': 'MP4', 'video_resolution': '360p', 'video_encoding': 'H.264', 'video_profile': '3D', 'video_bitrate': '0.5', 'audio_encoding': 'AAC', 'audio_bitrate': '96'},
{'itag': 18, 'container': 'MP4', 'video_resolution': '270p/360p', 'video_encoding': 'H.264', 'video_profile': 'Baseline', 'video_bitrate': '0.5', 'audio_encoding': 'AAC', 'audio_bitrate': '96'},
{'itag': 6, 'container': 'FLV', 'video_resolution': '270p', 'video_encoding': 'Sorenson H.263', 'video_profile': '', 'video_bitrate': '0.8', 'audio_encoding': 'MP3', 'audio_bitrate': '64'},
{'itag': 83, 'container': 'MP4', 'video_resolution': '240p', 'video_encoding': 'H.264', 'video_profile': '3D', 'video_bitrate': '0.5', 'audio_encoding': 'AAC', 'audio_bitrate': '96'},
{'itag': 13, 'container': '3GP', 'video_resolution': '', 'video_encoding': 'MPEG-4 Visual', 'video_profile': '', 'video_bitrate': '0.5', 'audio_encoding': 'AAC', 'audio_bitrate': ''},
{'itag': 5, 'container': 'FLV', 'video_resolution': '240p', 'video_encoding': 'Sorenson H.263', 'video_profile': '', 'video_bitrate': '0.25', 'audio_encoding': 'MP3', 'audio_bitrate': '64'},
{'itag': 36, 'container': '3GP', 'video_resolution': '240p', 'video_encoding': 'MPEG-4 Visual', 'video_profile': 'Simple', 'video_bitrate': '0.17', 'audio_encoding': 'AAC', 'audio_bitrate': '38'},
{'itag': 17, 'container': '3GP', 'video_resolution': '144p', 'video_encoding': 'MPEG-4 Visual', 'video_profile': 'Simple', 'video_bitrate': '0.05', 'audio_encoding': 'AAC', 'audio_bitrate': '24'},
]
def parse_video_info(raw_info):
"""Parser for YouTube's get_video_info data.
Returns a dict, where 'url_encoded_fmt_stream_map' maps to a sorted list.
"""
# Percent-encoding reserved characters, used as separators.
sepr = {
'&': '%26',
',': '%2C',
'=': '%3D',
}
# fmt_level = {'itag': level, ...}
# itag of a higher quality maps to a lower level number.
# The highest quality has level number 0.
fmt_level = dict(
zip(
[str(codec['itag'])
for codec in
youtube_codecs],
range(len(youtube_codecs))))
# {key1: value1, key2: value2, ...,
# 'url_encoded_fmt_stream_map': [{'itag': '38', ...}, ...]
# }
return dict(
[(lambda metadata:
['url_encoded_fmt_stream_map', (
lambda stream_map:
sorted(
[dict(
[subitem.split(sepr['='])
for subitem in
item.split(sepr['&'])])
for item in
stream_map.split(sepr[','])],
key =
lambda stream:
fmt_level[stream['itag']]))
(metadata[1])]
if metadata[0] == 'url_encoded_fmt_stream_map'
else metadata)
(item.split('='))
for item in
raw_info.split('&')])
def youtube_download_by_id(id, title = None, output_dir = '.', merge = True, info_only = False): def youtube_download_by_id(id, title = None, output_dir = '.', merge = True, info_only = False):
html = request.urlopen('http://www.youtube.com/watch?v=' + id).read().decode('utf-8')
raw_info = request.urlopen('http://www.youtube.com/get_video_info?video_id=%s' % id).read().decode('utf-8')
video_info = parse_video_info(raw_info)
if video_info['status'] == 'ok': # use get_video_info data
title = parse.unquote(video_info['title'].replace('+', ' '))
signature = video_info['url_encoded_fmt_stream_map'][0]['sig']
url = parse.unquote(parse.unquote(video_info['url_encoded_fmt_stream_map'][0]['url'])) + "&signature=%s" % signature
else: # parse video page when "embedding disabled by request"
import json
html = request.urlopen('http://www.youtube.com/watch?v=' + id).read().decode('utf-8')
html = unescape_html(html) html = unescape_html(html)
yt_player_config = json.loads(r1(r'yt.playerConfig = ([^\n]+);\n', html)) yt_player_config = json.loads(r1(r'ytplayer.config = ([^\n]+);', html))
title = yt_player_config['args']['title'] title = yt_player_config['args']['title']
title = unicodize(title) title = unicodize(title)
title = parse.unquote(title) title = parse.unquote(title)
@ -25,10 +111,7 @@ def youtube_download_by_id(id, title = None, output_dir = '.', merge = True, inf
'85', '85',
'44', '35', '44', '35',
'101', '100', '43', '34', '82', '18', '101', '100', '43', '34', '82', '18',
'6', '6', '83', '13', '5', '36', '17',
'83', '5', '36',
'17',
'13',
]: ]:
fmt = r1(r'([^,\"]*itag=' + itag + "[^,\"]*)", html) fmt = r1(r'([^,\"]*itag=' + itag + "[^,\"]*)", html)
if fmt: if fmt:
@ -41,7 +124,7 @@ def youtube_download_by_id(id, title = None, output_dir = '.', merge = True, inf
try: try:
url url
except NameError: except NameError:
url = r1(r'crossdomain.xml"\);yt.preload.start\("([^"]+)"\)', html) url = r1(r'ytdns.ping\("([^"]+)"[^;]*;</script>', html)
url = unicodize(url) url = unicodize(url)
url = re.sub(r'\\/', '/', url) url = re.sub(r'\\/', '/', url)
url = re.sub(r'generate_204', 'videoplayback', url) url = re.sub(r'generate_204', 'videoplayback', url)

View File

@ -2,5 +2,5 @@
__all__ = ['__version__', '__date__'] __all__ = ['__version__', '__date__']
__version__ = '0.3.5' __version__ = '0.3.6'
__date__ = '2013-03-15' __date__ = '2013-03-22'