Changeset 8258


Ignore:
Timestamp:
Nov 28, 2018, 9:49:07 AM (2 years ago)
Author:
hectorgh
Message:

updating to 2018.11.23

Location:
youtube-dl/trunk/fuentes
Files:
78 edited

Legend:

Unmodified
Added
Removed
  • youtube-dl/trunk/fuentes/ChangeLog

    r8096 r8258  
     1version 2018.11.23
     2
     3Core
     4+ [setup.py] Add more relevant classifiers
     5
     6Extractors
     7* [mixcloud] Fallback to hardcoded decryption key (#18016)
     8* [nbc:news] Fix article extraction (#16194)
     9* [foxsports] Fix extraction (#17543)
     10* [loc] Relax regular expression and improve formats extraction
     11+ [ciscolive] Add support for ciscolive.cisco.com (#17984)
     12* [nzz] Relax kaltura regex (#18228)
     13* [sixplay] Fix formats extraction
     14* [bitchute] Improve title extraction
     15* [kaltura] Limit requested MediaEntry fields
     16+ [americastestkitchen] Add support for zype embeds (#18225)
     17+ [pornhub] Add pornhub.net alias
     18* [nova:embed] Fix extraction (#18222)
     19
     20
     21version 2018.11.18
     22
     23Extractors
     24+ [wwe] Extract subtitles
     25+ [wwe] Add support for playlistst (#14781)
     26+ [wwe] Add support for wwe.com (#14781, #17450)
     27* [vk] Detect geo restriction (#17767)
     28* [openload] Use original host during extraction (#18211)
     29* [atvat] Fix extraction (#18041)
     30+ [rte] Add support for new API endpoint (#18206)
     31* [tnaflixnetwork:embed] Fix extraction (#18205)
     32* [picarto] Use API and add token support (#16518)
     33+ [zype] Add support for player.zype.com (#18143)
     34* [vivo] Fix extraction (#18139)
     35* [ruutu] Update API endpoint (#18138)
     36
     37
     38version 2018.11.07
     39
     40Extractors
     41+ [youtube] Add another JS signature function name regex (#18091, #18093,
     42  #18094)
     43* [facebook] Fix tahoe request (#17171)
     44* [cliphunter] Fix extraction (#18083)
     45+ [youtube:playlist] Add support for invidio.us (#18077)
     46* [zattoo] Arrange API hosts for derived extractors (#18035)
     47+ [youtube] Add fallback metadata extraction from videoDetails (#18052)
     48
     49
     50version 2018.11.03
     51
     52Core
     53* [extractor/common] Ensure response handle is not prematurely closed before
     54  it can be read if it matches expected_status (#17195, #17846, #17447)
     55
     56Extractors
     57* [laola1tv:embed] Set correct stream access URL scheme (#16341)
     58+ [ehftv] Add support for ehftv.com (#15408)
     59* [azmedien] Adopt to major site redesign (#17745, #17746)
     60+ [twitcasting] Add support for twitcasting.tv (#17981)
     61* [orf:tvthek] Fix extraction (#17737, #17956, #18024)
     62+ [openload] Add support for oload.fun (#18045)
     63* [njpwworld] Fix authentication (#17427)
     64+ [linkedin:learning] Add support for linkedin.com/learning (#13545)
     65* [theplatform] Improve error detection (#13222)
     66* [cnbc] Simplify extraction (#14280, #17110)
     67+ [cbnc] Add support for new URL schema (#14193)
     68* [aparat] Improve extraction and extract more metadata (#17445, #18008)
     69* [aparat] Fix extraction
     70
     71
     72version 2018.10.29
     73
     74Core
     75+ [extractor/common] Add validation for JSON-LD URLs
     76
     77Extractors
     78+ [sportbox] Add support for matchtv.ru
     79* [sportbox] Fix extraction (#17978)
     80* [screencast] Fix extraction (#14590, #14617, #17990)
     81+ [openload] Add support for oload.icu
     82+ [ivi] Add support for ivi.tv
     83* [crunchyroll] Improve extraction failsafeness (#17991)
     84* [dailymail] Fix formats extraction (#17976)
     85* [viewster] Reduce format requests
     86* [cwtv] Handle API errors (#17905)
     87+ [rutube] Use geo verification headers (#17897)
     88+ [brightcove:legacy] Add fallbacks to brightcove:new (#13912)
     89- [tv3] Remove extractor (#10461, #15339)
     90* [ted] Fix extraction for HTTP and RTMP formats (#5941, #17572, #17894)
     91+ [openload] Add support for oload.cc (#17823)
     92+ [patreon] Extract post_file URL (#17792)
     93* [patreon] Fix extraction (#14502, #10471)
     94
     95
     96version 2018.10.05
     97
     98Extractors
     99* [pluralsight] Improve authentication (#17762)
     100* [dailymotion] Fix extraction (#17699)
     101* [crunchyroll] Switch to HTTPS for RpcApi (#17749)
     102+ [philharmoniedeparis] Add support for pad.philharmoniedeparis.fr (#17705)
     103* [philharmoniedeparis] Fix extraction (#17705)
     104+ [jamendo] Add support for licensing.jamendo.com (#17724)
     105+ [openload] Add support for oload.cloud (#17710)
     106* [pluralsight] Fix subtitles extraction (#17726, #17728)
     107+ [vimeo] Add another config regular expression (#17690)
     108* [spike] Fix Paramount Network extraction (#17677)
     109* [hotstar] Fix extraction (#14694, #14931, #17637)
     110
     111
     112version 2018.09.26
     113
     114Extractors
     115* [pluralsight] Fix subtitles extraction (#17671)
     116* [mediaset] Improve embed support (#17668)
     117+ [youtube] Add support for invidio.us (#17613)
     118+ [zattoo] Add support for more zattoo platform sites
     119* [zattoo] Fix extraction (#17175, #17542)
     120
     121
     122version 2018.09.18
     123
     124Core
     125+ [extractor/common] Introduce channel meta fields
     126
     127Extractors
     128* [adobepass] Don't pollute default headers dict
     129* [udemy] Don't pollute default headers dict
     130* [twitch] Don't pollute default headers dict
     131* [youtube] Don't pollute default query dict (#17593)
     132* [crunchyroll] Prefer hardsubless formats and formats in locale language
     133* [vrv] Make format ids deterministic
     134* [vimeo] Fix ondemand playlist extraction (#14591)
     135+ [pornhub] Extract upload date (#17574)
     136+ [porntube] Extract channel meta fields
     137+ [vimeo] Extract channel meta fields
     138+ [youtube] Extract channel meta fields (#9676, #12939)
     139* [porntube] Fix extraction (#17541)
     140* [asiancrush] Fix extraction (#15630)
     141+ [twitch:clips] Extend URL regular expression (closes #17559)
     142+ [vzaar] Add support for HLS
     143* [tube8] Fix metadata extraction (#17520)
     144* [eporner] Extract JSON-LD (#17519)
     145
     146
    1147version 2018.09.10
    2148
  • youtube-dl/trunk/fuentes/README.md

    r8096 r8258  
    509509 - `upload_date` (string): Video upload date (YYYYMMDD)
    510510 - `uploader_id` (string): Nickname or id of the video uploader
     511 - `channel` (string): Full name of the channel the video is uploaded on
     512 - `channel_id` (string): Id of the channel
    511513 - `location` (string): Physical location where the video was filmed
    512514 - `duration` (numeric): Length of the video in seconds
     
    11641166### Use safe conversion functions
    11651167
    1166 Wrap all extracted numeric data into safe functions from `utils`: `int_or_none`, `float_or_none`. Use them for string to number conversions as well.
     1168Wrap all extracted numeric data into safe functions from [`youtube_dl/utils.py`](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/utils.py): `int_or_none`, `float_or_none`. Use them for string to number conversions as well.
     1169
     1170Use `url_or_none` for safe URL processing.
     1171
     1172Use `try_get` for safe metadata extraction from parsed JSON.
     1173
     1174Explore [`youtube_dl/utils.py`](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/utils.py) for more useful convenience functions.
     1175
     1176#### More examples
     1177
     1178##### Safely extract optional description from parsed JSON
     1179```python
     1180description = try_get(response, lambda x: x['result']['video'][0]['summary'], compat_str)
     1181```
     1182
     1183##### Safely extract more optional metadata
     1184```python
     1185video = try_get(response, lambda x: x['result']['video'][0], dict) or {}
     1186description = video.get('summary')
     1187duration = float_or_none(video.get('durationMs'), scale=1000)
     1188view_count = int_or_none(video.get('views'))
     1189```
    11671190
    11681191# EMBEDDING YOUTUBE-DL
  • youtube-dl/trunk/fuentes/README.txt

    r8096 r8258  
    595595-   upload_date (string): Video upload date (YYYYMMDD)
    596596-   uploader_id (string): Nickname or id of the video uploader
     597-   channel (string): Full name of the channel the video is uploaded on
     598-   channel_id (string): Id of the channel
    597599-   location (string): Physical location where the video was filmed
    598600-   duration (numeric): Length of the video in seconds
     
    15901592Use safe conversion functions
    15911593
    1592 Wrap all extracted numeric data into safe functions from utils:
    1593 int_or_none, float_or_none. Use them for string to number conversions as
    1594 well.
     1594Wrap all extracted numeric data into safe functions from
     1595youtube_dl/utils.py: int_or_none, float_or_none. Use them for string to
     1596number conversions as well.
     1597
     1598Use url_or_none for safe URL processing.
     1599
     1600Use try_get for safe metadata extraction from parsed JSON.
     1601
     1602Explore youtube_dl/utils.py for more useful convenience functions.
     1603
     1604More examples
     1605
     1606Safely extract optional description from parsed JSON
     1607
     1608    description = try_get(response, lambda x: x['result']['video'][0]['summary'], compat_str)
     1609
     1610Safely extract more optional metadata
     1611
     1612    video = try_get(response, lambda x: x['result']['video'][0], dict) or {}
     1613    description = video.get('summary')
     1614    duration = float_or_none(video.get('durationMs'), scale=1000)
     1615    view_count = int_or_none(video.get('views'))
    15951616
    15961617
  • youtube-dl/trunk/fuentes/debian/changelog

    r8096 r8258  
    1 youtube-dl-dmo (2018.09.10-dmo1+lliurex4) xenial; urgency=high
     1youtube-dl-dmo (2018.11.23-dmo1+lliurex1) xenial; urgency=high
    22
    33  * Lliurex upload
    44
    5  -- Hector Garcia Huerta <hectorgh@gmail.com>  Mon, 10 Sep 2018 16:54:39 +0200
     5 -- Hector Garcia Huerta <hectorgh@gmail.com>  Wed, 28 Nov 2018 09:13:34 +0100
     6
     7youtube-dl-dmo (2018.11.23-dmo1) unstable; urgency=medium
     8
     9  * New upstream bugfix release.
     10
     11 -- Christian Marillat <marillat@deb-multimedia.org>  Fri, 23 Nov 2018 13:27:20 +0100
     12
     13youtube-dl-dmo (2018.11.18-dmo1) unstable; urgency=medium
     14
     15  * New upstream bugfix release.
     16
     17 -- Christian Marillat <marillat@deb-multimedia.org>  Sun, 18 Nov 2018 09:20:11 +0100
     18
     19youtube-dl-dmo (2018.11.07-dmo1) unstable; urgency=medium
     20
     21  * New upstream bugfix release.
     22
     23 -- Christian Marillat <marillat@deb-multimedia.org>  Wed, 07 Nov 2018 08:26:28 +0100
     24
     25youtube-dl-dmo (2018.11.03-dmo1) unstable; urgency=medium
     26
     27  * New upstream bugfix release.
     28
     29 -- Christian Marillat <marillat@deb-multimedia.org>  Sat, 03 Nov 2018 08:45:13 +0100
     30
     31youtube-dl-dmo (2018.10.29-dmo1) unstable; urgency=medium
     32
     33  * New upstream bugfix release.
     34
     35 -- Christian Marillat <marillat@deb-multimedia.org>  Mon, 29 Oct 2018 08:49:53 +0100
     36
     37youtube-dl-dmo (2018.10.05-dmo1) unstable; urgency=medium
     38
     39  * New upstream bugfix release.
     40
     41 -- Christian Marillat <marillat@deb-multimedia.org>  Fri, 05 Oct 2018 08:38:48 +0200
     42
     43youtube-dl-dmo (2018.09.26-dmo1) unstable; urgency=medium
     44
     45  * New upstream bugfix release.
     46
     47 -- Christian Marillat <marillat@deb-multimedia.org>  Wed, 26 Sep 2018 09:15:28 +0200
     48
     49youtube-dl-dmo (2018.09.18-dmo2) unstable; urgency=medium
     50
     51  * New upstream bugfix release.
     52
     53 -- Christian Marillat <marillat@deb-multimedia.org>  Wed, 26 Sep 2018 09:13:01 +0200
     54
     55youtube-dl-dmo (2018.09.18-dmo1) unstable; urgency=medium
     56
     57  * New upstream bugfix release.
     58
     59 -- Christian Marillat <marillat@deb-multimedia.org>  Tue, 18 Sep 2018 08:37:33 +0200
    660
    761youtube-dl-dmo (2018.09.10-dmo1) unstable; urgency=medium
  • youtube-dl/trunk/fuentes/debian/compat

    r8096 r8258  
    1 9
     111
  • youtube-dl/trunk/fuentes/debian/control

    r8096 r8258  
    55Bugs: mailto:marillat@deb-multimedia.org
    66Homepage: https://rg3.github.com/youtube-dl/
     7Rules-Requires-Root: no
    78Standards-Version: 4.2.1
    89Build-Depends-Indep: python3
    9 Build-Depends: debhelper, bash-completion, dh-exec, dh-python, pandoc,
     10Build-Depends: debhelper (>= 11), bash-completion, dh-exec, dh-python, pandoc,
    1011 python3-pkg-resources, zip, quilt, python3-setuptools
    1112
  • youtube-dl/trunk/fuentes/docs/supportedsites.md

    r8096 r8258  
    8585 - **awaan:video**
    8686 - **AZMedien**: AZ Medien videos
    87  - **AZMedienPlaylist**: AZ Medien playlists
    88  - **AZMedienShowPlaylist**: AZ Medien show playlists
    8987 - **BaiduVideo**: 百度视频
    9088 - **bambuser**
     
    9997 - **bbc.co.uk:iplayer:playlist**
    10098 - **bbc.co.uk:playlist**
     99 - **BBVTV**
    101100 - **Beatport**
    102101 - **Beeg**
     
    165164 - **chirbit:profile**
    166165 - **Cinchcast**
     166 - **CiscoLiveSearch**
     167 - **CiscoLiveSession**
    167168 - **CJSW**
    168169 - **cliphunter**
     
    178179 - **cmt.com**
    179180 - **CNBC**
     181 - **CNBCVideo**
    180182 - **CNN**
    181183 - **CNNArticle**
     
    251253 - **egghead:course**: egghead.io course
    252254 - **egghead:lesson**: egghead.io lesson
     255 - **ehftv**
    253256 - **eHow**
     257 - **EinsUndEinsTV**
    254258 - **Einthusan**
    255259 - **eitb.tv**
     
    269273 - **Europa**
    270274 - **EveryonesMixtape**
     275 - **EWETV**
    271276 - **ExpoTV**
    272277 - **Expressen**
     
    328333 - **GiantBomb**
    329334 - **Giga**
     335 - **GlattvisionTV**
    330336 - **Glide**: Glide mobile video messages (glide.me)
    331337 - **Globo**
     
    357363 - **HornBunny**
    358364 - **HotNewHipHop**
    359  - **HotStar**
     365 - **hotstar**
    360366 - **hotstar:playlist**
    361367 - **Howcast**
     
    442448 - **limelight:channel_list**
    443449 - **LineTV**
     450 - **linkedin:learning**
     451 - **linkedin:learning:course**
    444452 - **LiTV**
    445453 - **LiveLeak**
     
    495503 - **MLB**
    496504 - **Mnet**
     505 - **MNetTV**
    497506 - **MoeVideo**: LetitBit video services: moevideo.net, playreplay.net and videochart.net
    498507 - **Mofosex**
     
    526535 - **MyVidster**
    527536 - **MyviEmbed**
     537 - **MyVisionTV**
    528538 - **n-tv.de**
    529539 - **natgeo**
     
    551561 - **netease:singer**: 网易云音乐 - 歌手
    552562 - **netease:song**: 网易云音乐
     563 - **NetPlus**
    553564 - **Netzkino**
    554565 - **Newgrounds**
     
    627638 - **orf:oe1**: Radio Österreich 1
    628639 - **orf:tvthek**: ORF TVthek
     640 - **OsnatelTV**
    629641 - **PacktPub**
    630642 - **PacktPubCourse**
     
    687699 - **qqmusic:singer**: QQ音乐 - 歌手
    688700 - **qqmusic:toplist**: QQ音乐 - 排行榜
     701 - **QuantumTV**
    689702 - **Quickline**
    690703 - **QuicklineLive**
     
    754767 - **safari:api**
    755768 - **safari:course**: safaribooksonline.com online courses
     769 - **SAKTV**
    756770 - **Sapo**: SAPO Vídeos
    757771 - **savefrom.net**
     
    809823 - **sport.francetvinfo.fr**
    810824 - **Sport5**
    811  - **SportBoxEmbed**
     825 - **SportBox**
    812826 - **SportDeutschland**
    813827 - **SpringboardPlatform**
     
    900914 - **tv2.hu**
    901915 - **TV2Article**
    902  - **TV3**
    903916 - **TV4**: tv4.se and tv4play.se
    904917 - **TV5MondePlus**: TV5MONDE+
     
    922935 - **TVPlayHome**
    923936 - **Tweakers**
     937 - **TwitCasting**
    924938 - **twitch:chapter**
    925939 - **twitch:clips**
     
    10361050 - **vrv:series**
    10371051 - **VShare**
     1052 - **VTXTV**
    10381053 - **vube**: Vube.com
    10391054 - **VuClip**
     
    10421057 - **Vzaar**
    10431058 - **Walla**
     1059 - **WalyTV**
    10441060 - **washingtonpost**
    10451061 - **washingtonpost:article**
     
    10671083 - **WSJ**: Wall Street Journal
    10681084 - **WSJArticle**
     1085 - **WWE**
    10691086 - **XBef**
    10701087 - **XboxClips**
     
    11261143 - **ZDFChannel**
    11271144 - **zingmp3**: mp3.zing.vn
     1145 - **Zype**
  • youtube-dl/trunk/fuentes/setup.py

    r8096 r8258  
    120120        'Environment :: Console',
    121121        'License :: Public Domain',
     122        'Programming Language :: Python',
     123        'Programming Language :: Python :: 2',
    122124        'Programming Language :: Python :: 2.6',
    123125        'Programming Language :: Python :: 2.7',
     
    128130        'Programming Language :: Python :: 3.5',
    129131        'Programming Language :: Python :: 3.6',
     132        'Programming Language :: Python :: 3.7',
     133        'Programming Language :: Python :: 3.8',
     134        'Programming Language :: Python :: Implementation',
     135        'Programming Language :: Python :: Implementation :: CPython',
     136        'Programming Language :: Python :: Implementation :: IronPython',
     137        'Programming Language :: Python :: Implementation :: Jython',
     138        'Programming Language :: Python :: Implementation :: PyPy',
    130139    ],
    131140
  • youtube-dl/trunk/fuentes/test/helper.py

    r8096 r8258  
    88import re
    99import types
     10import ssl
    1011import sys
    1112
     
    245246
    246247    ydl.report_warning = _report_warning
     248
     249
     250def http_server_port(httpd):
     251    if os.name == 'java' and isinstance(httpd.socket, ssl.SSLSocket):
     252        # In Jython SSLSocket is not a subclass of socket.socket
     253        sock = httpd.socket.sock
     254    else:
     255        sock = httpd.socket
     256    return sock.getsockname()[1]
  • youtube-dl/trunk/fuentes/test/test_InfoExtractor.py

    r8096 r8258  
    1010sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    1111
    12 from test.helper import FakeYDL, expect_dict, expect_value
    13 from youtube_dl.compat import compat_etree_fromstring
     12from test.helper import FakeYDL, expect_dict, expect_value, http_server_port
     13from youtube_dl.compat import compat_etree_fromstring, compat_http_server
    1414from youtube_dl.extractor.common import InfoExtractor
    1515from youtube_dl.extractor import YoutubeIE, get_info_extractor
    1616from youtube_dl.utils import encode_data_uri, strip_jsonp, ExtractorError, RegexNotFoundError
     17import threading
     18
     19
     20TEAPOT_RESPONSE_STATUS = 418
     21TEAPOT_RESPONSE_BODY = "<h1>418 I'm a teapot</h1>"
     22
     23
     24class InfoExtractorTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
     25    def log_message(self, format, *args):
     26        pass
     27
     28    def do_GET(self):
     29        if self.path == '/teapot':
     30            self.send_response(TEAPOT_RESPONSE_STATUS)
     31            self.send_header('Content-Type', 'text/html; charset=utf-8')
     32            self.end_headers()
     33            self.wfile.write(TEAPOT_RESPONSE_BODY.encode())
     34        else:
     35            assert False
    1736
    1837
     
    744763                    expect_dict(self, entries[i], expected_entries[i])
    745764
     765    def test_response_with_expected_status_returns_content(self):
     766        # Checks for mitigations against the effects of
     767        # <https://bugs.python.org/issue15002> that affect Python 3.4.1+, which
     768        # manifest as `_download_webpage`, `_download_xml`, `_download_json`,
     769        # or the underlying `_download_webpage_handle` returning no content
     770        # when a response matches `expected_status`.
     771
     772        httpd = compat_http_server.HTTPServer(
     773            ('127.0.0.1', 0), InfoExtractorTestRequestHandler)
     774        port = http_server_port(httpd)
     775        server_thread = threading.Thread(target=httpd.serve_forever)
     776        server_thread.daemon = True
     777        server_thread.start()
     778
     779        (content, urlh) = self.ie._download_webpage_handle(
     780            'http://127.0.0.1:%d/teapot' % port, None,
     781            expected_status=TEAPOT_RESPONSE_STATUS)
     782        self.assertEqual(content, TEAPOT_RESPONSE_BODY)
     783
    746784
    747785if __name__ == '__main__':
  • youtube-dl/trunk/fuentes/test/test_downloader_http.py

    r8096 r8258  
    1010sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    1111
    12 from test.helper import try_rm
     12from test.helper import http_server_port, try_rm
    1313from youtube_dl import YoutubeDL
    1414from youtube_dl.compat import compat_http_server
    1515from youtube_dl.downloader.http import HttpFD
    1616from youtube_dl.utils import encodeFilename
    17 import ssl
    1817import threading
    1918
    2019TEST_DIR = os.path.dirname(os.path.abspath(__file__))
    21 
    22 
    23 def http_server_port(httpd):
    24     if os.name == 'java' and isinstance(httpd.socket, ssl.SSLSocket):
    25         # In Jython SSLSocket is not a subclass of socket.socket
    26         sock = httpd.socket.sock
    27     else:
    28         sock = httpd.socket
    29     return sock.getsockname()[1]
    3020
    3121
  • youtube-dl/trunk/fuentes/test/test_http.py

    r8096 r8258  
    99sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    1010
     11from test.helper import http_server_port
    1112from youtube_dl import YoutubeDL
    1213from youtube_dl.compat import compat_http_server, compat_urllib_request
     
    1516
    1617TEST_DIR = os.path.dirname(os.path.abspath(__file__))
    17 
    18 
    19 def http_server_port(httpd):
    20     if os.name == 'java' and isinstance(httpd.socket, ssl.SSLSocket):
    21         # In Jython SSLSocket is not a subclass of socket.socket
    22         sock = httpd.socket.sock
    23     else:
    24         sock = httpd.socket
    25     return sock.getsockname()[1]
    2618
    2719
  • youtube-dl/trunk/fuentes/youtube-dl.1

    r8096 r8258  
    10641064.IP \[bu] 2
    10651065\f[C]uploader_id\f[] (string): Nickname or id of the video uploader
     1066.IP \[bu] 2
     1067\f[C]channel\f[] (string): Full name of the channel the video is
     1068uploaded on
     1069.IP \[bu] 2
     1070\f[C]channel_id\f[] (string): Id of the channel
    10661071.IP \[bu] 2
    10671072\f[C]location\f[] (string): Physical location where the video was filmed
     
    23292334.SS Use safe conversion functions
    23302335.PP
    2331 Wrap all extracted numeric data into safe functions from \f[C]utils\f[]:
     2336Wrap all extracted numeric data into safe functions from
     2337\f[C]youtube_dl/utils.py\f[] (https://github.com/rg3/youtube-dl/blob/master/youtube_dl/utils.py):
    23322338\f[C]int_or_none\f[], \f[C]float_or_none\f[].
    23332339Use them for string to number conversions as well.
     2340.PP
     2341Use \f[C]url_or_none\f[] for safe URL processing.
     2342.PP
     2343Use \f[C]try_get\f[] for safe metadata extraction from parsed JSON.
     2344.PP
     2345Explore
     2346\f[C]youtube_dl/utils.py\f[] (https://github.com/rg3/youtube-dl/blob/master/youtube_dl/utils.py)
     2347for more useful convenience functions.
     2348.SS More examples
     2349.SS Safely extract optional description from parsed JSON
     2350.IP
     2351.nf
     2352\f[C]
     2353description\ =\ try_get(response,\ lambda\ x:\ x[\[aq]result\[aq]][\[aq]video\[aq]][0][\[aq]summary\[aq]],\ compat_str)
     2354\f[]
     2355.fi
     2356.SS Safely extract more optional metadata
     2357.IP
     2358.nf
     2359\f[C]
     2360video\ =\ try_get(response,\ lambda\ x:\ x[\[aq]result\[aq]][\[aq]video\[aq]][0],\ dict)\ or\ {}
     2361description\ =\ video.get(\[aq]summary\[aq])
     2362duration\ =\ float_or_none(video.get(\[aq]durationMs\[aq]),\ scale=1000)
     2363view_count\ =\ int_or_none(video.get(\[aq]views\[aq]))
     2364\f[]
     2365.fi
    23342366.SH EMBEDDING YOUTUBE\-DL
    23352367.PP
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/adobepass.py

    r8096 r8258  
    13261326
    13271327    def _download_webpage_handle(self, *args, **kwargs):
    1328         headers = kwargs.get('headers', {})
    1329         headers.update(self.geo_verification_headers())
     1328        headers = self.geo_verification_headers()
     1329        headers.update(kwargs.get('headers', {}))
    13301330        kwargs['headers'] = headers
    13311331        return super(AdobePassIE, self)._download_webpage_handle(
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/americastestkitchen.py

    r8096 r8258  
    4444        webpage = self._download_webpage(url, video_id)
    4545
    46         partner_id = self._search_regex(
    47             r'src=["\'](?:https?:)?//(?:[^/]+\.)kaltura\.com/(?:[^/]+/)*(?:p|partner_id)/(\d+)',
    48             webpage, 'kaltura partner id')
    49 
    5046        video_data = self._parse_json(
    5147            self._search_regex(
     
    5955             lambda x: x['videoDetail']['content']['data']), dict)
    6056        ep_meta = ep_data.get('full_video', {})
    61         external_id = ep_data.get('external_id') or ep_meta['external_id']
     57
     58        zype_id = ep_meta.get('zype_id')
     59        if zype_id:
     60            embed_url = 'https://player.zype.com/embed/%s.js?api_key=jZ9GUhRmxcPvX7M3SlfejB6Hle9jyHTdk2jVxG7wOHPLODgncEKVdPYBhuz9iWXQ' % zype_id
     61            ie_key = 'Zype'
     62        else:
     63            partner_id = self._search_regex(
     64                r'src=["\'](?:https?:)?//(?:[^/]+\.)kaltura\.com/(?:[^/]+/)*(?:p|partner_id)/(\d+)',
     65                webpage, 'kaltura partner id')
     66            external_id = ep_data.get('external_id') or ep_meta['external_id']
     67            embed_url = 'kaltura:%s:%s' % (partner_id, external_id)
     68            ie_key = 'Kaltura'
    6269
    6370        title = ep_data.get('title') or ep_meta.get('title')
     
    7380        return {
    7481            '_type': 'url_transparent',
    75             'url': 'kaltura:%s:%s' % (partner_id, external_id),
    76             'ie_key': 'Kaltura',
     82            'url': embed_url,
     83            'ie_key': ie_key,
    7784            'title': title,
    7885            'description': description,
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/aparat.py

    r8096 r8258  
    55from ..utils import (
    66    int_or_none,
     7    merge_dicts,
    78    mimetype2ext,
    89    url_or_none,
     
    1314    _VALID_URL = r'https?://(?:www\.)?aparat\.com/(?:v/|video/video/embed/videohash/)(?P<id>[a-zA-Z0-9]+)'
    1415
    15     _TEST = {
     16    _TESTS = [{
    1617        'url': 'http://www.aparat.com/v/wP8On',
    1718        'md5': '131aca2e14fe7c4dcb3c4877ba300c89',
     
    2021            'ext': 'mp4',
    2122            'title': 'تیم گلکسی 11 - زومیت',
    22             'age_limit': 0,
     23            'description': 'md5:096bdabcdcc4569f2b8a5e903a3b3028',
     24            'duration': 231,
     25            'timestamp': 1387394859,
     26            'upload_date': '20131218',
     27            'view_count': int,
    2328        },
    24         # 'skip': 'Extremely unreliable',
    25     }
     29    }, {
     30        # multiple formats
     31        'url': 'https://www.aparat.com/v/8dflw/',
     32        'only_matching': True,
     33    }]
    2634
    2735    def _real_extract(self, url):
    2836        video_id = self._match_id(url)
    2937
    30         # Note: There is an easier-to-parse configuration at
    31         # http://www.aparat.com/video/video/config/videohash/%video_id
    32         # but the URL in there does not work
    33         webpage = self._download_webpage(
    34             'http://www.aparat.com/video/video/embed/vt/frame/showvideo/yes/videohash/' + video_id,
     38        # Provides more metadata
     39        webpage = self._download_webpage(url, video_id, fatal=False)
     40
     41        if not webpage:
     42            # Note: There is an easier-to-parse configuration at
     43            # http://www.aparat.com/video/video/config/videohash/%video_id
     44            # but the URL in there does not work
     45            webpage = self._download_webpage(
     46                'http://www.aparat.com/video/video/embed/vt/frame/showvideo/yes/videohash/' + video_id,
     47                video_id)
     48
     49        options = self._parse_json(
     50            self._search_regex(
     51                r'options\s*=\s*JSON\.parse\(\s*(["\'])(?P<value>(?:(?!\1).)+)\1\s*\)',
     52                webpage, 'options', group='value'),
    3553            video_id)
    3654
    37         title = self._search_regex(r'\s+title:\s*"([^"]+)"', webpage, 'title')
    38 
    39         file_list = self._parse_json(
    40             self._search_regex(
    41                 r'fileList\s*=\s*JSON\.parse\(\'([^\']+)\'\)', webpage,
    42                 'file list'),
    43             video_id)
     55        player = options['plugins']['sabaPlayerPlugin']
    4456
    4557        formats = []
    46         for item in file_list[0]:
    47             file_url = url_or_none(item.get('file'))
    48             if not file_url:
    49                 continue
    50             ext = mimetype2ext(item.get('type'))
    51             label = item.get('label')
    52             formats.append({
    53                 'url': file_url,
    54                 'ext': ext,
    55                 'format_id': label or ext,
    56                 'height': int_or_none(self._search_regex(
    57                     r'(\d+)[pP]', label or '', 'height', default=None)),
    58             })
    59         self._sort_formats(formats)
     58        for sources in player['multiSRC']:
     59            for item in sources:
     60                if not isinstance(item, dict):
     61                    continue
     62                file_url = url_or_none(item.get('src'))
     63                if not file_url:
     64                    continue
     65                item_type = item.get('type')
     66                if item_type == 'application/vnd.apple.mpegurl':
     67                    formats.extend(self._extract_m3u8_formats(
     68                        file_url, video_id, 'mp4',
     69                        entry_protocol='m3u8_native', m3u8_id='hls',
     70                        fatal=False))
     71                else:
     72                    ext = mimetype2ext(item.get('type'))
     73                    label = item.get('label')
     74                    formats.append({
     75                        'url': file_url,
     76                        'ext': ext,
     77                        'format_id': 'http-%s' % (label or ext),
     78                        'height': int_or_none(self._search_regex(
     79                            r'(\d+)[pP]', label or '', 'height',
     80                            default=None)),
     81                    })
     82        self._sort_formats(
     83            formats, field_preference=('height', 'width', 'tbr', 'format_id'))
    6084
    61         thumbnail = self._search_regex(
    62             r'image:\s*"([^"]+)"', webpage, 'thumbnail', fatal=False)
     85        info = self._search_json_ld(webpage, video_id, default={})
    6386
    64         return {
     87        if not info.get('title'):
     88            info['title'] = player['title']
     89
     90        return merge_dicts(info, {
    6591            'id': video_id,
    66             'title': title,
    67             'thumbnail': thumbnail,
    68             'age_limit': self._family_friendly_search(webpage),
     92            'thumbnail': url_or_none(options.get('poster')),
     93            'duration': int_or_none(player.get('duration')),
    6994            'formats': formats,
    70         }
     95        })
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/asiancrush.py

    r8096 r8258  
    99    extract_attributes,
    1010    remove_end,
    11     urlencode_postdata,
    1211)
    1312
     
    3534        video_id = self._match_id(url)
    3635
    37         data = self._download_json(
    38             'https://www.asiancrush.com/wp-admin/admin-ajax.php', video_id,
    39             data=urlencode_postdata({
    40                 'postid': video_id,
    41                 'action': 'get_channel_kaltura_vars',
    42             }))
     36        webpage = self._download_webpage(url, video_id)
    4337
    44         entry_id = data['entry_id']
     38        entry_id, partner_id, title = [None] * 3
     39
     40        vars = self._parse_json(
     41            self._search_regex(
     42                r'iEmbedVars\s*=\s*({.+?})', webpage, 'embed vars',
     43                default='{}'), video_id, fatal=False)
     44        if vars:
     45            entry_id = vars.get('entry_id')
     46            partner_id = vars.get('partner_id')
     47            title = vars.get('vid_label')
     48
     49        if not entry_id:
     50            entry_id = self._search_regex(
     51                r'\bentry_id["\']\s*:\s*["\'](\d+)', webpage, 'entry id')
     52
     53        player = self._download_webpage(
     54            'https://api.asiancrush.com/embeddedVideoPlayer', video_id,
     55            query={'id': entry_id})
     56
     57        kaltura_id = self._search_regex(
     58            r'entry_id["\']\s*:\s*(["\'])(?P<id>(?:(?!\1).)+)\1', player,
     59            'kaltura id', group='id')
     60
     61        if not partner_id:
     62            partner_id = self._search_regex(
     63                r'/p(?:artner_id)?/(\d+)', player, 'partner id',
     64                default='513551')
    4565
    4666        return self.url_result(
    47             'kaltura:%s:%s' % (data['partner_id'], entry_id),
    48             ie=KalturaIE.ie_key(), video_id=entry_id,
    49             video_title=data.get('vid_label'))
     67            'kaltura:%s:%s' % (partner_id, kaltura_id),
     68            ie=KalturaIE.ie_key(), video_id=kaltura_id,
     69            video_title=title)
    5070
    5171
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/atvat.py

    r8096 r8258  
    2929        webpage = self._download_webpage(url, display_id)
    3030        video_data = self._parse_json(unescapeHTML(self._search_regex(
    31             r'class="[^"]*jsb_video/FlashPlayer[^"]*"[^>]+data-jsb="([^"]+)"',
    32             webpage, 'player data')), display_id)['config']['initial_video']
     31            [r'flashPlayerOptions\s*=\s*(["\'])(?P<json>(?:(?!\1).)+)\1',
     32             r'class="[^"]*jsb_video/FlashPlayer[^"]*"[^>]+data-jsb="(?P<json>[^"]+)"'],
     33            webpage, 'player data', group='json')),
     34            display_id)['config']['initial_video']
    3335
    3436        video_id = video_data['id']
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/azmedien.py

    r8096 r8258  
    22from __future__ import unicode_literals
    33
     4import json
    45import re
    56
    67from .common import InfoExtractor
    78from .kaltura import KalturaIE
    8 from ..utils import (
    9     get_element_by_class,
    10     get_element_by_id,
    11     strip_or_none,
    12     urljoin,
    13 )
    149
    1510
    16 class AZMedienBaseIE(InfoExtractor):
    17     def _kaltura_video(self, partner_id, entry_id):
    18         return self.url_result(
    19             'kaltura:%s:%s' % (partner_id, entry_id), ie=KalturaIE.ie_key(),
    20             video_id=entry_id)
    21 
    22 
    23 class AZMedienIE(AZMedienBaseIE):
     11class AZMedienIE(InfoExtractor):
    2412    IE_DESC = 'AZ Medien videos'
    2513    _VALID_URL = r'''(?x)
    2614                    https?://
    2715                        (?:www\.)?
    28                         (?:
     16                        (?P<host>
    2917                            telezueri\.ch|
    3018                            telebaern\.tv|
    3119                            telem1\.ch
    3220                        )/
    33                         [0-9]+-show-[^/\#]+
     21                        [^/]+/
     22                        (?P<id>
     23                            [^/]+-(?P<article_id>\d+)
     24                        )
    3425                        (?:
    35                             /[0-9]+-episode-[^/\#]+
    36                             (?:
    37                                 /[0-9]+-segment-(?:[^/\#]+\#)?|
    38                                 \#
    39                             )|
    40                             \#
    41                         )
    42                         (?P<id>[^\#]+)
     26                            \#video=
     27                            (?P<kaltura_id>
     28                                [_0-9a-z]+
     29                            )
     30                        )?
    4331                    '''
    4432
    4533    _TESTS = [{
    46         # URL with 'segment'
    47         'url': 'http://www.telezueri.ch/62-show-zuerinews/13772-episode-sonntag-18-dezember-2016/32419-segment-massenabweisungen-beim-hiltl-club-wegen-pelzboom',
     34        'url': 'https://www.telezueri.ch/sonntalk/bundesrats-vakanzen-eu-rahmenabkommen-133214569',
    4835        'info_dict': {
    49             'id': '1_2444peh4',
     36            'id': '1_anruz3wy',
    5037            'ext': 'mp4',
    51             'title': 'Massenabweisungen beim Hiltl Club wegen Pelzboom',
    52             'description': 'md5:9ea9dd1b159ad65b36ddcf7f0d7c76a8',
    53             'uploader_id': 'TeleZ?ri',
    54             'upload_date': '20161218',
    55             'timestamp': 1482084490,
     38            'title': 'Bundesrats-Vakanzen / EU-Rahmenabkommen',
     39            'description': 'md5:dd9f96751ec9c35e409a698a328402f3',
     40            'uploader_id': 'TVOnline',
     41            'upload_date': '20180930',
     42            'timestamp': 1538328802,
    5643        },
    5744        'params': {
     
    5946        },
    6047    }, {
    61         # URL with 'segment' and fragment:
    62         'url': 'http://www.telebaern.tv/118-show-news/14240-episode-dienstag-17-januar-2017/33666-segment-achtung-gefahr#zu-wenig-pflegerinnen-und-pfleger',
    63         'only_matching': True
    64     }, {
    65         # URL with 'episode' and fragment:
    66         'url': 'http://www.telem1.ch/47-show-sonntalk/13986-episode-soldaten-fuer-grenzschutz-energiestrategie-obama-bilanz#soldaten-fuer-grenzschutz-energiestrategie-obama-bilanz',
    67         'only_matching': True
    68     }, {
    69         # URL with 'show' and fragment:
    70         'url': 'http://www.telezueri.ch/66-show-sonntalk#burka-plakate-trump-putin-china-besuch',
     48        'url': 'https://www.telebaern.tv/telebaern-news/montag-1-oktober-2018-ganze-sendung-133531189#video=0_7xjo9lf1',
    7149        'only_matching': True
    7250    }]
    7351
    74     def _real_extract(self, url):
    75         video_id = self._match_id(url)
    76 
    77         webpage = self._download_webpage(url, video_id)
    78 
    79         partner_id = self._search_regex(
    80             r'<script[^>]+src=["\'](?:https?:)?//(?:[^/]+\.)?kaltura\.com(?:/[^/]+)*/(?:p|partner_id)/([0-9]+)',
    81             webpage, 'kaltura partner id')
    82         entry_id = self._html_search_regex(
    83             r'<a[^>]+data-id=(["\'])(?P<id>(?:(?!\1).)+)\1[^>]+data-slug=["\']%s'
    84             % re.escape(video_id), webpage, 'kaltura entry id', group='id')
    85 
    86         return self._kaltura_video(partner_id, entry_id)
    87 
    88 
    89 class AZMedienPlaylistIE(AZMedienBaseIE):
    90     IE_DESC = 'AZ Medien playlists'
    91     _VALID_URL = r'''(?x)
    92                     https?://
    93                         (?:www\.)?
    94                         (?:
    95                             telezueri\.ch|
    96                             telebaern\.tv|
    97                             telem1\.ch
    98                         )/
    99                         (?P<id>[0-9]+-
    100                             (?:
    101                                 show|
    102                                 topic|
    103                                 themen
    104                             )-[^/\#]+
    105                             (?:
    106                                 /[0-9]+-episode-[^/\#]+
    107                             )?
    108                         )$
    109                     '''
    110 
    111     _TESTS = [{
    112         # URL with 'episode'
    113         'url': 'http://www.telebaern.tv/118-show-news/13735-episode-donnerstag-15-dezember-2016',
    114         'info_dict': {
    115             'id': '118-show-news/13735-episode-donnerstag-15-dezember-2016',
    116             'title': 'News - Donnerstag, 15. Dezember 2016',
    117         },
    118         'playlist_count': 9,
    119     }, {
    120         # URL with 'themen'
    121         'url': 'http://www.telem1.ch/258-themen-tele-m1-classics',
    122         'info_dict': {
    123             'id': '258-themen-tele-m1-classics',
    124             'title': 'Tele M1 Classics',
    125         },
    126         'playlist_mincount': 15,
    127     }, {
    128         # URL with 'topic', contains nested playlists
    129         'url': 'http://www.telezueri.ch/219-topic-aera-trump-hat-offiziell-begonnen',
    130         'only_matching': True,
    131     }, {
    132         # URL with 'show' only
    133         'url': 'http://www.telezueri.ch/86-show-talktaeglich',
    134         'only_matching': True
    135     }]
     52    _PARTNER_ID = '1719221'
    13653
    13754    def _real_extract(self, url):
    138         show_id = self._match_id(url)
    139         webpage = self._download_webpage(url, show_id)
     55        mobj = re.match(self._VALID_URL, url)
     56        video_id = mobj.group('id')
     57        entry_id = mobj.group('kaltura_id')
    14058
    141         entries = []
     59        if not entry_id:
     60            webpage = self._download_webpage(url, video_id)
     61            api_path = self._search_regex(
     62                r'["\']apiPath["\']\s*:\s*["\']([^"^\']+)["\']',
     63                webpage, 'api path')
     64            api_url = 'https://www.%s%s' % (mobj.group('host'), api_path)
     65            payload = {
     66                'query': '''query VideoContext($articleId: ID!) {
     67                    article: node(id: $articleId) {
     68                      ... on Article {
     69                        mainAssetRelation {
     70                          asset {
     71                            ... on VideoAsset {
     72                              kalturaId
     73                            }
     74                          }
     75                        }
     76                      }
     77                    }
     78                  }''',
     79                'variables': {'articleId': 'Article:%s' % mobj.group('article_id')},
     80            }
     81            json_data = self._download_json(
     82                api_url, video_id, headers={
     83                    'Content-Type': 'application/json',
     84                },
     85                data=json.dumps(payload).encode())
     86            entry_id = json_data['data']['article']['mainAssetRelation']['asset']['kalturaId']
    14287
    143         partner_id = self._search_regex(
    144             r'src=["\'](?:https?:)?//(?:[^/]+\.)kaltura\.com/(?:[^/]+/)*(?:p|partner_id)/(\d+)',
    145             webpage, 'kaltura partner id', default=None)
    146 
    147         if partner_id:
    148             entries = [
    149                 self._kaltura_video(partner_id, m.group('id'))
    150                 for m in re.finditer(
    151                     r'data-id=(["\'])(?P<id>(?:(?!\1).)+)\1', webpage)]
    152 
    153         if not entries:
    154             entries = [
    155                 self.url_result(m.group('url'), ie=AZMedienIE.ie_key())
    156                 for m in re.finditer(
    157                     r'<a[^>]+data-real=(["\'])(?P<url>http.+?)\1', webpage)]
    158 
    159         if not entries:
    160             entries = [
    161                 # May contain nested playlists (e.g. [1]) thus no explicit
    162                 # ie_key
    163                 # 1. http://www.telezueri.ch/219-topic-aera-trump-hat-offiziell-begonnen)
    164                 self.url_result(urljoin(url, m.group('url')))
    165                 for m in re.finditer(
    166                     r'<a[^>]+name=[^>]+href=(["\'])(?P<url>/.+?)\1', webpage)]
    167 
    168         title = self._search_regex(
    169             r'episodeShareTitle\s*=\s*(["\'])(?P<title>(?:(?!\1).)+)\1',
    170             webpage, 'title',
    171             default=strip_or_none(get_element_by_id(
    172                 'video-title', webpage)), group='title')
    173 
    174         return self.playlist_result(entries, show_id, title)
    175 
    176 
    177 class AZMedienShowPlaylistIE(AZMedienBaseIE):
    178     IE_DESC = 'AZ Medien show playlists'
    179     _VALID_URL = r'''(?x)
    180                     https?://
    181                         (?:www\.)?
    182                         (?:
    183                             telezueri\.ch|
    184                             telebaern\.tv|
    185                             telem1\.ch
    186                         )/
    187                         (?:
    188                             all-episodes|
    189                             alle-episoden
    190                         )/
    191                         (?P<id>[^/?#&]+)
    192                     '''
    193 
    194     _TEST = {
    195         'url': 'http://www.telezueri.ch/all-episodes/astrotalk',
    196         'info_dict': {
    197             'id': 'astrotalk',
    198             'title': 'TeleZüri: AstroTalk - alle episoden',
    199             'description': 'md5:4c0f7e7d741d906004266e295ceb4a26',
    200         },
    201         'playlist_mincount': 13,
    202     }
    203 
    204     def _real_extract(self, url):
    205         playlist_id = self._match_id(url)
    206         webpage = self._download_webpage(url, playlist_id)
    207         episodes = get_element_by_class('search-mobile-box', webpage)
    208         entries = [self.url_result(
    209             urljoin(url, m.group('url'))) for m in re.finditer(
    210                 r'<a[^>]+href=(["\'])(?P<url>(?:(?!\1).)+)\1', episodes)]
    211         title = self._og_search_title(webpage, fatal=False)
    212         description = self._og_search_description(webpage)
    213         return self.playlist_result(entries, playlist_id, title, description)
     88        return self.url_result(
     89            'kaltura:%s:%s' % (self._PARTNER_ID, entry_id),
     90            ie=KalturaIE.ie_key(), video_id=entry_id)
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/bitchute.py

    r8096 r8258  
    3838            })
    3939
    40         title = self._search_regex(
     40        title = self._html_search_regex(
    4141            (r'<[^>]+\bid=["\']video-title[^>]+>([^<]+)', r'<title>([^<]+)'),
    4242            webpage, 'title', default=None) or self._html_search_meta(
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/brightcove.py

    r8096 r8258  
    22from __future__ import unicode_literals
    33
     4import base64
     5import json
    46import re
    5 import json
     7import struct
    68
    79from .common import InfoExtractor
     
    311313                expected=True)
    312314
     315    def _brightcove_new_url_result(self, publisher_id, video_id):
     316        brightcove_new_url = 'http://players.brightcove.net/%s/default_default/index.html?videoId=%s' % (publisher_id, video_id)
     317        return self.url_result(brightcove_new_url, BrightcoveNewIE.ie_key(), video_id)
     318
    313319    def _get_video_info(self, video_id, query, referer=None):
    314320        headers = {}
     
    324330            'error message', default=None)
    325331        if error_msg is not None:
     332            publisher_id = query.get('publisherId')
     333            if publisher_id and publisher_id[0].isdigit():
     334                publisher_id = publisher_id[0]
     335            if not publisher_id:
     336                player_key = query.get('playerKey')
     337                if player_key and ',' in player_key[0]:
     338                    player_key = player_key[0]
     339                else:
     340                    player_id = query.get('playerID')
     341                    if player_id and player_id[0].isdigit():
     342                        player_page = self._download_webpage(
     343                            'http://link.brightcove.com/services/player/bcpid' + player_id[0],
     344                            video_id, headers=headers, fatal=False)
     345                        if player_page:
     346                            player_key = self._search_regex(
     347                                r'<param\s+name="playerKey"\s+value="([\w~,-]+)"',
     348                                player_page, 'player key', fatal=False)
     349                if player_key:
     350                    enc_pub_id = player_key.split(',')[1].replace('~', '=')
     351                    publisher_id = struct.unpack('>Q', base64.urlsafe_b64decode(enc_pub_id))[0]
     352                if publisher_id:
     353                    return self._brightcove_new_url_result(publisher_id, video_id)
    326354            raise ExtractorError(
    327355                'brightcove said: %s' % error_msg, expected=True)
     
    445473                    return ad_info
    446474
    447         if 'url' not in info and not info.get('formats'):
    448             raise ExtractorError('Unable to extract video url for %s' % video_id)
     475        if not info.get('url') and not info.get('formats'):
     476            uploader_id = info.get('uploader_id')
     477            if uploader_id:
     478                info.update(self._brightcove_new_url_result(uploader_id, video_id))
     479            else:
     480                raise ExtractorError('Unable to extract video url for %s' % video_id)
    449481        return info
    450482
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/cliphunter.py

    r8096 r8258  
    22
    33from .common import InfoExtractor
    4 from ..utils import int_or_none
    5 
    6 
    7 _translation_table = {
    8     'a': 'h', 'd': 'e', 'e': 'v', 'f': 'o', 'g': 'f', 'i': 'd', 'l': 'n',
    9     'm': 'a', 'n': 'm', 'p': 'u', 'q': 't', 'r': 's', 'v': 'p', 'x': 'r',
    10     'y': 'l', 'z': 'i',
    11     '$': ':', '&': '.', '(': '=', '^': '&', '=': '/',
    12 }
    13 
    14 
    15 def _decode(s):
    16     return ''.join(_translation_table.get(c, c) for c in s)
     4from ..utils import (
     5    int_or_none,
     6    url_or_none,
     7)
    178
    189
     
    6152        formats = []
    6253        for format_id, f in gexo_files.items():
    63             video_url = f.get('url')
     54            video_url = url_or_none(f.get('url'))
    6455            if not video_url:
    6556                continue
     
    6859            format_id = '%s_%sp' % (fmt, height) if fmt and height else format_id
    6960            formats.append({
    70                 'url': _decode(video_url),
     61                'url': video_url,
    7162                'format_id': format_id,
    7263                'width': int_or_none(f.get('w')),
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/cnbc.py

    r8096 r8258  
    11# coding: utf-8
    22from __future__ import unicode_literals
     3
    34
    45from .common import InfoExtractor
     
    3536            'id': video_id,
    3637        }
     38
     39
     40class CNBCVideoIE(InfoExtractor):
     41    _VALID_URL = r'https?://(?:www\.)?cnbc\.com/video/(?:[^/]+/)+(?P<id>[^./?#&]+)'
     42    _TEST = {
     43        'url': 'https://www.cnbc.com/video/2018/07/19/trump-i-dont-necessarily-agree-with-raising-rates.html',
     44        'info_dict': {
     45            'id': '7000031301',
     46            'ext': 'mp4',
     47            'title': "Trump: I don't necessarily agree with raising rates",
     48            'description': 'md5:878d8f0b4ebb5bb1dda3514b91b49de3',
     49            'timestamp': 1531958400,
     50            'upload_date': '20180719',
     51            'uploader': 'NBCU-CNBC',
     52        },
     53        'params': {
     54            'skip_download': True,
     55        },
     56    }
     57
     58    def _real_extract(self, url):
     59        display_id = self._match_id(url)
     60        webpage = self._download_webpage(url, display_id)
     61        video_id = self._search_regex(
     62            r'content_id["\']\s*:\s*["\'](\d+)', webpage, display_id,
     63            'video id')
     64        return self.url_result(
     65            'http://video.cnbc.com/gallery/?video=%s' % video_id,
     66            CNBCIE.ie_key())
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/common.py

    r8096 r8258  
    7070    urljoin,
    7171    url_basename,
     72    url_or_none,
    7273    xpath_element,
    7374    xpath_text,
     
    212213    uploader_id:    Nickname or id of the video uploader.
    213214    uploader_url:   Full URL to a personal webpage of the video uploader.
     215    channel:        Full name of the channel the video is uploaded on.
     216                    Note that channel fields may or may not repeat uploader
     217                    fields. This depends on a particular extractor.
     218    channel_id:     Id of the channel.
     219    channel_url:    Full URL to a channel webpage.
    214220    location:       Physical location where the video was filmed.
    215221    subtitles:      The available subtitles as a dictionary in the format
     
    601607            if isinstance(err, compat_urllib_error.HTTPError):
    602608                if self.__can_accept_status_code(err, expected_status):
     609                    # Retain reference to error to prevent file object from
     610                    # being closed before it can be read. Works around the
     611                    # effects of <https://bugs.python.org/issue15002>
     612                    # introduced in Python 3.4.1.
     613                    err.fp._error = err
    603614                    return err.fp
    604615
     
    12091220            assert e['@type'] == 'VideoObject'
    12101221            info.update({
    1211                 'url': e.get('contentUrl'),
     1222                'url': url_or_none(e.get('contentUrl')),
    12121223                'title': unescapeHTML(e.get('name')),
    12131224                'description': unescapeHTML(e.get('description')),
    1214                 'thumbnail': e.get('thumbnailUrl') or e.get('thumbnailURL'),
     1225                'thumbnail': url_or_none(e.get('thumbnailUrl') or e.get('thumbnailURL')),
    12151226                'duration': parse_duration(e.get('duration')),
    12161227                'timestamp': unified_timestamp(e.get('uploadDate')),
     
    17021713                # contains EXT-X-STREAM-INF tag which references AUDIO
    17031714                # rendition group but does not have CODECS and despite
    1704                 # referencing audio group an audio group, it represents
    1705                 # a complete (with audio and video) format. So, for such cases
    1706                 # we will ignore references to rendition groups and treat them
     1715                # referencing an audio group it represents a complete
     1716                # (with audio and video) format. So, for such cases we will
     1717                # ignore references to rendition groups and treat them
    17071718                # as complete formats.
    17081719                if audio_group_id and codecs and f.get('vcodec') != 'none':
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/crunchyroll.py

    r8096 r8258  
    44import re
    55import json
     6import xml.etree.ElementTree as etree
    67import zlib
    78
     
    4647        data = compat_urllib_parse_urlencode(data).encode('utf-8')
    4748        return self._download_xml(
    48             'http://www.crunchyroll.com/xml/',
     49            'https://www.crunchyroll.com/xml/',
    4950            video_id, note, fatal=False, data=data, headers={
    5051                'Content-Type': 'application/x-www-form-urlencoded',
     
    399400                    'subtitle_script_id': sub_id,
    400401                })
    401             if sub_doc is None:
     402            if not isinstance(sub_doc, etree.Element):
    402403                continue
    403404            sid = sub_doc.get('id')
     
    445446            webpage, 'vilos media', default='{}'), video_id)
    446447        media_metadata = media.get('metadata') or {}
     448
     449        language = self._search_regex(
     450            r'(?:vilos\.config\.player\.language|LOCALE)\s*=\s*(["\'])(?P<lang>(?:(?!\1).)+)\1',
     451            webpage, 'language', default=None, group='lang')
    447452
    448453        video_title = self._html_search_regex(
     
    467472        formats = []
    468473        for stream in media.get('streams', []):
    469             formats.extend(self._extract_vrv_formats(
     474            audio_lang = stream.get('audio_lang')
     475            hardsub_lang = stream.get('hardsub_lang')
     476            vrv_formats = self._extract_vrv_formats(
    470477                stream.get('url'), video_id, stream.get('format'),
    471                 stream.get('audio_lang'), stream.get('hardsub_lang')))
     478                audio_lang, hardsub_lang)
     479            for f in vrv_formats:
     480                if not hardsub_lang:
     481                    f['preference'] = 1
     482                language_preference = 0
     483                if audio_lang == language:
     484                    language_preference += 1
     485                if hardsub_lang == language:
     486                    language_preference += 1
     487                if language_preference:
     488                    f['language_preference'] = language_preference
     489            formats.extend(vrv_formats)
    472490        if not formats:
    473491            available_fmts = []
     
    499517                        'current_page': url,
    500518                    })
    501                 if streamdata is not None:
     519                if isinstance(streamdata, etree.Element):
    502520                    stream_info = streamdata.find('./{default}preload/stream_info')
    503521                    if stream_info is not None:
     
    510528                        'video_encode_quality': stream_quality,
    511529                    })
    512                 if stream_info is not None:
     530                if isinstance(stream_info, etree.Element):
    513531                    stream_infos.append(stream_info)
    514532                for stream_info in stream_infos:
     
    558576                    })
    559577                    formats.append(format_info)
    560         self._sort_formats(formats, ('height', 'width', 'tbr', 'fps'))
     578        self._sort_formats(formats, ('preference', 'language_preference', 'height', 'width', 'tbr', 'fps'))
    561579
    562580        metadata = self._call_rpc_api(
     
    582600            r'(?s)<h\d[^>]+\bid=["\']showmedia_about_episode_num[^>]+>(.+?)</h\d',
    583601            webpage, 'series', fatal=False)
    584         season = xpath_text(metadata, 'series_title')
    585 
    586         episode = xpath_text(metadata, 'episode_title') or media_metadata.get('title')
    587         episode_number = int_or_none(xpath_text(metadata, 'episode_number') or media_metadata.get('episode_number'))
     602
     603        season = episode = episode_number = duration = thumbnail = None
     604
     605        if isinstance(metadata, etree.Element):
     606            season = xpath_text(metadata, 'series_title')
     607            episode = xpath_text(metadata, 'episode_title')
     608            episode_number = int_or_none(xpath_text(metadata, 'episode_number'))
     609            duration = float_or_none(media_metadata.get('duration'), 1000)
     610            thumbnail = xpath_text(metadata, 'episode_image_url')
     611
     612        if not episode:
     613            episode = media_metadata.get('title')
     614        if not episode_number:
     615            episode_number = int_or_none(media_metadata.get('episode_number'))
     616        if not thumbnail:
     617            thumbnail = media_metadata.get('thumbnail', {}).get('url')
    588618
    589619        season_number = int_or_none(self._search_regex(
     
    595625            'title': video_title,
    596626            'description': video_description,
    597             'duration': float_or_none(media_metadata.get('duration'), 1000),
    598             'thumbnail': xpath_text(metadata, 'episode_image_url') or media_metadata.get('thumbnail', {}).get('url'),
     627            'duration': duration,
     628            'thumbnail': thumbnail,
    599629            'uploader': video_uploader,
    600630            'upload_date': video_upload_date,
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/cwtv.py

    r8096 r8258  
    44from .common import InfoExtractor
    55from ..utils import (
     6    ExtractorError,
    67    int_or_none,
    78    parse_age_limit,
     
    6768    def _real_extract(self, url):
    6869        video_id = self._match_id(url)
    69         video_data = self._download_json(
     70        data = self._download_json(
    7071            'http://images.cwtv.com/feed/mobileapp/video-meta/apiversion_8/guid_' + video_id,
    71             video_id)['video']
     72            video_id)
     73        if data.get('result') != 'ok':
     74            raise ExtractorError(data['msg'], expected=True)
     75        video_data = data['video']
    7276        title = video_data['title']
    7377        mpx_url = video_data.get('mpx_url') or 'http://link.theplatform.com/s/cwtv/media/guid/2703454149/%s?formats=M3U' % video_id
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/dailymail.py

    r8096 r8258  
    5050
    5151        video_sources = self._download_json(sources_url, video_id)
     52        body = video_sources.get('body')
     53        if body:
     54            video_sources = body
    5255
    5356        formats = []
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/dailymotion.py

    r8096 r8258  
    2323    sanitized_Request,
    2424    str_to_int,
     25    try_get,
    2526    unescapeHTML,
     27    update_url_query,
     28    url_or_none,
    2629    urlencode_postdata,
    2730)
     
    172175            webpage, 'player v5', default=None)
    173176        if player_v5:
    174             player = self._parse_json(player_v5, video_id)
    175             metadata = player['metadata']
    176 
    177             if metadata.get('error', {}).get('type') == 'password_protected':
     177            player = self._parse_json(player_v5, video_id, fatal=False) or {}
     178            metadata = try_get(player, lambda x: x['metadata'], dict)
     179            if not metadata:
     180                metadata_url = url_or_none(try_get(
     181                    player, lambda x: x['context']['metadata_template_url1']))
     182                if metadata_url:
     183                    metadata_url = metadata_url.replace(':videoId', video_id)
     184                else:
     185                    metadata_url = update_url_query(
     186                        'https://www.dailymotion.com/player/metadata/video/%s'
     187                        % video_id, {
     188                            'embedder': url,
     189                            'integration': 'inline',
     190                            'GK_PV5_NEON': '1',
     191                        })
     192                metadata = self._download_json(
     193                    metadata_url, video_id, 'Downloading metadata JSON')
     194
     195            if try_get(metadata, lambda x: x['error']['type']) == 'password_protected':
    178196                password = self._downloader.params.get('videopassword')
    179197                if password:
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/eporner.py

    r8096 r8258  
    1010    ExtractorError,
    1111    int_or_none,
     12    merge_dicts,
    1213    parse_duration,
    1314    str_to_int,
     
    2627            'ext': 'mp4',
    2728            'title': 'Infamous Tiffany Teen Strip Tease Video',
     29            'description': 'md5:764f39abf932daafa37485eb46efa152',
     30            'timestamp': 1232520922,
     31            'upload_date': '20090121',
    2832            'duration': 1838,
    2933            'view_count': int,
    3034            'age_limit': 18,
    3135        },
     36        'params': {
     37            'proxy': '127.0.0.1:8118'
     38        }
    3239    }, {
    3340        # New (May 2016) URL layout
     
    105112        self._sort_formats(formats)
    106113
    107         duration = parse_duration(self._html_search_meta('duration', webpage))
     114        json_ld = self._search_json_ld(webpage, display_id, default={})
     115
     116        duration = parse_duration(self._html_search_meta(
     117            'duration', webpage, default=None))
    108118        view_count = str_to_int(self._search_regex(
    109119            r'id="cinemaviews">\s*([0-9,]+)\s*<small>views',
    110120            webpage, 'view count', fatal=False))
    111121
    112         return {
     122        return merge_dicts(json_ld, {
    113123            'id': video_id,
    114124            'display_id': display_id,
     
    118128            'formats': formats,
    119129            'age_limit': 18,
    120         }
     130        })
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/extractors.py

    r8096 r8258  
    8989    AWAANSeasonIE,
    9090)
    91 from .azmedien import (
    92     AZMedienIE,
    93     AZMedienPlaylistIE,
    94     AZMedienShowPlaylistIE,
    95 )
     91from .azmedien import AZMedienIE
    9692from .baidu import BaiduVideoIE
    9793from .bambuser import BambuserIE, BambuserChannelIE
     
    199195)
    200196from .cinchcast import CinchcastIE
     197from .ciscolive import (
     198    CiscoLiveSessionIE,
     199    CiscoLiveSearchIE,
     200)
    201201from .cjsw import CJSWIE
    202202from .cliphunter import CliphunterIE
     
    210210from .clyp import ClypIE
    211211from .cmt import CMTIE
    212 from .cnbc import CNBCIE
     212from .cnbc import (
     213    CNBCIE,
     214    CNBCVideoIE,
     215)
    213216from .cnn import (
    214217    CNNIE,
     
    541544    Laola1TvEmbedIE,
    542545    Laola1TvIE,
     546    EHFTVIE,
    543547    ITTFIE,
    544548)
     
    570574)
    571575from .line import LineTVIE
     576from .linkedin import (
     577    LinkedInLearningIE,
     578    LinkedInLearningCourseIE,
     579)
    572580from .litv import LiTVIE
    573581from .liveleak import (
     
    10441052from .stitcher import StitcherIE
    10451053from .sport5 import Sport5IE
    1046 from .sportbox import SportBoxEmbedIE
     1054from .sportbox import SportBoxIE
    10471055from .sportdeutschland import SportDeutschlandIE
    10481056from .springboardplatform import SpringboardPlatformIE
     
    11541162)
    11551163from .tv2hu import TV2HuIE
    1156 from .tv3 import TV3IE
    11571164from .tv4 import TV4IE
    11581165from .tv5mondeplus import TV5MondePlusIE
     
    11911198from .twentymin import TwentyMinutenIE
    11921199from .twentythreevideo import TwentyThreeVideoIE
     1200from .twitcasting import TwitCastingIE
    11931201from .twitch import (
    11941202    TwitchVideoIE,
     
    13831391    WSJArticleIE,
    13841392)
     1393from .wwe import WWEIE
    13851394from .xbef import XBefIE
    13861395from .xboxclips import XboxClipsIE
     
    14561465from .zaq1 import Zaq1IE
    14571466from .zattoo import (
     1467    BBVTVIE,
     1468    EinsUndEinsTVIE,
     1469    EWETVIE,
     1470    GlattvisionTVIE,
     1471    MNetTVIE,
     1472    MyVisionTVIE,
     1473    NetPlusIE,
     1474    OsnatelTVIE,
     1475    QuantumTVIE,
    14581476    QuicklineIE,
    14591477    QuicklineLiveIE,
     1478    SAKTVIE,
     1479    VTXTVIE,
     1480    WalyTVIE,
    14601481    ZattooIE,
    14611482    ZattooLiveIE,
     
    14631484from .zdf import ZDFIE, ZDFChannelIE
    14641485from .zingmp3 import ZingMp3IE
     1486from .zype import ZypeIE
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/facebook.py

    r8096 r8258  
    5858
    5959    _VIDEO_PAGE_TEMPLATE = 'https://www.facebook.com/video/video.php?v=%s'
    60     _VIDEO_PAGE_TAHOE_TEMPLATE = 'https://www.facebook.com/video/tahoe/async/%s/?chain=true&isvideo=true'
     60    _VIDEO_PAGE_TAHOE_TEMPLATE = 'https://www.facebook.com/video/tahoe/async/%s/?chain=true&isvideo=true&payloadtype=primary'
    6161
    6262    _TESTS = [{
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/fourtube.py

    r8096 r8258  
    44
    55from .common import InfoExtractor
    6 from ..compat import compat_urlparse
     6from ..compat import (
     7    compat_b64decode,
     8    compat_str,
     9    compat_urllib_parse_unquote,
     10    compat_urlparse,
     11)
    712from ..utils import (
     13    int_or_none,
    814    parse_duration,
    915    parse_iso8601,
     16    str_or_none,
    1017    str_to_int,
     18    try_get,
     19    unified_timestamp,
     20    url_or_none,
    1121)
    1222
    1323
    1424class FourTubeBaseIE(InfoExtractor):
     25    _TKN_HOST = 'tkn.kodicdn.com'
     26
     27    def _extract_formats(self, url, video_id, media_id, sources):
     28        token_url = 'https://%s/%s/desktop/%s' % (
     29            self._TKN_HOST, media_id, '+'.join(sources))
     30
     31        parsed_url = compat_urlparse.urlparse(url)
     32        tokens = self._download_json(token_url, video_id, data=b'', headers={
     33            'Origin': '%s://%s' % (parsed_url.scheme, parsed_url.hostname),
     34            'Referer': url,
     35        })
     36        formats = [{
     37            'url': tokens[format]['token'],
     38            'format_id': format + 'p',
     39            'resolution': format + 'p',
     40            'quality': int(format),
     41        } for format in sources]
     42        self._sort_formats(formats)
     43        return formats
     44
    1545    def _real_extract(self, url):
    1646        mobj = re.match(self._VALID_URL, url)
     
    6999            sources = ['%s' % p for p in params[2]]
    70100
    71         token_url = 'https://tkn.kodicdn.com/{0}/desktop/{1}'.format(
    72             media_id, '+'.join(sources))
    73 
    74         parsed_url = compat_urlparse.urlparse(url)
    75         tokens = self._download_json(token_url, video_id, data=b'', headers={
    76             'Origin': '%s://%s' % (parsed_url.scheme, parsed_url.hostname),
    77             'Referer': url,
    78         })
    79         formats = [{
    80             'url': tokens[format]['token'],
    81             'format_id': format + 'p',
    82             'resolution': format + 'p',
    83             'quality': int(format),
    84         } for format in sources]
    85         self._sort_formats(formats)
     101        formats = self._extract_formats(url, video_id, media_id, sources)
    86102
    87103        return {
     
    165181    _VALID_URL = r'https?://(?:(?P<kind>www|m)\.)?porntube\.com/(?:videos/(?P<display_id>[^/]+)_|embed/)(?P<id>\d+)'
    166182    _URL_TEMPLATE = 'https://www.porntube.com/videos/video_%s'
     183    _TKN_HOST = 'tkn.porntube.com'
    167184    _TESTS = [{
    168185        'url': 'https://www.porntube.com/videos/teen-couple-doing-anal_7089759',
     
    172189            'title': 'Teen couple doing anal',
    173190            'uploader': 'Alexy',
    174             'uploader_id': 'Alexy',
     191            'uploader_id': '91488',
    175192            'upload_date': '20150606',
    176193            'timestamp': 1433595647,
     
    178195            'view_count': int,
    179196            'like_count': int,
    180             'categories': list,
    181197            'age_limit': 18,
    182198        },
     
    185201        },
    186202    }, {
     203        'url': 'https://www.porntube.com/videos/squirting-teen-ballerina-ecg_1331406',
     204        'info_dict': {
     205            'id': '1331406',
     206            'ext': 'mp4',
     207            'title': 'Squirting Teen Ballerina on ECG',
     208            'uploader': 'Exploited College Girls',
     209            'uploader_id': '665',
     210            'channel': 'Exploited College Girls',
     211            'channel_id': '665',
     212            'upload_date': '20130920',
     213            'timestamp': 1379685485,
     214            'duration': 851,
     215            'view_count': int,
     216            'like_count': int,
     217            'age_limit': 18,
     218        },
     219        'params': {
     220            'skip_download': True,
     221        },
     222    }, {
    187223        'url': 'https://www.porntube.com/embed/7089759',
    188224        'only_matching': True,
     
    191227        'only_matching': True,
    192228    }]
     229
     230    def _real_extract(self, url):
     231        mobj = re.match(self._VALID_URL, url)
     232        video_id, display_id = mobj.group('id', 'display_id')
     233
     234        webpage = self._download_webpage(url, display_id)
     235
     236        video = self._parse_json(
     237            self._search_regex(
     238                r'INITIALSTATE\s*=\s*(["\'])(?P<value>(?:(?!\1).)+)\1',
     239                webpage, 'data', group='value'), video_id,
     240            transform_source=lambda x: compat_urllib_parse_unquote(
     241                compat_b64decode(x).decode('utf-8')))['page']['video']
     242
     243        title = video['title']
     244        media_id = video['mediaId']
     245        sources = [compat_str(e['height'])
     246                   for e in video['encodings'] if e.get('height')]
     247        formats = self._extract_formats(url, video_id, media_id, sources)
     248
     249        thumbnail = url_or_none(video.get('masterThumb'))
     250        uploader = try_get(video, lambda x: x['user']['username'], compat_str)
     251        uploader_id = str_or_none(try_get(
     252            video, lambda x: x['user']['id'], int))
     253        channel = try_get(video, lambda x: x['channel']['name'], compat_str)
     254        channel_id = str_or_none(try_get(
     255            video, lambda x: x['channel']['id'], int))
     256        like_count = int_or_none(video.get('likes'))
     257        dislike_count = int_or_none(video.get('dislikes'))
     258        view_count = int_or_none(video.get('playsQty'))
     259        duration = int_or_none(video.get('durationInSeconds'))
     260        timestamp = unified_timestamp(video.get('publishedAt'))
     261
     262        return {
     263            'id': video_id,
     264            'title': title,
     265            'formats': formats,
     266            'thumbnail': thumbnail,
     267            'uploader': uploader or channel,
     268            'uploader_id': uploader_id or channel_id,
     269            'channel': channel,
     270            'channel_id': channel_id,
     271            'timestamp': timestamp,
     272            'like_count': like_count,
     273            'dislike_count': dislike_count,
     274            'view_count': view_count,
     275            'duration': duration,
     276            'age_limit': 18,
     277        }
    193278
    194279
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/foxsports.py

    r8096 r8258  
    22
    33from .common import InfoExtractor
    4 from ..utils import (
    5     smuggle_url,
    6     update_url_query,
    7 )
    84
    95
    106class FoxSportsIE(InfoExtractor):
    11     _VALID_URL = r'https?://(?:www\.)?foxsports\.com/(?:[^/]+/)*(?P<id>[^/]+)'
     7    _VALID_URL = r'https?://(?:www\.)?foxsports\.com/(?:[^/]+/)*video/(?P<id>\d+)'
    128
    139    _TEST = {
     
    1511        'md5': 'b49050e955bebe32c301972e4012ac17',
    1612        'info_dict': {
    17             'id': 'bwduI3X_TgUB',
     13            'id': '432609859715',
    1814            'ext': 'mp4',
    1915            'title': 'Courtney Lee on going up 2-0 in series vs. Blazers',
    2016            'description': 'Courtney Lee talks about Memphis being focused.',
    21             'upload_date': '20150423',
    22             'timestamp': 1429761109,
     17            # TODO: fix timestamp
     18            'upload_date': '19700101',  # '20150423',
     19            # 'timestamp': 1429761109,
    2320            'uploader': 'NEWA-FNG-FOXSPORTS',
     21        },
     22        'params': {
     23            # m3u8 download
     24            'skip_download': True,
    2425        },
    2526        'add_ie': ['ThePlatform'],
     
    2930        video_id = self._match_id(url)
    3031
    31         webpage = self._download_webpage(url, video_id)
    32 
    33         config = self._parse_json(
    34             self._html_search_regex(
    35                 r"""class="[^"]*(?:fs-player|platformPlayer-wrapper)[^"]*".+?data-player-config='([^']+)'""",
    36                 webpage, 'data player config'),
    37             video_id)
    38 
    39         return self.url_result(smuggle_url(update_url_query(
    40             config['releaseURL'], {
    41                 'mbr': 'true',
    42                 'switch': 'http',
    43             }), {'force_smil_url': True}))
     32        return self.url_result(
     33            'https://feed.theplatform.com/f/BKQ29B/foxsports-all?byId=' + video_id, 'ThePlatformFeed')
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/generic.py

    r8096 r8258  
    4848from .rutv import RUTVIE
    4949from .tvc import TVCIE
    50 from .sportbox import SportBoxEmbedIE
     50from .sportbox import SportBoxIE
    5151from .smotri import SmotriIE
    5252from .myvi import MyviIE
     
    115115from .viqeo import ViqeoIE
    116116from .expressen import ExpressenIE
     117from .zype import ZypeIE
    117118
    118119
     
    20702071            },
    20712072            'playlist_count': 6,
     2073        },
     2074        {
     2075            # Zype embed
     2076            'url': 'https://www.cookscountry.com/episode/554-smoky-barbecue-favorites',
     2077            'info_dict': {
     2078                'id': '5b400b834b32992a310622b9',
     2079                'ext': 'mp4',
     2080                'title': 'Smoky Barbecue Favorites',
     2081                'thumbnail': r're:^https?://.*\.jpe?g',
     2082            },
     2083            'add_ie': [ZypeIE.ie_key()],
     2084            'params': {
     2085                'skip_download': True,
     2086            },
    20722087        },
    20732088        {
     
    26372652
    26382653        # Look for embedded SportBox player
    2639         sportbox_urls = SportBoxEmbedIE._extract_urls(webpage)
     2654        sportbox_urls = SportBoxIE._extract_urls(webpage)
    26402655        if sportbox_urls:
    2641             return self.playlist_from_matches(sportbox_urls, video_id, video_title, ie='SportBoxEmbed')
     2656            return self.playlist_from_matches(sportbox_urls, video_id, video_title, ie=SportBoxIE.ie_key())
    26422657
    26432658        # Look for embedded XHamster player
     
    30243039
    30253040        # Look for Mediaset embeds
    3026         mediaset_urls = MediasetIE._extract_urls(webpage)
     3041        mediaset_urls = MediasetIE._extract_urls(self, webpage)
    30273042        if mediaset_urls:
    30283043            return self.playlist_from_matches(
     
    31293144            return self.playlist_from_matches(
    31303145                expressen_urls, video_id, video_title, ie=ExpressenIE.ie_key())
     3146
     3147        zype_urls = ZypeIE._extract_urls(webpage)
     3148        if zype_urls:
     3149            return self.playlist_from_matches(
     3150                zype_urls, video_id, video_title, ie=ZypeIE.ie_key())
    31313151
    31323152        # Look for HTML5 media
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/hotstar.py

    r8096 r8258  
    22from __future__ import unicode_literals
    33
    4 import re
     4import hashlib
     5import hmac
     6import time
    57
    68from .common import InfoExtractor
    7 from ..compat import compat_str
     9from ..compat import compat_HTTPError
    810from ..utils import (
    911    determine_ext,
    1012    ExtractorError,
    1113    int_or_none,
     14    try_get,
    1215)
    1316
    1417
    1518class HotStarBaseIE(InfoExtractor):
    16     _GEO_COUNTRIES = ['IN']
     19    _AKAMAI_ENCRYPTION_KEY = b'\x05\xfc\x1a\x01\xca\xc9\x4b\xc4\x12\xfc\x53\x12\x07\x75\xf9\xee'
    1720
    18     def _download_json(self, *args, **kwargs):
    19         response = super(HotStarBaseIE, self)._download_json(*args, **kwargs)
    20         if response['resultCode'] != 'OK':
    21             if kwargs.get('fatal'):
    22                 raise ExtractorError(
    23                     response['errorDescription'], expected=True)
    24             return None
    25         return response['resultObj']
    26 
    27     def _download_content_info(self, content_id):
    28         return self._download_json(
    29             'https://account.hotstar.com/AVS/besc', content_id, query={
    30                 'action': 'GetAggregatedContentDetails',
    31                 'appVersion': '5.0.40',
    32                 'channel': 'PCTV',
    33                 'contentId': content_id,
    34             })['contentInfo'][0]
     21    def _call_api(self, path, video_id, query_name='contentId'):
     22        st = int(time.time())
     23        exp = st + 6000
     24        auth = 'st=%d~exp=%d~acl=/*' % (st, exp)
     25        auth += '~hmac=' + hmac.new(self._AKAMAI_ENCRYPTION_KEY, auth.encode(), hashlib.sha256).hexdigest()
     26        response = self._download_json(
     27            'https://api.hotstar.com/' + path,
     28            video_id, headers={
     29                'hotstarauth': auth,
     30                'x-country-code': 'IN',
     31                'x-platform-code': 'JIO',
     32            }, query={
     33                query_name: video_id,
     34                'tas': 10000,
     35            })
     36        if response['statusCode'] != 'OK':
     37            raise ExtractorError(
     38                response['body']['message'], expected=True)
     39        return response['body']['results']
    3540
    3641
    3742class HotStarIE(HotStarBaseIE):
     43    IE_NAME = 'hotstar'
    3844    _VALID_URL = r'https?://(?:www\.)?hotstar\.com/(?:.+?[/-])?(?P<id>\d{10})'
    3945    _TESTS = [{
    40         'url': 'http://www.hotstar.com/on-air-with-aib--english-1000076273',
     46        'url': 'https://www.hotstar.com/can-you-not-spread-rumours/1000076273',
    4147        'info_dict': {
    4248            'id': '1000076273',
    4349            'ext': 'mp4',
    44             'title': 'On Air With AIB',
     50            'title': 'Can You Not Spread Rumours?',
    4551            'description': 'md5:c957d8868e9bc793ccb813691cc4c434',
    46             'timestamp': 1447227000,
     52            'timestamp': 1447248600,
    4753            'upload_date': '20151111',
    4854            'duration': 381,
     
    5965        'only_matching': True,
    6066    }]
     67    _GEO_BYPASS = False
    6168
    6269    def _real_extract(self, url):
    6370        video_id = self._match_id(url)
    6471
    65         video_data = self._download_content_info(video_id)
     72        webpage = self._download_webpage(url, video_id)
     73        app_state = self._parse_json(self._search_regex(
     74            r'<script>window\.APP_STATE\s*=\s*({.+?})</script>',
     75            webpage, 'app state'), video_id)
     76        video_data = {}
     77        for v in app_state.values():
     78            content = try_get(v, lambda x: x['initialState']['contentData']['content'], dict)
     79            if content and content.get('contentId') == video_id:
     80                video_data = content
    6681
    67         title = video_data['episodeTitle']
     82        title = video_data['title']
    6883
    69         if video_data.get('encrypted') == 'Y':
     84        if video_data.get('drmProtected'):
    7085            raise ExtractorError('This video is DRM protected.', expected=True)
    7186
    7287        formats = []
    73         for f in ('JIO',):
    74             format_data = self._download_json(
    75                 'http://getcdn.hotstar.com/AVS/besc',
    76                 video_id, 'Downloading %s JSON metadata' % f,
    77                 fatal=False, query={
    78                     'action': 'GetCDN',
    79                     'asJson': 'Y',
    80                     'channel': f,
    81                     'id': video_id,
    82                     'type': 'VOD',
    83                 })
    84             if format_data:
    85                 format_url = format_data.get('src')
    86                 if not format_url:
    87                     continue
    88                 ext = determine_ext(format_url)
    89                 if ext == 'm3u8':
    90                     formats.extend(self._extract_m3u8_formats(
    91                         format_url, video_id, 'mp4',
    92                         m3u8_id='hls', fatal=False))
    93                 elif ext == 'f4m':
    94                     # produce broken files
    95                     continue
    96                 else:
    97                     formats.append({
    98                         'url': format_url,
    99                         'width': int_or_none(format_data.get('width')),
    100                         'height': int_or_none(format_data.get('height')),
    101                     })
     88        format_data = self._call_api('h/v1/play', video_id)['item']
     89        format_url = format_data['playbackUrl']
     90        ext = determine_ext(format_url)
     91        if ext == 'm3u8':
     92            try:
     93                formats.extend(self._extract_m3u8_formats(
     94                    format_url, video_id, 'mp4', m3u8_id='hls'))
     95            except ExtractorError as e:
     96                if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
     97                    self.raise_geo_restricted(countries=['IN'])
     98                raise
     99        elif ext == 'f4m':
     100            # produce broken files
     101            pass
     102        else:
     103            formats.append({
     104                'url': format_url,
     105                'width': int_or_none(format_data.get('width')),
     106                'height': int_or_none(format_data.get('height')),
     107            })
    102108        self._sort_formats(formats)
    103109
     
    107113            'description': video_data.get('description'),
    108114            'duration': int_or_none(video_data.get('duration')),
    109             'timestamp': int_or_none(video_data.get('broadcastDate')),
     115            'timestamp': int_or_none(video_data.get('broadcastDate') or video_data.get('startDate')),
    110116            'formats': formats,
     117            'channel': video_data.get('channelName'),
     118            'channel_id': video_data.get('channelId'),
     119            'series': video_data.get('showName'),
     120            'season': video_data.get('seasonName'),
     121            'season_number': int_or_none(video_data.get('seasonNo')),
     122            'season_id': video_data.get('seasonId'),
    111123            'episode': title,
    112             'episode_number': int_or_none(video_data.get('episodeNumber')),
    113             'series': video_data.get('contentTitle'),
     124            'episode_number': int_or_none(video_data.get('episodeNo')),
    114125        }
    115126
     
    117128class HotStarPlaylistIE(HotStarBaseIE):
    118129    IE_NAME = 'hotstar:playlist'
    119     _VALID_URL = r'(?P<url>https?://(?:www\.)?hotstar\.com/tv/[^/]+/(?P<content_id>\d+))/(?P<type>[^/]+)/(?P<id>\d+)'
     130    _VALID_URL = r'https?://(?:www\.)?hotstar\.com/tv/[^/]+/s-\w+/list/[^/]+/t-(?P<id>\w+)'
    120131    _TESTS = [{
    121         'url': 'http://www.hotstar.com/tv/pratidaan/14982/episodes/14812/9993',
     132        'url': 'https://www.hotstar.com/tv/savdhaan-india/s-26/list/popular-clips/t-3_2_26',
    122133        'info_dict': {
    123             'id': '14812',
     134            'id': '3_2_26',
    124135        },
    125         'playlist_mincount': 75,
     136        'playlist_mincount': 20,
    126137    }, {
    127         'url': 'http://www.hotstar.com/tv/pratidaan/14982/popular-clips/9998/9998',
     138        'url': 'https://www.hotstar.com/tv/savdhaan-india/s-26/list/extras/t-2480',
    128139        'only_matching': True,
    129140    }]
    130     _ITEM_TYPES = {
    131         'episodes': 'EPISODE',
    132         'popular-clips': 'CLIPS',
    133     }
    134141
    135142    def _real_extract(self, url):
    136         mobj = re.match(self._VALID_URL, url)
    137         base_url = mobj.group('url')
    138         content_id = mobj.group('content_id')
    139         playlist_type = mobj.group('type')
     143        playlist_id = self._match_id(url)
    140144
    141         content_info = self._download_content_info(content_id)
    142         playlist_id = compat_str(content_info['categoryId'])
    143 
    144         collection = self._download_json(
    145             'https://search.hotstar.com/AVS/besc', playlist_id, query={
    146                 'action': 'SearchContents',
    147                 'appVersion': '5.0.40',
    148                 'channel': 'PCTV',
    149                 'moreFilters': 'series:%s;' % playlist_id,
    150                 'query': '*',
    151                 'searchOrder': 'last_broadcast_date desc,year desc,title asc',
    152                 'type': self._ITEM_TYPES.get(playlist_type, 'EPISODE'),
    153             })
     145        collection = self._call_api('o/v1/tray/find', playlist_id, 'uqId')
    154146
    155147        entries = [
    156148            self.url_result(
    157                 '%s/_/%s' % (base_url, video['contentId']),
     149                'https://www.hotstar.com/%s' % video['contentId'],
    158150                ie=HotStarIE.ie_key(), video_id=video['contentId'])
    159             for video in collection['response']['docs']
     151            for video in collection['assets']['items']
    160152            if video.get('contentId')]
    161153
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/ivi.py

    r8096 r8258  
    1616    IE_DESC = 'ivi.ru'
    1717    IE_NAME = 'ivi'
    18     _VALID_URL = r'https?://(?:www\.)?ivi\.ru/(?:watch/(?:[^/]+/)?|video/player\?.*?videoId=)(?P<id>\d+)'
     18    _VALID_URL = r'https?://(?:www\.)?ivi\.(?:ru|tv)/(?:watch/(?:[^/]+/)?|video/player\?.*?videoId=)(?P<id>\d+)'
    1919    _GEO_BYPASS = False
    2020    _GEO_COUNTRIES = ['RU']
     
    6666            },
    6767            'skip': 'Only works from Russia',
    68         }
     68        },
     69        {
     70            'url': 'https://www.ivi.tv/watch/33560/',
     71            'only_matching': True,
     72        },
    6973    ]
    7074
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/jamendo.py

    r8096 r8258  
    2727
    2828class JamendoIE(JamendoBaseIE):
    29     _VALID_URL = r'https?://(?:www\.)?jamendo\.com/track/(?P<id>[0-9]+)/(?P<display_id>[^/?#&]+)'
    30     _TEST = {
     29    _VALID_URL = r'''(?x)
     30                    https?://
     31                        (?:
     32                            licensing\.jamendo\.com/[^/]+|
     33                            (?:www\.)?jamendo\.com
     34                        )
     35                        /track/(?P<id>[0-9]+)/(?P<display_id>[^/?#&]+)
     36                    '''
     37    _TESTS = [{
    3138        'url': 'https://www.jamendo.com/track/196219/stories-from-emona-i',
    3239        'md5': '6e9e82ed6db98678f171c25a8ed09ffd',
     
    4148            'thumbnail': r're:^https?://.*\.jpg'
    4249        }
    43     }
     50    }, {
     51        'url': 'https://licensing.jamendo.com/en/track/1496667/energetic-rock',
     52        'only_matching': True,
     53    }]
    4454
    4555    def _real_extract(self, url):
     
    4858        display_id = mobj.group('display_id')
    4959
    50         webpage = self._download_webpage(url, display_id)
     60        webpage = self._download_webpage(
     61            'https://www.jamendo.com/track/%s/%s' % (track_id, display_id),
     62            display_id)
    5163
    5264        title, artist, track = self._extract_meta(webpage)
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/kaltura.py

    r8096 r8258  
    193193                'service': 'baseentry',
    194194                'ks': '{1:result:ks}',
     195                'responseProfile:fields': 'createdAt,dataUrl,duration,name,plays,thumbnailUrl,userId',
     196                'responseProfile:type': 1,
    195197            },
    196198            {
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/laola1tv.py

    r8096 r8258  
    33
    44import json
     5import re
    56
    67from .common import InfoExtractor
     
    3334    def _extract_token_url(self, stream_access_url, video_id, data):
    3435        return self._download_json(
    35             stream_access_url, video_id, headers={
     36            self._proto_relative_url(stream_access_url, 'https:'), video_id,
     37            headers={
    3638                'Content-Type': 'application/json',
    3739            }, data=json.dumps(data).encode())['data']['stream-access'][0]
     
    120122
    121123
    122 class Laola1TvIE(Laola1TvEmbedIE):
    123     IE_NAME = 'laola1tv'
    124     _VALID_URL = r'https?://(?:www\.)?laola1\.tv/[a-z]+-[a-z]+/[^/]+/(?P<id>[^/?#&]+)'
    125     _TESTS = [{
    126         'url': 'http://www.laola1.tv/de-de/video/straubing-tigers-koelner-haie/227883.html',
    127         'info_dict': {
    128             'id': '227883',
    129             'display_id': 'straubing-tigers-koelner-haie',
    130             'ext': 'flv',
    131             'title': 'Straubing Tigers - Kölner Haie',
    132             'upload_date': '20140912',
    133             'is_live': False,
    134             'categories': ['Eishockey'],
    135         },
    136         'params': {
    137             'skip_download': True,
    138         },
    139     }, {
    140         'url': 'http://www.laola1.tv/de-de/video/straubing-tigers-koelner-haie',
    141         'info_dict': {
    142             'id': '464602',
    143             'display_id': 'straubing-tigers-koelner-haie',
    144             'ext': 'flv',
    145             'title': 'Straubing Tigers - Kölner Haie',
    146             'upload_date': '20160129',
    147             'is_live': False,
    148             'categories': ['Eishockey'],
    149         },
    150         'params': {
    151             'skip_download': True,
    152         },
    153     }, {
    154         'url': 'http://www.laola1.tv/de-de/livestream/2016-03-22-belogorie-belgorod-trentino-diatec-lde',
    155         'info_dict': {
    156             'id': '487850',
    157             'display_id': '2016-03-22-belogorie-belgorod-trentino-diatec-lde',
    158             'ext': 'flv',
    159             'title': 'Belogorie BELGOROD - TRENTINO Diatec',
    160             'upload_date': '20160322',
    161             'uploader': 'CEV - Europäischer Volleyball Verband',
    162             'is_live': True,
    163             'categories': ['Volleyball'],
    164         },
    165         'params': {
    166             'skip_download': True,
    167         },
    168         'skip': 'This live stream has already finished.',
    169     }]
    170 
    171     def _real_extract(self, url):
     124class Laola1TvBaseIE(Laola1TvEmbedIE):
     125    def _extract_video(self, url):
    172126        display_id = self._match_id(url)
    173 
    174127        webpage = self._download_webpage(url, display_id)
    175128
     
    179132        conf = self._parse_json(self._search_regex(
    180133            r'(?s)conf\s*=\s*({.+?});', webpage, 'conf'),
    181             display_id, js_to_json)
    182 
     134            display_id,
     135            transform_source=lambda s: js_to_json(re.sub(r'shareurl:.+,', '', s)))
    183136        video_id = conf['videoid']
    184137
     
    218171
    219172
     173class Laola1TvIE(Laola1TvBaseIE):
     174    IE_NAME = 'laola1tv'
     175    _VALID_URL = r'https?://(?:www\.)?laola1\.tv/[a-z]+-[a-z]+/[^/]+/(?P<id>[^/?#&]+)'
     176
     177    _TESTS = [{
     178        'url': 'http://www.laola1.tv/de-de/video/straubing-tigers-koelner-haie/227883.html',
     179        'info_dict': {
     180            'id': '227883',
     181            'display_id': 'straubing-tigers-koelner-haie',
     182            'ext': 'flv',
     183            'title': 'Straubing Tigers - Kölner Haie',
     184            'upload_date': '20140912',
     185            'is_live': False,
     186            'categories': ['Eishockey'],
     187        },
     188        'params': {
     189            'skip_download': True,
     190        },
     191    }, {
     192        'url': 'http://www.laola1.tv/de-de/video/straubing-tigers-koelner-haie',
     193        'info_dict': {
     194            'id': '464602',
     195            'display_id': 'straubing-tigers-koelner-haie',
     196            'ext': 'flv',
     197            'title': 'Straubing Tigers - Kölner Haie',
     198            'upload_date': '20160129',
     199            'is_live': False,
     200            'categories': ['Eishockey'],
     201        },
     202        'params': {
     203            'skip_download': True,
     204        },
     205    }, {
     206        'url': 'http://www.laola1.tv/de-de/livestream/2016-03-22-belogorie-belgorod-trentino-diatec-lde',
     207        'info_dict': {
     208            'id': '487850',
     209            'display_id': '2016-03-22-belogorie-belgorod-trentino-diatec-lde',
     210            'ext': 'flv',
     211            'title': 'Belogorie BELGOROD - TRENTINO Diatec',
     212            'upload_date': '20160322',
     213            'uploader': 'CEV - Europäischer Volleyball Verband',
     214            'is_live': True,
     215            'categories': ['Volleyball'],
     216        },
     217        'params': {
     218            'skip_download': True,
     219        },
     220        'skip': 'This live stream has already finished.',
     221    }]
     222
     223    def _real_extract(self, url):
     224        return self._extract_video(url)
     225
     226
     227class EHFTVIE(Laola1TvBaseIE):
     228    IE_NAME = 'ehftv'
     229    _VALID_URL = r'https?://(?:www\.)?ehftv\.com/[a-z]+(?:-[a-z]+)?/[^/]+/(?P<id>[^/?#&]+)'
     230
     231    _TESTS = [{
     232        'url': 'https://www.ehftv.com/int/video/paris-saint-germain-handball-pge-vive-kielce/1166761',
     233        'info_dict': {
     234            'id': '1166761',
     235            'display_id': 'paris-saint-germain-handball-pge-vive-kielce',
     236            'ext': 'mp4',
     237            'title': 'Paris Saint-Germain Handball - PGE Vive Kielce',
     238            'is_live': False,
     239            'categories': ['Handball'],
     240        },
     241        'params': {
     242            'skip_download': True,
     243        },
     244    }]
     245
     246    def _real_extract(self, url):
     247        return self._extract_video(url)
     248
     249
    220250class ITTFIE(InfoExtractor):
    221251    _VALID_URL = r'https?://tv\.ittf\.com/video/[^/]+/(?P<id>\d+)'
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/libraryofcongress.py

    r8096 r8258  
    1717    IE_NAME = 'loc'
    1818    IE_DESC = 'Library of Congress'
    19     _VALID_URL = r'https?://(?:www\.)?loc\.gov/(?:item/|today/cyberlc/feature_wdesc\.php\?.*\brec=)(?P<id>[0-9]+)'
     19    _VALID_URL = r'https?://(?:www\.)?loc\.gov/(?:item/|today/cyberlc/feature_wdesc\.php\?.*\brec=)(?P<id>[0-9a-z_.]+)'
    2020    _TESTS = [{
    2121        # embedded via <div class="media-player"
    2222        'url': 'http://loc.gov/item/90716351/',
    23         'md5': '353917ff7f0255aa6d4b80a034833de8',
     23        'md5': '6ec0ae8f07f86731b1b2ff70f046210a',
    2424        'info_dict': {
    2525            'id': '90716351',
    2626            'ext': 'mp4',
    2727            'title': "Pa's trip to Mars",
    28             'thumbnail': r're:^https?://.*\.jpg$',
    2928            'duration': 0,
    3029            'view_count': int,
     
    5857            'skip_download': True,
    5958        },
     59    }, {
     60        'url': 'https://www.loc.gov/item/ihas.200197114/',
     61        'only_matching': True,
     62    }, {
     63        'url': 'https://www.loc.gov/item/afc1981005_afs20503/',
     64        'only_matching': True,
    6065    }]
    6166
     
    6873             r'<video[^>]+id=(["\'])uuid-(?P<id>.+?)\1',
    6974             r'<video[^>]+data-uuid=(["\'])(?P<id>.+?)\1',
    70              r'mediaObjectId\s*:\s*(["\'])(?P<id>.+?)\1'),
     75             r'mediaObjectId\s*:\s*(["\'])(?P<id>.+?)\1',
     76             r'data-tab="share-media-(?P<id>[0-9A-F]{32})"'),
    7177            webpage, 'media id', group='id')
    7278
    7379        data = self._download_json(
    7480            'https://media.loc.gov/services/v1/media?id=%s&context=json' % media_id,
    75             video_id)['mediaObject']
     81            media_id)['mediaObject']
    7682
    7783        derivative = data['derivatives'][0]
     
    9096            media_url += '.mp4' if is_video else '.mp3'
    9197
    92         if 'vod/mp4:' in media_url:
    93             formats = [{
    94                 'url': media_url.replace('vod/mp4:', 'hls-vod/media/') + '.m3u8',
     98        formats = []
     99        if '/vod/mp4:' in media_url:
     100            formats.append({
     101                'url': media_url.replace('/vod/mp4:', '/hls-vod/media/') + '.m3u8',
    95102                'format_id': 'hls',
    96103                'ext': 'mp4',
    97104                'protocol': 'm3u8_native',
    98105                'quality': 1,
    99             }]
    100         elif 'vod/mp3:' in media_url:
    101             formats = [{
    102                 'url': media_url.replace('vod/mp3:', ''),
    103                 'vcodec': 'none',
    104             }]
     106            })
     107        http_format = {
     108            'url': re.sub(r'(://[^/]+/)(?:[^/]+/)*(?:mp4|mp3):', r'\1', media_url),
     109            'format_id': 'http',
     110            'quality': 1,
     111        }
     112        if not is_video:
     113            http_format['vcodec'] = 'none'
     114        formats.append(http_format)
    105115
    106116        download_urls = set()
     
    108118                r'<option[^>]+value=(["\'])(?P<url>.+?)\1[^>]+data-file-download=[^>]+>\s*(?P<id>.+?)(?:(?:&nbsp;|\s+)\((?P<size>.+?)\))?\s*<', webpage):
    109119            format_id = m.group('id').lower()
    110             if format_id == 'gif':
     120            if format_id in ('gif', 'jpeg'):
    111121                continue
    112122            download_url = m.group('url')
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/mediaset.py

    r8096 r8258  
    55
    66from .theplatform import ThePlatformBaseIE
     7from ..compat import (
     8    compat_parse_qs,
     9    compat_str,
     10    compat_urllib_parse_urlparse,
     11)
    712from ..utils import (
    813    ExtractorError,
     
    7782
    7883    @staticmethod
    79     def _extract_urls(webpage):
    80         return [
    81             mobj.group('url')
    82             for mobj in re.finditer(
    83                 r'<iframe\b[^>]+\bsrc=(["\'])(?P<url>https?://(?:www\.)?video\.mediaset\.it/player/playerIFrame(?:Twitter)?\.shtml\?.*?\bid=\d+.*?)\1',
    84                 webpage)]
     84    def _extract_urls(ie, webpage):
     85        def _qs(url):
     86            return compat_parse_qs(compat_urllib_parse_urlparse(url).query)
     87
     88        def _program_guid(qs):
     89            return qs.get('programGuid', [None])[0]
     90
     91        entries = []
     92        for mobj in re.finditer(
     93                r'<iframe\b[^>]+\bsrc=(["\'])(?P<url>(?:https?:)?//(?:www\.)?video\.mediaset\.it/player/playerIFrame(?:Twitter)?\.shtml.*?)\1',
     94                webpage):
     95            embed_url = mobj.group('url')
     96            embed_qs = _qs(embed_url)
     97            program_guid = _program_guid(embed_qs)
     98            if program_guid:
     99                entries.append(embed_url)
     100                continue
     101            video_id = embed_qs.get('id', [None])[0]
     102            if not video_id:
     103                continue
     104            urlh = ie._request_webpage(
     105                embed_url, video_id, note='Following embed URL redirect')
     106            embed_url = compat_str(urlh.geturl())
     107            program_guid = _program_guid(_qs(embed_url))
     108            if program_guid:
     109                entries.append(embed_url)
     110        return entries
    85111
    86112    def _real_extract(self, url):
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/mixcloud.py

    r8096 r8258  
    162162            formats = []
    163163
     164            def decrypt_url(f_url):
     165                for k in (key, 'IFYOUWANTTHEARTISTSTOGETPAIDDONOTDOWNLOADFROMMIXCLOUD'):
     166                    decrypted_url = self._decrypt_xor_cipher(k, f_url)
     167                    if re.search(r'^https?://[0-9a-z.]+/[0-9A-Za-z/.?=&_-]+$', decrypted_url):
     168                        return decrypted_url
     169
    164170            for url_key in ('url', 'hlsUrl', 'dashUrl'):
    165171                format_url = stream_info.get(url_key)
    166172                if not format_url:
    167173                    continue
    168                 decrypted = self._decrypt_xor_cipher(key, compat_b64decode(format_url))
     174                decrypted = decrypt_url(compat_b64decode(format_url))
    169175                if not decrypted:
    170176                    continue
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/nbc.py

    r8096 r8258  
    1010from ..compat import compat_urllib_parse_unquote
    1111from ..utils import (
    12     find_xpath_attr,
    1312    smuggle_url,
    1413    try_get,
    15     unescapeHTML,
    1614    update_url_query,
    1715    int_or_none,
     
    270268
    271269class NBCNewsIE(ThePlatformIE):
    272     _VALID_URL = r'''(?x)https?://(?:www\.)?(?:nbcnews|today|msnbc)\.com/
    273         (?:video/.+?/(?P<id>\d+)|
    274         ([^/]+/)*(?:.*-)?(?P<mpx_id>[^/?]+))
    275         '''
     270    _VALID_URL = r'(?x)https?://(?:www\.)?(?:nbcnews|today|msnbc)\.com/([^/]+/)*(?:.*-)?(?P<id>[^/?]+)'
    276271
    277272    _TESTS = [
    278         {
    279             'url': 'http://www.nbcnews.com/video/nbc-news/52753292',
    280             'md5': '47abaac93c6eaf9ad37ee6c4463a5179',
    281             'info_dict': {
    282                 'id': '52753292',
    283                 'ext': 'flv',
    284                 'title': 'Crew emerges after four-month Mars food study',
    285                 'description': 'md5:24e632ffac72b35f8b67a12d1b6ddfc1',
    286             },
    287         },
    288273        {
    289274            'url': 'http://www.nbcnews.com/watch/nbcnews-com/how-twitter-reacted-to-the-snowden-interview-269389891880',
    290275            'md5': 'af1adfa51312291a017720403826bb64',
    291276            'info_dict': {
    292                 'id': 'p_tweet_snow_140529',
     277                'id': '269389891880',
    293278                'ext': 'mp4',
    294279                'title': 'How Twitter Reacted To The Snowden Interview',
     
    314299            'md5': '73135a2e0ef819107bbb55a5a9b2a802',
    315300            'info_dict': {
    316                 'id': 'nn_netcast_150204',
     301                'id': '394064451844',
    317302                'ext': 'mp4',
    318303                'title': 'Nightly News with Brian Williams Full Broadcast (February 4)',
     
    327312            'md5': 'a49e173825e5fcd15c13fc297fced39d',
    328313            'info_dict': {
    329                 'id': 'x_lon_vwhorn_150922',
     314                'id': '529953347624',
    330315                'ext': 'mp4',
    331316                'title': 'Volkswagen U.S. Chief:\xa0 We Have Totally Screwed Up',
     
    340325            'md5': '118d7ca3f0bea6534f119c68ef539f71',
    341326            'info_dict': {
    342                 'id': 'tdy_al_space_160420',
     327                'id': '669831235788',
    343328                'ext': 'mp4',
    344329                'title': 'See the aurora borealis from space in stunning new NASA video',
     
    353338            'md5': '6d236bf4f3dddc226633ce6e2c3f814d',
    354339            'info_dict': {
    355                 'id': 'n_hayes_Aimm_140801_272214',
     340                'id': '314487875924',
    356341                'ext': 'mp4',
    357342                'title': 'The chaotic GOP immigration vote',
     
    375360
    376361    def _real_extract(self, url):
    377         mobj = re.match(self._VALID_URL, url)
    378         video_id = mobj.group('id')
    379         if video_id is not None:
    380             all_info = self._download_xml('http://www.nbcnews.com/id/%s/displaymode/1219' % video_id, video_id)
    381             info = all_info.find('video')
    382 
    383             return {
    384                 'id': video_id,
    385                 'title': info.find('headline').text,
    386                 'ext': 'flv',
    387                 'url': find_xpath_attr(info, 'media', 'type', 'flashVideo').text,
    388                 'description': info.find('caption').text,
    389                 'thumbnail': find_xpath_attr(info, 'media', 'type', 'thumbnail').text,
    390             }
    391         else:
    392             # "feature" and "nightly-news" pages use theplatform.com
    393             video_id = mobj.group('mpx_id')
     362        video_id = self._match_id(url)
     363        if not video_id.isdigit():
    394364            webpage = self._download_webpage(url, video_id)
    395365
    396             filter_param = 'byId'
    397             bootstrap_json = self._search_regex(
    398                 [r'(?m)(?:var\s+(?:bootstrapJson|playlistData)|NEWS\.videoObj)\s*=\s*({.+});?\s*$',
    399                  r'videoObj\s*:\s*({.+})', r'data-video="([^"]+)"',
    400                  r'jQuery\.extend\(Drupal\.settings\s*,\s*({.+?})\);'],
    401                 webpage, 'bootstrap json', default=None)
    402             if bootstrap_json:
    403                 bootstrap = self._parse_json(
    404                     bootstrap_json, video_id, transform_source=unescapeHTML)
    405 
    406                 info = None
    407                 if 'results' in bootstrap:
    408                     info = bootstrap['results'][0]['video']
    409                 elif 'video' in bootstrap:
    410                     info = bootstrap['video']
    411                 elif 'msnbcVideoInfo' in bootstrap:
    412                     info = bootstrap['msnbcVideoInfo']['meta']
    413                 elif 'msnbcThePlatform' in bootstrap:
    414                     info = bootstrap['msnbcThePlatform']['videoPlayer']['video']
    415                 else:
    416                     info = bootstrap
    417 
    418                 if 'guid' in info:
    419                     video_id = info['guid']
    420                     filter_param = 'byGuid'
    421                 elif 'mpxId' in info:
    422                     video_id = info['mpxId']
    423 
    424             return {
    425                 '_type': 'url_transparent',
    426                 'id': video_id,
    427                 # http://feed.theplatform.com/f/2E2eJC/nbcnews also works
    428                 'url': update_url_query('http://feed.theplatform.com/f/2E2eJC/nnd_NBCNews', {filter_param: video_id}),
    429                 'ie_key': 'ThePlatformFeed',
    430             }
     366            data = self._parse_json(self._search_regex(
     367                r'window\.__data\s*=\s*({.+});', webpage,
     368                'bootstrap json'), video_id)
     369            video_id = data['article']['content'][0]['primaryMedia']['video']['mpxMetadata']['id']
     370
     371        return {
     372            '_type': 'url_transparent',
     373            'id': video_id,
     374            # http://feed.theplatform.com/f/2E2eJC/nbcnews also works
     375            'url': update_url_query('http://feed.theplatform.com/f/2E2eJC/nnd_NBCNews', {'byId': video_id}),
     376            'ie_key': 'ThePlatformFeed',
     377        }
    431378
    432379
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/njpwworld.py

    r8096 r8258  
    3232    }
    3333
     34    _LOGIN_URL = 'https://front.njpwworld.com/auth/login'
     35
    3436    def _real_initialize(self):
    3537        self._login()
     
    4143            return True
    4244
     45        # Setup session (will set necessary cookies)
     46        self._request_webpage(
     47            'https://njpwworld.com/', None, note='Setting up session')
     48
    4349        webpage, urlh = self._download_webpage_handle(
    44             'https://njpwworld.com/auth/login', None,
     50            self._LOGIN_URL, None,
    4551            note='Logging in', errnote='Unable to login',
    4652            data=urlencode_postdata({'login_id': username, 'pw': password}),
    47             headers={'Referer': 'https://njpwworld.com/auth'})
     53            headers={'Referer': 'https://front.njpwworld.com/auth'})
    4854        # /auth/login will return 302 for successful logins
    49         if urlh.geturl() == 'https://njpwworld.com/auth/login':
     55        if urlh.geturl() == self._LOGIN_URL:
    5056            self.report_warning('unable to login')
    5157            return False
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/nova.py

    r8096 r8258  
    3636        bitrates = self._parse_json(
    3737            self._search_regex(
    38                 r'(?s)bitrates\s*=\s*({.+?})\s*;', webpage, 'formats'),
     38                r'(?s)(?:src|bitrates)\s*=\s*({.+?})\s*;', webpage, 'formats'),
    3939            video_id, transform_source=js_to_json)
    4040
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/nzz.py

    r8096 r8258  
    1212class NZZIE(InfoExtractor):
    1313    _VALID_URL = r'https?://(?:www\.)?nzz\.ch/(?:[^/]+/)*[^/?#]+-ld\.(?P<id>\d+)'
    14     _TEST = {
     14    _TESTS = [{
    1515        'url': 'http://www.nzz.ch/zuerich/gymizyte/gymizyte-schreiben-schueler-heute-noch-diktate-ld.9153',
    1616        'info_dict': {
     
    1818        },
    1919        'playlist_mincount': 6,
    20     }
     20    }, {
     21        'url': 'https://www.nzz.ch/video/nzz-standpunkte/cvp-auf-der-suche-nach-dem-mass-der-mitte-ld.1368112',
     22        'info_dict': {
     23            'id': '1368112',
     24        },
     25        'playlist_count': 1,
     26    }]
    2127
    2228    def _real_extract(self, url):
     
    2531
    2632        entries = []
    27         for player_element in re.findall(r'(<[^>]+class="kalturaPlayer"[^>]*>)', webpage):
     33        for player_element in re.findall(
     34                r'(<[^>]+class="kalturaPlayer[^"]*"[^>]*>)', webpage):
    2835            player_params = extract_attributes(player_element)
    2936            if player_params.get('data-type') not in ('kaltura_singleArticle',):
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/openload.py

    r8096 r8258  
    244244
    245245class OpenloadIE(InfoExtractor):
    246     _VALID_URL = r'https?://(?:www\.)?(?:openload\.(?:co|io|link)|oload\.(?:tv|stream|site|xyz|win|download))/(?:f|embed)/(?P<id>[a-zA-Z0-9-_]+)'
     246    _VALID_URL = r'''(?x)
     247                    https?://
     248                        (?P<host>
     249                            (?:www\.)?
     250                            (?:
     251                                openload\.(?:co|io|link)|
     252                                oload\.(?:tv|stream|site|xyz|win|download|cloud|cc|icu|fun)
     253                            )
     254                        )/
     255                        (?:f|embed)/
     256                        (?P<id>[a-zA-Z0-9-_]+)
     257                    '''
    247258
    248259    _TESTS = [{
     
    309320        'only_matching': True,
    310321    }, {
     322        'url': 'https://oload.cloud/f/4ZDnBXRWiB8',
     323        'only_matching': True,
     324    }, {
    311325        # Its title has not got its extension but url has it
    312326        'url': 'https://oload.download/f/N4Otkw39VCw/Tomb.Raider.2018.HDRip.XviD.AC3-EVO.avi.mp4',
     327        'only_matching': True,
     328    }, {
     329        'url': 'https://oload.cc/embed/5NEAbI2BDSk',
     330        'only_matching': True,
     331    }, {
     332        'url': 'https://oload.icu/f/-_i4y_F_Hs8',
     333        'only_matching': True,
     334    }, {
     335        'url': 'https://oload.fun/f/gb6G1H4sHXY',
    313336        'only_matching': True,
    314337    }]
     
    323346
    324347    def _real_extract(self, url):
    325         video_id = self._match_id(url)
    326         url_pattern = 'https://openload.co/%%s/%s/' % video_id
     348        mobj = re.match(self._VALID_URL, url)
     349        host = mobj.group('host')
     350        video_id = mobj.group('id')
     351
     352        url_pattern = 'https://%s/%%s/%s/' % (host, video_id)
    327353        headers = {
    328354            'User-Agent': self._USER_AGENT,
     
    357383                          'stream URL'))
    358384
    359         video_url = 'https://openload.co/stream/%s?mime=true' % decoded_id
     385        video_url = 'https://%s/stream/%s?mime=true' % (host, decoded_id)
    360386
    361387        title = self._og_search_title(webpage, default=None) or self._search_regex(
     
    368394        subtitles = entry.get('subtitles')
    369395
    370         info_dict = {
     396        return {
    371397            'id': video_id,
    372398            'title': title,
     
    377403            'http_headers': headers,
    378404        }
    379         return info_dict
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/orf.py

    r8096 r8258  
    1616    unescapeHTML,
    1717    unified_strdate,
     18    url_or_none,
    1819)
    1920
     
    6970            playlist_id, transform_source=unescapeHTML)['playlist']['videos']
    7071
    71         def quality_to_int(s):
    72             m = re.search('([0-9]+)', s)
    73             if m is None:
    74                 return -1
    75             return int(m.group(1))
    76 
    7772        entries = []
    7873        for sd in data_jsb:
     
    8176                continue
    8277            video_id = compat_str(video_id)
    83             formats = [{
    84                 'preference': -10 if fd['delivery'] == 'hls' else None,
    85                 'format_id': '%s-%s-%s' % (
    86                     fd['delivery'], fd['quality'], fd['quality_string']),
    87                 'url': fd['src'],
    88                 'protocol': fd['protocol'],
    89                 'quality': quality_to_int(fd['quality']),
    90             } for fd in sd['sources']]
     78            formats = []
     79            for fd in sd['sources']:
     80                src = url_or_none(fd.get('src'))
     81                if not src:
     82                    continue
     83                format_id_list = []
     84                for key in ('delivery', 'quality', 'quality_string'):
     85                    value = fd.get(key)
     86                    if value:
     87                        format_id_list.append(value)
     88                format_id = '-'.join(format_id_list)
     89                if determine_ext(fd['src']) == 'm3u8':
     90                    formats.extend(self._extract_m3u8_formats(
     91                        fd['src'], video_id, 'mp4', m3u8_id=format_id))
     92                elif determine_ext(fd['src']) == 'f4m':
     93                    formats.extend(self._extract_f4m_formats(
     94                        fd['src'], video_id, f4m_id=format_id))
     95                else:
     96                    formats.append({
     97                        'format_id': format_id,
     98                        'url': src,
     99                        'protocol': fd.get('protocol'),
     100                    })
    91101
    92102            # Check for geoblocking.
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/patreon.py

    r8096 r8258  
    33
    44from .common import InfoExtractor
    5 from ..utils import js_to_json
     5from ..utils import (
     6    clean_html,
     7    determine_ext,
     8    int_or_none,
     9    parse_iso8601,
     10)
    611
    712
    813class PatreonIE(InfoExtractor):
    9     _VALID_URL = r'https?://(?:www\.)?patreon\.com/creation\?hid=(?P<id>[^&#]+)'
    10     _TESTS = [
    11         {
    12             'url': 'http://www.patreon.com/creation?hid=743933',
    13             'md5': 'e25505eec1053a6e6813b8ed369875cc',
    14             'info_dict': {
    15                 'id': '743933',
    16                 'ext': 'mp3',
    17                 'title': 'Episode 166: David Smalley of Dogma Debate',
    18                 'uploader': 'Cognitive Dissonance Podcast',
    19                 'thumbnail': 're:^https?://.*$',
    20             },
     14    _VALID_URL = r'https?://(?:www\.)?patreon\.com/(?:creation\?hid=|posts/(?:[\w-]+-)?)(?P<id>\d+)'
     15    _TESTS = [{
     16        'url': 'http://www.patreon.com/creation?hid=743933',
     17        'md5': 'e25505eec1053a6e6813b8ed369875cc',
     18        'info_dict': {
     19            'id': '743933',
     20            'ext': 'mp3',
     21            'title': 'Episode 166: David Smalley of Dogma Debate',
     22            'description': 'md5:713b08b772cd6271b9f3906683cfacdf',
     23            'uploader': 'Cognitive Dissonance Podcast',
     24            'thumbnail': 're:^https?://.*$',
     25            'timestamp': 1406473987,
     26            'upload_date': '20140727',
    2127        },
    22         {
    23             'url': 'http://www.patreon.com/creation?hid=754133',
    24             'md5': '3eb09345bf44bf60451b8b0b81759d0a',
    25             'info_dict': {
    26                 'id': '754133',
    27                 'ext': 'mp3',
    28                 'title': 'CD 167 Extra',
    29                 'uploader': 'Cognitive Dissonance Podcast',
    30                 'thumbnail': 're:^https?://.*$',
    31             },
     28    }, {
     29        'url': 'http://www.patreon.com/creation?hid=754133',
     30        'md5': '3eb09345bf44bf60451b8b0b81759d0a',
     31        'info_dict': {
     32            'id': '754133',
     33            'ext': 'mp3',
     34            'title': 'CD 167 Extra',
     35            'uploader': 'Cognitive Dissonance Podcast',
     36            'thumbnail': 're:^https?://.*$',
    3237        },
    33         {
    34             'url': 'https://www.patreon.com/creation?hid=1682498',
    35             'info_dict': {
    36                 'id': 'SU4fj_aEMVw',
    37                 'ext': 'mp4',
    38                 'title': 'I\'m on Patreon!',
    39                 'uploader': 'TraciJHines',
    40                 'thumbnail': 're:^https?://.*$',
    41                 'upload_date': '20150211',
    42                 'description': 'md5:c5a706b1f687817a3de09db1eb93acd4',
    43                 'uploader_id': 'TraciJHines',
    44             },
    45             'params': {
    46                 'noplaylist': True,
    47                 'skip_download': True,
    48             }
     38        'skip': 'Patron-only content',
     39    }, {
     40        'url': 'https://www.patreon.com/creation?hid=1682498',
     41        'info_dict': {
     42            'id': 'SU4fj_aEMVw',
     43            'ext': 'mp4',
     44            'title': 'I\'m on Patreon!',
     45            'uploader': 'TraciJHines',
     46            'thumbnail': 're:^https?://.*$',
     47            'upload_date': '20150211',
     48            'description': 'md5:c5a706b1f687817a3de09db1eb93acd4',
     49            'uploader_id': 'TraciJHines',
     50        },
     51        'params': {
     52            'noplaylist': True,
     53            'skip_download': True,
    4954        }
    50     ]
     55    }, {
     56        'url': 'https://www.patreon.com/posts/episode-166-of-743933',
     57        'only_matching': True,
     58    }, {
     59        'url': 'https://www.patreon.com/posts/743933',
     60        'only_matching': True,
     61    }]
    5162
    5263    # Currently Patreon exposes download URL via hidden CSS, so login is not
     
    7990    def _real_extract(self, url):
    8091        video_id = self._match_id(url)
    81         webpage = self._download_webpage(url, video_id)
    82         title = self._og_search_title(webpage).strip()
     92        post = self._download_json(
     93            'https://www.patreon.com/api/posts/' + video_id, video_id)
     94        attributes = post['data']['attributes']
     95        title = attributes['title'].strip()
     96        image = attributes.get('image') or {}
     97        info = {
     98            'id': video_id,
     99            'title': title,
     100            'description': clean_html(attributes.get('content')),
     101            'thumbnail': image.get('large_url') or image.get('url'),
     102            'timestamp': parse_iso8601(attributes.get('published_at')),
     103            'like_count': int_or_none(attributes.get('like_count')),
     104            'comment_count': int_or_none(attributes.get('comment_count')),
     105        }
    83106
    84         attach_fn = self._html_search_regex(
    85             r'<div class="attach"><a target="_blank" href="([^"]+)">',
    86             webpage, 'attachment URL', default=None)
    87         embed = self._html_search_regex(
    88             r'<div[^>]+id="watchCreation"[^>]*>\s*<iframe[^>]+src="([^"]+)"',
    89             webpage, 'embedded URL', default=None)
     107        def add_file(file_data):
     108            file_url = file_data.get('url')
     109            if file_url:
     110                info.update({
     111                    'url': file_url,
     112                    'ext': determine_ext(file_data.get('name'), 'mp3'),
     113                })
    90114
    91         if attach_fn is not None:
    92             video_url = 'http://www.patreon.com' + attach_fn
    93             thumbnail = self._og_search_thumbnail(webpage)
    94             uploader = self._html_search_regex(
    95                 r'<strong>(.*?)</strong> is creating', webpage, 'uploader')
    96         elif embed is not None:
    97             return self.url_result(embed)
    98         else:
    99             playlist = self._parse_json(self._search_regex(
    100                 r'(?s)new\s+jPlayerPlaylist\(\s*\{\s*[^}]*},\s*(\[.*?,?\s*\])',
    101                 webpage, 'playlist JSON'),
    102                 video_id, transform_source=js_to_json)
    103             data = playlist[0]
    104             video_url = self._proto_relative_url(data['mp3'])
    105             thumbnail = self._proto_relative_url(data.get('cover'))
    106             uploader = data.get('artist')
     115        for i in post.get('included', []):
     116            i_type = i.get('type')
     117            if i_type == 'attachment':
     118                add_file(i.get('attributes') or {})
     119            elif i_type == 'user':
     120                user_attributes = i.get('attributes')
     121                if user_attributes:
     122                    info.update({
     123                        'uploader': user_attributes.get('full_name'),
     124                        'uploader_url': user_attributes.get('url'),
     125                    })
    107126
    108         return {
    109             'id': video_id,
    110             'url': video_url,
    111             'ext': 'mp3',
    112             'title': title,
    113             'uploader': uploader,
    114             'thumbnail': thumbnail,
    115         }
     127        if not info.get('url'):
     128            add_file(attributes.get('post_file') or {})
     129
     130        if not info.get('url'):
     131            info.update({
     132                '_type': 'url',
     133                'url': attributes['embed']['url'],
     134            })
     135
     136        return info
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/philharmoniedeparis.py

    r8096 r8258  
    33
    44from .common import InfoExtractor
     5from ..compat import compat_str
    56from ..utils import (
    6     float_or_none,
    7     int_or_none,
    8     parse_iso8601,
    9     xpath_text,
     7    try_get,
     8    urljoin,
    109)
    1110
     
    1312class PhilharmonieDeParisIE(InfoExtractor):
    1413    IE_DESC = 'Philharmonie de Paris'
    15     _VALID_URL = r'https?://live\.philharmoniedeparis\.fr/(?:[Cc]oncert/|misc/Playlist\.ashx\?id=)(?P<id>\d+)'
     14    _VALID_URL = r'''(?x)
     15                    https?://
     16                        (?:
     17                            live\.philharmoniedeparis\.fr/(?:[Cc]oncert/|misc/Playlist\.ashx\?id=)|
     18                            pad\.philharmoniedeparis\.fr/doc/CIMU/
     19                        )
     20                        (?P<id>\d+)
     21                    '''
    1622    _TESTS = [{
     23        'url': 'http://pad.philharmoniedeparis.fr/doc/CIMU/1086697/jazz-a-la-villette-knower',
     24        'md5': 'a0a4b195f544645073631cbec166a2c2',
     25        'info_dict': {
     26            'id': '1086697',
     27            'ext': 'mp4',
     28            'title': 'Jazz à la Villette : Knower',
     29        },
     30    }, {
    1731        'url': 'http://live.philharmoniedeparis.fr/concert/1032066.html',
    1832        'info_dict': {
    1933            'id': '1032066',
    20             'ext': 'flv',
    21             'title': 'md5:d1f5585d87d041d07ce9434804bc8425',
    22             'timestamp': 1428179400,
    23             'upload_date': '20150404',
    24             'duration': 6592.278,
     34            'title': 'md5:0a031b81807b3593cffa3c9a87a167a0',
    2535        },
    26         'params': {
    27             # rtmp download
    28             'skip_download': True,
    29         }
     36        'playlist_mincount': 2,
    3037    }, {
    3138        'url': 'http://live.philharmoniedeparis.fr/Concert/1030324.html',
     
    3542        'only_matching': True,
    3643    }]
     44    _LIVE_URL = 'https://live.philharmoniedeparis.fr'
    3745
    3846    def _real_extract(self, url):
    3947        video_id = self._match_id(url)
    4048
    41         concert = self._download_xml(
    42             'http://live.philharmoniedeparis.fr/misc/Playlist.ashx?id=%s' % video_id,
    43             video_id).find('./concert')
     49        config = self._download_json(
     50            '%s/otoPlayer/config.ashx' % self._LIVE_URL, video_id, query={
     51                'id': video_id,
     52                'lang': 'fr-FR',
     53            })
    4454
    45         formats = []
    46         info_dict = {
    47             'id': video_id,
    48             'title': xpath_text(concert, './titre', 'title', fatal=True),
    49             'formats': formats,
    50         }
     55        def extract_entry(source):
     56            if not isinstance(source, dict):
     57                return
     58            title = source.get('title')
     59            if not title:
     60                return
     61            files = source.get('files')
     62            if not isinstance(files, dict):
     63                return
     64            format_urls = set()
     65            formats = []
     66            for format_id in ('mobile', 'desktop'):
     67                format_url = try_get(
     68                    files, lambda x: x[format_id]['file'], compat_str)
     69                if not format_url or format_url in format_urls:
     70                    continue
     71                format_urls.add(format_url)
     72                m3u8_url = urljoin(self._LIVE_URL, format_url)
     73                formats.extend(self._extract_m3u8_formats(
     74                    m3u8_url, video_id, 'mp4', entry_protocol='m3u8_native',
     75                    m3u8_id='hls', fatal=False))
     76            if not formats:
     77                return
     78            self._sort_formats(formats)
     79            return {
     80                'title': title,
     81                'formats': formats,
     82            }
    5183
    52         fichiers = concert.find('./fichiers')
    53         stream = fichiers.attrib['serveurstream']
    54         for fichier in fichiers.findall('./fichier'):
    55             info_dict['duration'] = float_or_none(fichier.get('timecodefin'))
    56             for quality, (format_id, suffix) in enumerate([('lq', ''), ('hq', '_hd')]):
    57                 format_url = fichier.get('url%s' % suffix)
    58                 if not format_url:
    59                     continue
    60                 formats.append({
    61                     'url': stream,
    62                     'play_path': format_url,
    63                     'ext': 'flv',
    64                     'format_id': format_id,
    65                     'width': int_or_none(concert.get('largeur%s' % suffix)),
    66                     'height': int_or_none(concert.get('hauteur%s' % suffix)),
    67                     'quality': quality,
    68                 })
    69         self._sort_formats(formats)
     84        thumbnail = urljoin(self._LIVE_URL, config.get('image'))
    7085
    71         date, hour = concert.get('date'), concert.get('heure')
    72         if date and hour:
    73             info_dict['timestamp'] = parse_iso8601(
    74                 '%s-%s-%sT%s:00' % (date[0:4], date[4:6], date[6:8], hour))
    75         elif date:
    76             info_dict['upload_date'] = date
     86        info = extract_entry(config)
     87        if info:
     88            info.update({
     89                'id': video_id,
     90                'thumbnail': thumbnail,
     91            })
     92            return info
    7793
    78         return info_dict
     94        entries = []
     95        for num, chapter in enumerate(config['chapters'], start=1):
     96            entry = extract_entry(chapter)
     97            entry['id'] = '%s-%d' % (video_id, num)
     98            entries.append(entry)
     99
     100        return self.playlist_result(entries, video_id, config.get('title'))
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/picarto.py

    r8096 r8258  
    22from __future__ import unicode_literals
    33
     4import re
    45import time
    56
     
    1617
    1718class PicartoIE(InfoExtractor):
    18     _VALID_URL = r'https?://(?:www.)?picarto\.tv/(?P<id>[a-zA-Z0-9]+)'
     19    _VALID_URL = r'https?://(?:www.)?picarto\.tv/(?P<id>[a-zA-Z0-9]+)(?:/(?P<token>[a-zA-Z0-9]+))?'
    1920    _TEST = {
    2021        'url': 'https://picarto.tv/Setz',
     
    3435
    3536    def _real_extract(self, url):
    36         channel_id = self._match_id(url)
    37         stream_page = self._download_webpage(url, channel_id)
     37        mobj = re.match(self._VALID_URL, url)
     38        channel_id = mobj.group('id')
    3839
    39         if '>This channel does not exist' in stream_page:
    40             raise ExtractorError(
    41                 'Channel %s does not exist' % channel_id, expected=True)
     40        metadata = self._download_json(
     41            'https://api.picarto.tv/v1/channel/name/' + channel_id,
     42            channel_id)
    4243
    43         player = self._parse_json(
    44             self._search_regex(
    45                 r'(?s)playerSettings\[\d+\]\s*=\s*(\{.+?\}\s*\n)', stream_page,
    46                 'player settings'),
    47             channel_id, transform_source=js_to_json)
    48 
    49         if player.get('online') is False:
     44        if metadata.get('online') is False:
    5045            raise ExtractorError('Stream is offline', expected=True)
    5146
     
    5550            note='Downloading load balancing info')
    5651
    57         def get_event(key):
    58             return try_get(player, lambda x: x['event'][key], compat_str) or ''
    59 
     52        token = mobj.group('token') or 'public'
    6053        params = {
    61             'token': player.get('token') or '',
    62             'ticket': get_event('ticket'),
    6354            'con': int(time.time() * 1000),
    64             'type': get_event('ticket'),
    65             'scope': get_event('scope'),
     55            'token': token,
    6656        }
    6757
    6858        prefered_edge = cdn_data.get('preferedEdge')
    69         default_tech = player.get('defaultTech')
    70 
    7159        formats = []
    7260
     
    8169                preference = 0
    8270                if edge_id == prefered_edge:
    83                     preference += 1
    84                 if tech_type == default_tech:
    8571                    preference += 1
    8672                format_id = []
     
    11096        self._sort_formats(formats)
    11197
    112         mature = player.get('mature')
     98        mature = metadata.get('adult')
    11399        if mature is None:
    114100            age_limit = None
     
    118104        return {
    119105            'id': channel_id,
    120             'title': self._live_title(channel_id),
     106            'title': self._live_title(metadata.get('title') or channel_id),
    121107            'is_live': True,
    122             'thumbnail': player.get('vodThumb'),
     108            'thumbnail': try_get(metadata, lambda x: x['thumbnails']['web']),
     109            'channel': channel_id,
     110            'channel_url': 'https://picarto.tv/%s' % channel_id,
    123111            'age_limit': age_limit,
    124112            'formats': formats,
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/pluralsight.py

    r8096 r8258  
    55import os
    66import random
     7import re
    78
    89from .common import InfoExtractor
     
    197198            raise ExtractorError('Unable to login: %s' % error, expected=True)
    198199
    199         if all(p not in response for p in ('__INITIAL_STATE__', '"currentUser"')):
     200        if all(not re.search(p, response) for p in (
     201                r'__INITIAL_STATE__', r'["\']currentUser["\']',
     202                # new layout?
     203                r'>\s*Sign out\s*<')):
    200204            BLOCKED = 'Your account has been blocked due to suspicious activity'
    201205            if BLOCKED in response:
     
    211215            raise ExtractorError('Unable to log in')
    212216
    213     def _get_subtitles(self, author, clip_idx, lang, name, duration, video_id):
    214         captions_post = {
    215             'a': author,
    216             'cn': clip_idx,
    217             'lc': lang,
    218             'm': name,
    219         }
    220         captions = self._download_json(
    221             '%s/player/retrieve-captions' % self._API_BASE, video_id,
    222             'Downloading captions JSON', 'Unable to download captions JSON',
    223             fatal=False, data=json.dumps(captions_post).encode('utf-8'),
    224             headers={'Content-Type': 'application/json;charset=utf-8'})
     217    def _get_subtitles(self, author, clip_idx, clip_id, lang, name, duration, video_id):
     218        captions = None
     219        if clip_id:
     220            captions = self._download_json(
     221                '%s/transcript/api/v1/caption/json/%s/%s'
     222                % (self._API_BASE, clip_id, lang), video_id,
     223                'Downloading captions JSON', 'Unable to download captions JSON',
     224                fatal=False)
     225        if not captions:
     226            captions_post = {
     227                'a': author,
     228                'cn': int(clip_idx),
     229                'lc': lang,
     230                'm': name,
     231            }
     232            captions = self._download_json(
     233                '%s/player/retrieve-captions' % self._API_BASE, video_id,
     234                'Downloading captions JSON', 'Unable to download captions JSON',
     235                fatal=False, data=json.dumps(captions_post).encode('utf-8'),
     236                headers={'Content-Type': 'application/json;charset=utf-8'})
    225237        if captions:
    226238            return {
     
    414426        # TODO: other languages?
    415427        subtitles = self.extract_subtitles(
    416             author, clip_idx, 'en', name, duration, display_id)
     428            author, clip_idx, clip.get('clipId'), 'en', name, duration, display_id)
    417429
    418430        return {
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/popcorntv.py

    r8096 r8258  
    5959        timestamp = unified_timestamp(self._html_search_meta(
    6060            'uploadDate', webpage, 'timestamp'))
    61         print(self._html_search_meta(
    62             'duration', webpage))
    6361        duration = int_or_none(self._html_search_meta(
    6462            'duration', webpage), invscale=60)
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/pornhub.py

    r8096 r8258  
    2828                    https?://
    2929                        (?:
    30                             (?:[^/]+\.)?pornhub\.com/(?:(?:view_video\.php|video/show)\?viewkey=|embed/)|
     30                            (?:[^/]+\.)?pornhub\.(?:com|net)/(?:(?:view_video\.php|video/show)\?viewkey=|embed/)|
    3131                            (?:www\.)?thumbzilla\.com/video/
    3232                        )
     
    4141            'title': 'Seductive Indian beauty strips down and fingers her pink pussy',
    4242            'uploader': 'Babes',
     43            'upload_date': '20130628',
    4344            'duration': 361,
    4445            'view_count': int,
     
    5859            'title': '重庆婷婷女王足交',
    5960            'uploader': 'Unknown',
     61            'upload_date': '20150213',
    6062            'duration': 1753,
    6163            'view_count': int,
     
    119121    }, {
    120122        'url': 'http://www.pornhub.com/video/show?viewkey=648719015',
     123        'only_matching': True,
     124    }, {
     125        'url': 'https://www.pornhub.net/view_video.php?viewkey=203640933',
    121126        'only_matching': True,
    122127    }]
     
    238243                video_urls_set.add(video_url)
    239244
     245        upload_date = None
    240246        formats = []
    241247        for video_url, height in video_urls:
     248            if not upload_date:
     249                upload_date = self._search_regex(
     250                    r'/(\d{6}/\d{2})/', video_url, 'upload data', default=None)
     251                if upload_date:
     252                    upload_date = upload_date.replace('/', '')
    242253            tbr = None
    243254            mobj = re.search(r'(?P<height>\d+)[pP]?_(?P<tbr>\d+)[kK]', video_url)
     
    279290            'id': video_id,
    280291            'uploader': video_uploader,
     292            'upload_date': upload_date,
    281293            'title': title,
    282294            'thumbnail': thumbnail,
     
    332344
    333345class PornHubPlaylistIE(PornHubPlaylistBaseIE):
    334     _VALID_URL = r'https?://(?:[^/]+\.)?pornhub\.com/playlist/(?P<id>\d+)'
     346    _VALID_URL = r'https?://(?:[^/]+\.)?pornhub\.(?:com|net)/playlist/(?P<id>\d+)'
    335347    _TESTS = [{
    336348        'url': 'http://www.pornhub.com/playlist/4667351',
     
    347359
    348360class PornHubUserVideosIE(PornHubPlaylistBaseIE):
    349     _VALID_URL = r'https?://(?:[^/]+\.)?pornhub\.com/(?:(?:user|channel)s|model|pornstar)/(?P<id>[^/]+)/videos'
     361    _VALID_URL = r'https?://(?:[^/]+\.)?pornhub\.(?:com|net)/(?:(?:user|channel)s|model|pornstar)/(?P<id>[^/]+)/videos'
    350362    _TESTS = [{
    351363        'url': 'http://www.pornhub.com/users/zoe_ph/videos/public',
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/rai.py

    r8096 r8258  
    275275        description = unescapeHTML(self._html_search_meta(
    276276            ('description', 'og:description'), webpage, 'description'))
    277         print(description)
    278277
    279278        entries = []
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/rte.py

    r8096 r8258  
    99    float_or_none,
    1010    parse_iso8601,
     11    str_or_none,
     12    try_get,
    1113    unescapeHTML,
     14    url_or_none,
    1215    ExtractorError,
    1316)
     
    1821        item_id = self._match_id(url)
    1922
    20         try:
    21             json_string = self._download_json(
    22                 'http://www.rte.ie/rteavgen/getplaylist/?type=web&format=json&id=' + item_id,
    23                 item_id)
    24         except ExtractorError as ee:
    25             if isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 404:
    26                 error_info = self._parse_json(ee.cause.read().decode(), item_id, fatal=False)
    27                 if error_info:
    28                     raise ExtractorError(
    29                         '%s said: %s' % (self.IE_NAME, error_info['message']),
    30                         expected=True)
    31             raise
    32 
    33         # NB the string values in the JSON are stored using XML escaping(!)
    34         show = json_string['shows'][0]
    35         title = unescapeHTML(show['title'])
    36         description = unescapeHTML(show.get('description'))
    37         thumbnail = show.get('thumbnail')
    38         duration = float_or_none(show.get('duration'), 1000)
    39         timestamp = parse_iso8601(show.get('published'))
    40 
    41         mg = show['media:group'][0]
    42 
     23        info_dict = {}
    4324        formats = []
    4425
    45         if mg.get('url'):
    46             m = re.match(r'(?P<url>rtmpe?://[^/]+)/(?P<app>.+)/(?P<playpath>mp4:.*)', mg['url'])
    47             if m:
    48                 m = m.groupdict()
    49                 formats.append({
    50                     'url': m['url'] + '/' + m['app'],
    51                     'app': m['app'],
    52                     'play_path': m['playpath'],
    53                     'player_url': url,
    54                     'ext': 'flv',
    55                     'format_id': 'rtmp',
    56                 })
     26        ENDPOINTS = (
     27            'https://feeds.rasset.ie/rteavgen/player/playlist?type=iptv&format=json&showId=',
     28            'http://www.rte.ie/rteavgen/getplaylist/?type=web&format=json&id=',
     29        )
    5730
    58         if mg.get('hls_server') and mg.get('hls_url'):
    59             formats.extend(self._extract_m3u8_formats(
    60                 mg['hls_server'] + mg['hls_url'], item_id, 'mp4',
    61                 entry_protocol='m3u8_native', m3u8_id='hls', fatal=False))
     31        for num, ep_url in enumerate(ENDPOINTS, start=1):
     32            try:
     33                data = self._download_json(ep_url + item_id, item_id)
     34            except ExtractorError as ee:
     35                if num < len(ENDPOINTS) or formats:
     36                    continue
     37                if isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 404:
     38                    error_info = self._parse_json(ee.cause.read().decode(), item_id, fatal=False)
     39                    if error_info:
     40                        raise ExtractorError(
     41                            '%s said: %s' % (self.IE_NAME, error_info['message']),
     42                            expected=True)
     43                raise
    6244
    63         if mg.get('hds_server') and mg.get('hds_url'):
    64             formats.extend(self._extract_f4m_formats(
    65                 mg['hds_server'] + mg['hds_url'], item_id,
    66                 f4m_id='hds', fatal=False))
     45            # NB the string values in the JSON are stored using XML escaping(!)
     46            show = try_get(data, lambda x: x['shows'][0], dict)
     47            if not show:
     48                continue
     49
     50            if not info_dict:
     51                title = unescapeHTML(show['title'])
     52                description = unescapeHTML(show.get('description'))
     53                thumbnail = show.get('thumbnail')
     54                duration = float_or_none(show.get('duration'), 1000)
     55                timestamp = parse_iso8601(show.get('published'))
     56                info_dict = {
     57                    'id': item_id,
     58                    'title': title,
     59                    'description': description,
     60                    'thumbnail': thumbnail,
     61                    'timestamp': timestamp,
     62                    'duration': duration,
     63                }
     64
     65            mg = try_get(show, lambda x: x['media:group'][0], dict)
     66            if not mg:
     67                continue
     68
     69            if mg.get('url'):
     70                m = re.match(r'(?P<url>rtmpe?://[^/]+)/(?P<app>.+)/(?P<playpath>mp4:.*)', mg['url'])
     71                if m:
     72                    m = m.groupdict()
     73                    formats.append({
     74                        'url': m['url'] + '/' + m['app'],
     75                        'app': m['app'],
     76                        'play_path': m['playpath'],
     77                        'player_url': url,
     78                        'ext': 'flv',
     79                        'format_id': 'rtmp',
     80                    })
     81
     82            if mg.get('hls_server') and mg.get('hls_url'):
     83                formats.extend(self._extract_m3u8_formats(
     84                    mg['hls_server'] + mg['hls_url'], item_id, 'mp4',
     85                    entry_protocol='m3u8_native', m3u8_id='hls', fatal=False))
     86
     87            if mg.get('hds_server') and mg.get('hds_url'):
     88                formats.extend(self._extract_f4m_formats(
     89                    mg['hds_server'] + mg['hds_url'], item_id,
     90                    f4m_id='hds', fatal=False))
     91
     92            mg_rte_server = str_or_none(mg.get('rte:server'))
     93            mg_url = str_or_none(mg.get('url'))
     94            if mg_rte_server and mg_url:
     95                hds_url = url_or_none(mg_rte_server + mg_url)
     96                if hds_url:
     97                    formats.extend(self._extract_f4m_formats(
     98                        hds_url, item_id, f4m_id='hds', fatal=False))
    6799
    68100        self._sort_formats(formats)
    69101
    70         return {
    71             'id': item_id,
    72             'title': title,
    73             'description': description,
    74             'thumbnail': thumbnail,
    75             'timestamp': timestamp,
    76             'duration': duration,
    77             'formats': formats,
    78         }
     102        info_dict['formats'] = formats
     103        return info_dict
    79104
    80105
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/rutube.py

    r8096 r8258  
    104104        options = self._download_json(
    105105            'http://rutube.ru/api/play/options/%s/?format=json' % video_id,
    106             video_id, 'Downloading options JSON')
     106            video_id, 'Downloading options JSON',
     107            headers=self.geo_verification_headers())
    107108
    108109        formats = []
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/ruutu.py

    r8096 r8258  
    6666
    6767        video_xml = self._download_xml(
    68             'http://gatling.ruutu.fi/media-xml-cache?id=%s' % video_id, video_id)
     68            'https://gatling.nelonenmedia.fi/media-xml-cache', video_id,
     69            query={'id': video_id})
    6970
    7071        formats = []
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/screencast.py

    r8096 r8258  
    9292
    9393        if video_url is None:
     94            video_url = self._html_search_regex(
     95                r'MediaContentUrl["\']\s*:(["\'])(?P<url>(?:(?!\1).)+)\1',
     96                webpage, 'video url', default=None, group='url')
     97
     98        if video_url is None:
     99            video_url = self._html_search_meta(
     100                'og:video', webpage, default=None)
     101
     102        if video_url is None:
    94103            raise ExtractorError('Cannot find video')
    95104
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/shared.py

    r8096 r8258  
    66    ExtractorError,
    77    int_or_none,
     8    url_or_none,
    89    urlencode_postdata,
    910)
     
    8788
    8889    def _extract_video_url(self, webpage, video_id, *args):
     90        def decode_url(encoded_url):
     91            return compat_b64decode(encoded_url).decode('utf-8')
     92
     93        stream_url = url_or_none(decode_url(self._search_regex(
     94            r'data-stream\s*=\s*(["\'])(?P<url>(?:(?!\1).)+)\1', webpage,
     95            'stream url', default=None, group='url')))
     96        if stream_url:
     97            return stream_url
    8998        return self._parse_json(
    9099            self._search_regex(
    91100                r'InitializeStream\s*\(\s*(["\'])(?P<url>(?:(?!\1).)+)\1',
    92101                webpage, 'stream', group='url'),
    93             video_id,
    94             transform_source=lambda x: compat_b64decode(x).decode('utf-8'))[0]
     102            video_id, transform_source=decode_url)[0]
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/sixplay.py

    r8096 r8258  
    6565            asset_url = asset.get('full_physical_path')
    6666            protocol = asset.get('protocol')
    67             if not asset_url or protocol == 'primetime' or asset_url in urls:
     67            if not asset_url or protocol == 'primetime' or asset.get('type') == 'usp_hlsfp_h264' or asset_url in urls:
    6868                continue
    6969            urls.append(asset_url)
     
    8282                            continue
    8383                        asset_url = urlh.geturl()
    84                     asset_url = re.sub(r'/([^/]+)\.ism/[^/]*\.m3u8', r'/\1.ism/\1.m3u8', asset_url)
    85                     formats.extend(self._extract_m3u8_formats(
    86                         asset_url, video_id, 'mp4', 'm3u8_native',
    87                         m3u8_id='hls', fatal=False))
    88                     formats.extend(self._extract_f4m_formats(
    89                         asset_url.replace('.m3u8', '.f4m'),
    90                         video_id, f4m_id='hds', fatal=False))
    91                     formats.extend(self._extract_mpd_formats(
    92                         asset_url.replace('.m3u8', '.mpd'),
    93                         video_id, mpd_id='dash', fatal=False))
    94                     formats.extend(self._extract_ism_formats(
    95                         re.sub(r'/[^/]+\.m3u8', '/Manifest', asset_url),
    96                         video_id, ism_id='mss', fatal=False))
     84                    for i in range(3, 0, -1):
     85                        asset_url = asset_url = asset_url.replace('_sd1/', '_sd%d/' % i)
     86                        m3u8_formats = self._extract_m3u8_formats(
     87                            asset_url, video_id, 'mp4', 'm3u8_native',
     88                            m3u8_id='hls', fatal=False)
     89                        formats.extend(m3u8_formats)
     90                        formats.extend(self._extract_mpd_formats(
     91                            asset_url.replace('.m3u8', '.mpd'),
     92                            video_id, mpd_id='dash', fatal=False))
     93                        if m3u8_formats:
     94                            break
    9795                else:
    9896                    formats.extend(self._extract_m3u8_formats(
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/spike.py

    r8096 r8258  
    4545    _FEED_URL = 'http://www.paramountnetwork.com/feeds/mrss/'
    4646    _GEO_COUNTRIES = ['US']
     47
     48    def _extract_mgid(self, webpage):
     49        cs = self._parse_json(self._search_regex(
     50            r'window\.__DATA__\s*=\s*({.+})',
     51            webpage, 'data'), None)['children']
     52        c = next(c for c in cs if c.get('type') == 'VideoPlayer')
     53        return c['props']['media']['video']['config']['uri']
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/sportbox.py

    r8096 r8258  
    99    int_or_none,
    1010    js_to_json,
     11    merge_dicts,
    1112)
    1213
    1314
    14 class SportBoxEmbedIE(InfoExtractor):
    15     _VALID_URL = r'https?://news\.sportbox\.ru/vdl/player(?:/[^/]+/|\?.*?\bn?id=)(?P<id>\d+)'
     15class SportBoxIE(InfoExtractor):
     16    _VALID_URL = r'https?://(?:news\.sportbox|matchtv)\.ru/vdl/player(?:/[^/]+/|\?.*?\bn?id=)(?P<id>\d+)'
    1617    _TESTS = [{
    1718        'url': 'http://news.sportbox.ru/vdl/player/ci/211355',
    1819        'info_dict': {
    19             'id': '211355',
     20            'id': '109158',
    2021            'ext': 'mp4',
    21             'title': '211355',
     22            'title': 'В Новороссийске прошел детский турнир «Поле славы боевой»',
     23            'description': 'В Новороссийске прошел детский турнир «Поле славы боевой»',
    2224            'thumbnail': r're:^https?://.*\.jpg$',
    2325            'duration': 292,
    2426            'view_count': int,
     27            'timestamp': 1426237001,
     28            'upload_date': '20150313',
    2529        },
    2630        'params': {
     
    3438        'url': 'https://news.sportbox.ru/vdl/player/media/193095',
    3539        'only_matching': True,
     40    }, {
     41        'url': 'https://news.sportbox.ru/vdl/player/media/109158',
     42        'only_matching': True,
     43    }, {
     44        'url': 'https://matchtv.ru/vdl/player/media/109158',
     45        'only_matching': True,
    3646    }]
    3747
     
    3949    def _extract_urls(webpage):
    4050        return re.findall(
    41             r'<iframe[^>]+src="(https?://news\.sportbox\.ru/vdl/player[^"]+)"',
     51            r'<iframe[^>]+src="(https?://(?:news\.sportbox|matchtv)\.ru/vdl/player[^"]+)"',
    4252            webpage)
    4353
     
    4757        webpage = self._download_webpage(url, video_id)
    4858
    49         wjplayer_data = self._parse_json(
     59        sources = self._parse_json(
    5060            self._search_regex(
    51                 r'(?s)wjplayer\(({.+?})\);', webpage, 'wjplayer settings'),
     61                r'(?s)playerOptions\.sources(?:WithRes)?\s*=\s*(\[.+?\])\s*;\s*\n',
     62                webpage, 'sources'),
    5263            video_id, transform_source=js_to_json)
    5364
    5465        formats = []
    55         for source in wjplayer_data['sources']:
     66        for source in sources:
    5667            src = source.get('src')
    5768            if not src:
     
    6778        self._sort_formats(formats)
    6879
     80        player = self._parse_json(
     81            self._search_regex(
     82                r'(?s)playerOptions\s*=\s*({.+?})\s*;\s*\n', webpage,
     83                'player options', default='{}'),
     84            video_id, transform_source=js_to_json)
     85        media_id = player['mediaId']
     86
     87        info = self._search_json_ld(webpage, media_id, default={})
     88
    6989        view_count = int_or_none(self._search_regex(
    7090            r'Просмотров\s*:\s*(\d+)', webpage, 'view count', default=None))
    7191
    72         return {
    73             'id': video_id,
    74             'title': video_id,
    75             'thumbnail': wjplayer_data.get('poster'),
    76             'duration': int_or_none(wjplayer_data.get('duration')),
     92        return merge_dicts(info, {
     93            'id': media_id,
     94            'title': self._og_search_title(webpage, default=None) or media_id,
     95            'thumbnail': player.get('poster'),
     96            'duration': int_or_none(player.get('duration')),
    7797            'view_count': view_count,
    7898            'formats': formats,
    79         }
     99        })
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/ted.py

    r8096 r8258  
    213213        http_url = None
    214214        for format_id, resources in resources_.items():
    215             if not isinstance(resources, dict):
    216                 continue
    217215            if format_id == 'h264':
    218216                for resource in resources:
     
    243241                    })
    244242            elif format_id == 'hls':
     243                if not isinstance(resources, dict):
     244                    continue
    245245                stream_url = url_or_none(resources.get('stream'))
    246246                if not stream_url:
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/theplatform.py

    r8096 r8258  
    4040            headers=self.geo_verification_headers())
    4141        error_element = find_xpath_attr(meta, _x('.//smil:ref'), 'src')
    42         if error_element is not None and error_element.attrib['src'].startswith(
    43                 'http://link.theplatform.%s/s/errorFiles/Unavailable.' % self._TP_TLD):
    44             raise ExtractorError(error_element.attrib['abstract'], expected=True)
     42        if error_element is not None:
     43            exception = find_xpath_attr(
     44                error_element, _x('.//smil:param'), 'name', 'exception')
     45            if exception is not None:
     46                if exception.get('value') == 'GeoLocationBlocked':
     47                    self.raise_geo_restricted(error_element.attrib['abstract'])
     48                elif error_element.attrib['src'].startswith(
     49                        'http://link.theplatform.%s/s/errorFiles/Unavailable.'
     50                        % self._TP_TLD):
     51                    raise ExtractorError(
     52                        error_element.attrib['abstract'], expected=True)
    4553
    4654        smil_formats = self._parse_smil_formats(
     
    336344        real_url = self._URL_TEMPLATE % (self.http_scheme(), provider_id, feed_id, filter_query)
    337345        entry = self._download_json(real_url, video_id)['entries'][0]
    338         main_smil_url = 'http://link.theplatform.com/s/%s/media/guid/%d/%s' % (provider_id, account_id, entry['guid']) if account_id else None
     346        main_smil_url = 'http://link.theplatform.com/s/%s/media/guid/%d/%s' % (provider_id, account_id, entry['guid']) if account_id else entry.get('plmedia$publicUrl')
    339347
    340348        formats = []
     
    349357                first_video_id = cur_video_id
    350358                duration = float_or_none(item.get('plfile$duration'))
    351             for asset_type in item['plfile$assetTypes']:
     359            file_asset_types = item.get('plfile$assetTypes') or compat_parse_qs(compat_urllib_parse_urlparse(smil_url).query)['assetTypes']
     360            for asset_type in file_asset_types:
    352361                if asset_type in asset_types:
    353362                    continue
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/tnaflix.py

    r8096 r8258  
    1919    # May be overridden in descendants if necessary
    2020    _CONFIG_REGEX = [
    21         r'flashvars\.config\s*=\s*escape\("([^"]+)"',
    22         r'<input[^>]+name="config\d?" value="([^"]+)"',
     21        r'flashvars\.config\s*=\s*escape\("(?P<url>[^"]+)"',
     22        r'<input[^>]+name="config\d?" value="(?P<url>[^"]+)"',
     23        r'config\s*=\s*(["\'])(?P<url>(?:https?:)?//(?:(?!\1).)+)\1',
    2324    ]
    2425    _HOST = 'tna'
     
    8687
    8788        cfg_url = self._proto_relative_url(self._html_search_regex(
    88             self._CONFIG_REGEX, webpage, 'flashvars.config', default=None), 'http:')
     89            self._CONFIG_REGEX, webpage, 'flashvars.config', default=None,
     90            group='url'), 'http:')
    8991
    9092        if not cfg_url:
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/tube8.py

    r8096 r8258  
    4646
    4747        description = self._html_search_regex(
    48             r'>Description:</strong>\s*(.+?)\s*<', webpage, 'description', fatal=False)
     48            r'(?s)Description:</dt>\s*<dd>(.+?)</dd>', webpage, 'description', fatal=False)
    4949        uploader = self._html_search_regex(
    5050            r'<span class="username">\s*(.+?)\s*<',
     
    5656            r'rdownVar\s*=\s*"(\d+)"', webpage, 'dislike count', fatal=False))
    5757        view_count = str_to_int(self._search_regex(
    58             r'<strong>Views: </strong>([\d,\.]+)\s*</li>',
     58            r'Views:\s*</dt>\s*<dd>([\d,\.]+)',
    5959            webpage, 'view count', fatal=False))
    6060        comment_count = str_to_int(self._search_regex(
     
    6363
    6464        category = self._search_regex(
    65             r'Category:\s*</strong>\s*<a[^>]+href=[^>]+>([^<]+)',
     65            r'Category:\s*</dt>\s*<dd>\s*<a[^>]+href=[^>]+>([^<]+)',
    6666            webpage, 'category', fatal=False)
    6767        categories = [category] if category else None
    6868
    6969        tags_str = self._search_regex(
    70             r'(?s)Tags:\s*</strong>(.+?)</(?!a)',
     70            r'(?s)Tags:\s*</dt>\s*<dd>(.+?)</(?!a)',
    7171            webpage, 'tags', fatal=False)
    7272        tags = [t for t in re.findall(
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/twitch.py

    r8096 r8258  
    5252
    5353    def _call_api(self, path, item_id, *args, **kwargs):
    54         kwargs.setdefault('headers', {})['Client-ID'] = self._CLIENT_ID
     54        headers = kwargs.get('headers', {}).copy()
     55        headers['Client-ID'] = self._CLIENT_ID
     56        kwargs['headers'] = headers
    5557        response = self._download_json(
    5658            '%s/%s' % (self._API_BASE, path), item_id,
     
    560562                    TwitchUploadsIE,
    561563                    TwitchPastBroadcastsIE,
    562                     TwitchHighlightsIE))
     564                    TwitchHighlightsIE,
     565                    TwitchClipsIE))
    563566                else super(TwitchStreamIE, cls).suitable(url))
    564567
     
    634637class TwitchClipsIE(TwitchBaseIE):
    635638    IE_NAME = 'twitch:clips'
    636     _VALID_URL = r'https?://clips\.twitch\.tv/(?:[^/]+/)*(?P<id>[^/?#&]+)'
     639    _VALID_URL = r'https?://(?:clips\.twitch\.tv/(?:[^/]+/)*|(?:www\.)?twitch\.tv/[^/]+/clip/)(?P<id>[^/?#&]+)'
    637640
    638641    _TESTS = [{
     
    653656        # multiple formats
    654657        'url': 'https://clips.twitch.tv/rflegendary/UninterestedBeeDAESuppy',
     658        'only_matching': True,
     659    }, {
     660        'url': 'https://www.twitch.tv/sergeynixon/clip/StormyThankfulSproutFutureMan',
    655661        'only_matching': True,
    656662    }]
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/udemy.py

    r8096 r8258  
    123123
    124124    def _download_webpage_handle(self, *args, **kwargs):
    125         kwargs.setdefault('headers', {})['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4'
     125        headers = kwargs.get('headers', {}).copy()
     126        headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4'
     127        kwargs['headers'] = headers
    126128        return super(UdemyIE, self)._download_webpage_handle(
    127129            *args, **compat_kwargs(kwargs))
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/viewster.py

    r8096 r8258  
    131131                return (base_format_id + '%s%s' % (sep, suffix)) if base_format_id else suffix
    132132
    133             for media_type in ('application/f4m+xml', 'application/x-mpegURL', 'video/mp4'):
    134                 media = self._download_json(
    135                     'https://public-api.viewster.com/movies/%s/video' % entry_id,
    136                     video_id, 'Downloading %s JSON' % concat(media_type, ' '), fatal=False, query={
    137                         'mediaType': media_type,
    138                         'language': audio,
    139                         'subtitle': subtitle,
    140                     })
    141                 if not media:
    142                     continue
     133            medias = self._download_json(
     134                'https://public-api.viewster.com/movies/%s/videos' % entry_id,
     135                video_id, fatal=False, query={
     136                    'mediaTypes': ['application/f4m+xml', 'application/x-mpegURL', 'video/mp4'],
     137                    'language': audio,
     138                    'subtitle': subtitle,
     139                })
     140            if not medias:
     141                continue
     142            for media in medias:
    143143                video_url = media.get('Uri')
    144144                if not video_url:
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/vimeo.py

    r8096 r8258  
    300300                'uploader_id': 'atencio',
    301301                'uploader': 'Peter Atencio',
     302                'channel_id': 'keypeele',
     303                'channel_url': r're:https?://(?:www\.)?vimeo\.com/channels/keypeele',
    302304                'timestamp': 1380339469,
    303305                'upload_date': '20130928',
    304306                'duration': 187,
    305307            },
     308            'expected_warnings': ['Unable to download JSON metadata'],
    306309        },
    307310        {
     
    356359            'info_dict': {
    357360                'id': '6213729',
    358                 'ext': 'mov',
     361                'ext': 'mp4',
    359362                'title': 'Vimeo Tribute: The Shining',
    360363                'uploader': 'Casey Donahue',
    361364                'uploader_url': r're:https?://(?:www\.)?vimeo\.com/caseydonahue',
    362365                'uploader_id': 'caseydonahue',
     366                'channel_url': r're:https?://(?:www\.)?vimeo\.com/channels/tributes',
     367                'channel_id': 'tributes',
    363368                'timestamp': 1250886430,
    364369                'upload_date': '20090821',
     
    465470        if 'Referer' not in headers:
    466471            headers['Referer'] = url
     472
     473        channel_id = self._search_regex(
     474            r'vimeo\.com/channels/([^/]+)', url, 'channel id', default=None)
    467475
    468476        # Extract ID from URL
     
    544552                    config_re = [r' = {config:({.+?}),assets:', r'(?:[abc])=({.+?});']
    545553                config_re.append(r'\bvar\s+r\s*=\s*({.+?})\s*;')
     554                config_re.append(r'\bconfig\s*=\s*({.+?})\s*;')
    546555                config = self._search_regex(config_re, webpage, 'info section',
    547556                                            flags=re.DOTALL)
     
    564573                config = self._verify_player_video_password(redirect_url, video_id)
    565574
     575        vod = config.get('video', {}).get('vod', {})
     576
    566577        def is_rented():
    567578            if '>You rented this title.<' in webpage:
     
    569580            if config.get('user', {}).get('purchased'):
    570581                return True
    571             label = try_get(
    572                 config, lambda x: x['video']['vod']['purchase_options'][0]['label_string'], compat_str)
    573             if label and label.startswith('You rented this'):
    574                 return True
     582            for purchase_option in vod.get('purchase_options', []):
     583                if purchase_option.get('purchased'):
     584                    return True
     585                label = purchase_option.get('label_string')
     586                if label and (label.startswith('You rented this') or label.endswith(' remaining')):
     587                    return True
    575588            return False
    576589
    577         if is_rented():
    578             feature_id = config.get('video', {}).get('vod', {}).get('feature_id')
     590        if is_rented() and vod.get('is_trailer'):
     591            feature_id = vod.get('feature_id')
    579592            if feature_id and not data.get('force_feature_id', False):
    580593                return self.url_result(smuggle_url(
     
    653666                webpage, 'license', default=None, group='license')
    654667
     668        channel_url = 'https://vimeo.com/channels/%s' % channel_id if channel_id else None
     669
    655670        info_dict = {
    656671            'id': video_id,
     
    663678            'comment_count': comment_count,
    664679            'license': cc_license,
     680            'channel_id': channel_id,
     681            'channel_url': channel_url,
    665682        }
    666683
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/vk.py

    r8096 r8258  
    294294            'url': 'https://vk.com/video-10639516_456240611',
    295295            'only_matching': True,
    296         }
    297     ]
     296        },
     297        {
     298            # The video is not available in your region.
     299            'url': 'https://vk.com/video-51812607_171445436',
     300            'only_matching': True,
     301        }]
    298302
    299303    def _real_extract(self, url):
     
    355359            r'<!>This video is no longer available, because it has been deleted.':
    356360            'Video %s is no longer available, because it has been deleted.',
     361
     362            r'<!>The video .+? is not available in your region.':
     363            'Video %s is not available in your region.',
    357364        }
    358365
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/vrv.py

    r8096 r8258  
    9191        if not url or stream_format not in ('hls', 'dash'):
    9292            return []
    93         stream_id = hardsub_lang or audio_lang
     93        assert audio_lang or hardsub_lang
     94        stream_id_list = []
     95        if audio_lang:
     96            stream_id_list.append('audio-%s' % audio_lang)
     97        if hardsub_lang:
     98            stream_id_list.append('hardsub-%s' % hardsub_lang)
     99        stream_id = '-'.join(stream_id_list)
    94100        format_id = '%s-%s' % (stream_format, stream_id)
    95101        if stream_format == 'hls':
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/vzaar.py

    r8096 r8258  
    55
    66from .common import InfoExtractor
     7from ..compat import compat_str
    78from ..utils import (
    89    int_or_none,
    910    float_or_none,
     11    unified_timestamp,
     12    url_or_none,
    1013)
    1114
     
    1417    _VALID_URL = r'https?://(?:(?:www|view)\.)?vzaar\.com/(?:videos/)?(?P<id>\d+)'
    1518    _TESTS = [{
     19        # HTTP and HLS
    1620        'url': 'https://vzaar.com/videos/1152805',
    1721        'md5': 'bde5ddfeb104a6c56a93a06b04901dbf',
     
    4145        video_data = self._download_json(
    4246            'http://view.vzaar.com/v2/%s/video' % video_id, video_id)
    43         source_url = video_data['sourceUrl']
    4447
    45         info = {
     48        title = video_data['videoTitle']
     49
     50        formats = []
     51
     52        source_url = url_or_none(video_data.get('sourceUrl'))
     53        if source_url:
     54            f = {
     55                'url': source_url,
     56                'format_id': 'http',
     57            }
     58            if 'audio' in source_url:
     59                f.update({
     60                    'vcodec': 'none',
     61                    'ext': 'mp3',
     62                })
     63            else:
     64                f.update({
     65                    'width': int_or_none(video_data.get('width')),
     66                    'height': int_or_none(video_data.get('height')),
     67                    'ext': 'mp4',
     68                    'fps': float_or_none(video_data.get('fps')),
     69                })
     70            formats.append(f)
     71
     72        video_guid = video_data.get('guid')
     73        usp = video_data.get('usp')
     74        if isinstance(video_guid, compat_str) and isinstance(usp, dict):
     75            m3u8_url = ('http://fable.vzaar.com/v4/usp/%s/%s.ism/.m3u8?'
     76                        % (video_guid, video_id)) + '&'.join(
     77                '%s=%s' % (k, v) for k, v in usp.items())
     78            formats.extend(self._extract_m3u8_formats(
     79                m3u8_url, video_id, 'mp4', entry_protocol='m3u8_native',
     80                m3u8_id='hls', fatal=False))
     81
     82        self._sort_formats(formats)
     83
     84        return {
    4685            'id': video_id,
    47             'title': video_data['videoTitle'],
    48             'url': source_url,
     86            'title': title,
    4987            'thumbnail': self._proto_relative_url(video_data.get('poster')),
    5088            'duration': float_or_none(video_data.get('videoDuration')),
     89            'timestamp': unified_timestamp(video_data.get('ts')),
     90            'formats': formats,
    5191        }
    52         if 'audio' in source_url:
    53             info.update({
    54                 'vcodec': 'none',
    55                 'ext': 'mp3',
    56             })
    57         else:
    58             info.update({
    59                 'width': int_or_none(video_data.get('width')),
    60                 'height': int_or_none(video_data.get('height')),
    61                 'ext': 'mp4',
    62             })
    63         return info
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/youtube.py

    r8096 r8258  
    4242    remove_start,
    4343    smuggle_url,
     44    str_or_none,
    4445    str_to_int,
    4546    try_get,
     
    260261
    261262    def _download_webpage_handle(self, *args, **kwargs):
    262         kwargs.setdefault('query', {})['disable_polymer'] = 'true'
     263        query = kwargs.get('query', {}).copy()
     264        query['disable_polymer'] = 'true'
     265        kwargs['query'] = query
    263266        return super(YoutubeBaseInfoExtractor, self)._download_webpage_handle(
    264267            *args, **compat_kwargs(kwargs))
     
    348351                            (?:www\.)?yourepeat\.com/|
    349352                            tube\.majestyc\.net/|
     353                            (?:www\.)?invidio\.us/|
    350354                            youtube\.googleapis\.com/)                        # the various hostnames, with wildcard subdomains
    351355                         (?:.*?\#/)?                                          # handle anchor (#/) redirect urls
     
    491495                'uploader_id': 'phihag',
    492496                'uploader_url': r're:https?://(?:www\.)?youtube\.com/user/phihag',
     497                'channel_id': 'UCLqxVugv74EIW3VWh2NOa3Q',
     498                'channel_url': r're:https?://(?:www\.)?youtube\.com/channel/UCLqxVugv74EIW3VWh2NOa3Q',
    493499                'upload_date': '20121002',
    494500                'license': 'Standard YouTube License',
     
    497503                'tags': ['youtube-dl'],
    498504                'duration': 10,
     505                'view_count': int,
    499506                'like_count': int,
    500507                'dislike_count': int,
     
    579586                'tags': ['youtube-dl'],
    580587                'duration': 10,
     588                'view_count': int,
    581589                'like_count': int,
    582590                'dislike_count': int,
     
    10651073            'only_matching': True,
    10661074        },
     1075        {
     1076            'url': 'https://invidio.us/watch?v=BaW_jenozKc',
     1077            'only_matching': True,
     1078        },
    10671079    ]
    10681080
     
    11811193             r'\.sig\|\|(?P<sig>[a-zA-Z0-9$]+)\(',
    11821194             r'yt\.akamaized\.net/\)\s*\|\|\s*.*?\s*c\s*&&\s*d\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(',
    1183              r'\bc\s*&&\s*d\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\('),
     1195             r'\bc\s*&&\s*d\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(',
     1196             r'\bc\s*&&\s*d\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\('),
    11841197            jscode, 'Initial JS player signature function name', group='sig')
    11851198
     
    15291542        def extract_view_count(v_info):
    15301543            return int_or_none(try_get(v_info, lambda x: x['view_count'][0]))
     1544
     1545        player_response = {}
    15311546
    15321547        # Get video info
     
    15721587                    is_live = True
    15731588                sts = ytplayer_config.get('sts')
     1589                if not player_response:
     1590                    pl_response = str_or_none(args.get('player_response'))
     1591                    if pl_response:
     1592                        pl_response = self._parse_json(pl_response, video_id, fatal=False)
     1593                        if isinstance(pl_response, dict):
     1594                            player_response = pl_response
    15741595            if not video_info or self._downloader.params.get('youtube_include_dash_manifest', True):
    15751596                # We also try looking in get_video_info since it may contain different dashmpd
     
    16001621                        continue
    16011622                    get_video_info = compat_parse_qs(video_info_webpage)
     1623                    if not player_response:
     1624                        pl_response = get_video_info.get('player_response', [None])[0]
     1625                        if isinstance(pl_response, dict):
     1626                            player_response = pl_response
    16021627                    add_dash_mpd(get_video_info)
    16031628                    if view_count is None:
     
    16451670                    video_id=video_id)
    16461671
     1672        video_details = try_get(
     1673            player_response, lambda x: x['videoDetails'], dict) or {}
     1674
    16471675        # title
    16481676        if 'title' in video_info:
    16491677            video_title = video_info['title'][0]
     1678        elif 'title' in player_response:
     1679            video_title = video_details['title']
    16501680        else:
    16511681            self._downloader.report_warning('Unable to extract video title')
     
    17101740        if view_count is None:
    17111741            view_count = extract_view_count(video_info)
     1742        if view_count is None and video_details:
     1743            view_count = int_or_none(video_details.get('viewCount'))
    17121744
    17131745        # Check for "rental" videos
     
    18901922
    18911923        # uploader
    1892         video_uploader = try_get(video_info, lambda x: x['author'][0], compat_str)
     1924        video_uploader = try_get(
     1925            video_info, lambda x: x['author'][0],
     1926            compat_str) or str_or_none(video_details.get('author'))
    18931927        if video_uploader:
    18941928            video_uploader = compat_urllib_parse_unquote_plus(video_uploader)
     
    19071941        else:
    19081942            self._downloader.report_warning('unable to extract uploader nickname')
     1943
     1944        channel_id = self._html_search_meta(
     1945            'channelId', video_webpage, 'channel id')
     1946        channel_url = 'http://www.youtube.com/channel/%s' % channel_id if channel_id else None
    19091947
    19101948        # thumbnail image
     
    19992037        dislike_count = _extract_count('dislike')
    20002038
     2039        if view_count is None:
     2040            view_count = str_to_int(self._search_regex(
     2041                r'<[^>]+class=["\']watch-view-count[^>]+>\s*([\d,\s]+)', video_webpage,
     2042                'view count', default=None))
     2043
    20012044        # subtitles
    20022045        video_subtitles = self.extract_subtitles(video_id, video_webpage)
     
    20052048        video_duration = try_get(
    20062049            video_info, lambda x: int_or_none(x['length_seconds'][0]))
     2050        if not video_duration:
     2051            video_duration = int_or_none(video_details.get('lengthSeconds'))
    20072052        if not video_duration:
    20082053            video_duration = parse_duration(self._html_search_meta(
     
    20792124            'uploader_id': video_uploader_id,
    20802125            'uploader_url': video_uploader_url,
     2126            'channel_id': channel_id,
     2127            'channel_url': channel_url,
    20812128            'upload_date': upload_date,
    20822129            'license': video_license,
     
    21172164                        (?:\w+\.)?
    21182165                        (?:
    2119                             youtube\.com/
     2166                            (?:
     2167                                youtube\.com|
     2168                                invidio\.us
     2169                            )
     2170                            /
    21202171                            (?:
    21212172                               (?:course|view_play_list|my_playlists|artist|playlist|watch|embed/(?:videoseries|[0-9A-Za-z_-]{11}))
     
    22302281            'categories': ['People & Blogs'],
    22312282            'tags': list,
     2283            'view_count': int,
    22322284            'like_count': int,
    22332285            'dislike_count': int,
     
    22672319        # music album playlist
    22682320        'url': 'OLAK5uy_m4xAFdmMC5rX3Ji3g93pQe3hqLZw_9LhM',
     2321        'only_matching': True,
     2322    }, {
     2323        'url': 'https://invidio.us/playlist?list=PLDIoUOhQQPlXr63I_vwF9GD8sAKh77dWU',
    22692324        'only_matching': True,
    22702325    }]
     
    24102465class YoutubeChannelIE(YoutubePlaylistBaseInfoExtractor):
    24112466    IE_DESC = 'YouTube.com channels'
    2412     _VALID_URL = r'https?://(?:youtu\.be|(?:\w+\.)?youtube(?:-nocookie)?\.com)/channel/(?P<id>[0-9A-Za-z_-]+)'
     2467    _VALID_URL = r'https?://(?:youtu\.be|(?:\w+\.)?youtube(?:-nocookie)?\.com|(?:www\.)?invidio\.us)/channel/(?P<id>[0-9A-Za-z_-]+)'
    24132468    _TEMPLATE_URL = 'https://www.youtube.com/channel/%s/videos'
    24142469    _VIDEO_RE = r'(?:title="(?P<title>[^"]+)"[^>]+)?href="/watch\?v=(?P<id>[0-9A-Za-z_-]+)&?'
     
    24312486            'title': 'Uploads from Deus Ex',
    24322487        },
     2488    }, {
     2489        'url': 'https://invidio.us/channel/UC23qupoDRn9YOAVzeoxjOQA',
     2490        'only_matching': True,
    24332491    }]
    24342492
  • youtube-dl/trunk/fuentes/youtube_dl/extractor/zattoo.py

    r8096 r8258  
    1919
    2020
    21 class ZattooBaseIE(InfoExtractor):
    22     _NETRC_MACHINE = 'zattoo'
    23     _HOST_URL = 'https://zattoo.com'
    24 
     21class ZattooPlatformBaseIE(InfoExtractor):
    2522    _power_guide_hash = None
     23
     24    def _host_url(self):
     25        return 'https://%s' % (self._API_HOST if hasattr(self, '_API_HOST') else self._HOST)
    2626
    2727    def _login(self):
     
    3434        try:
    3535            data = self._download_json(
    36                 '%s/zapi/v2/account/login' % self._HOST_URL, None, 'Logging in',
     36                '%s/zapi/v2/account/login' % self._host_url(), None, 'Logging in',
    3737                data=urlencode_postdata({
    3838                    'login': username,
     
    4040                    'remember': 'true',
    4141                }), headers={
    42                     'Referer': '%s/login' % self._HOST_URL,
     42                    'Referer': '%s/login' % self._host_url(),
    4343                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    4444                })
     
    5454    def _real_initialize(self):
    5555        webpage = self._download_webpage(
    56             self._HOST_URL, None, 'Downloading app token')
     56            self._host_url(), None, 'Downloading app token')
    5757        app_token = self._html_search_regex(
    5858            r'appToken\s*=\s*(["\'])(?P<token>(?:(?!\1).)+?)\1',
     
    6363        # Will setup appropriate cookies
    6464        self._request_webpage(
    65             '%s/zapi/v2/session/hello' % self._HOST_URL, None,
     65            '%s/zapi/v2/session/hello' % self._host_url(), None,
    6666            'Opening session', data=urlencode_postdata({
    6767                'client_app_token': app_token,
     
    7676    def _extract_cid(self, video_id, channel_name):
    7777        channel_groups = self._download_json(
    78             '%s/zapi/v2/cached/channels/%s' % (self._HOST_URL,
     78            '%s/zapi/v2/cached/channels/%s' % (self._host_url(),
    7979                                               self._power_guide_hash),
    8080            video_id, 'Downloading channel list',
     
    9494    def _extract_cid_and_video_info(self, video_id):
    9595        data = self._download_json(
    96             '%s/zapi/program/details' % self._HOST_URL,
     96            '%s/zapi/v2/cached/program/power_details/%s' % (
     97                self._host_url(), self._power_guide_hash),
    9798            video_id,
    9899            'Downloading video information',
    99100            query={
    100                 'program_id': video_id,
    101                 'complete': True
     101                'program_ids': video_id,
     102                'complete': True,
    102103            })
    103104
    104         p = data['program']
     105        p = data['programs'][0]
    105106        cid = p['cid']
    106107
    107108        info_dict = {
    108109            'id': video_id,
    109             'title': p.get('title') or p['episode_title'],
    110             'description': p.get('description'),
    111             'thumbnail': p.get('image_url'),
     110            'title': p.get('t') or p['et'],
     111            'description': p.get('d'),
     112            'thumbnail': p.get('i_url'),
    112113            'creator': p.get('channel_name'),
    113             'episode': p.get('episode_title'),
    114             'episode_number': int_or_none(p.get('episode_number')),
    115             'season_number': int_or_none(p.get('season_number')),
     114            'episode': p.get('et'),
     115            'episode_number': int_or_none(p.get('e_no')),
     116            'season_number': int_or_none(p.get('s_no')),
    116117            'release_year': int_or_none(p.get('year')),
    117             'categories': try_get(p, lambda x: x['categories'], list),
     118            'categories': try_get(p, lambda x: x['c'], list),
     119            'tags': try_get(p, lambda x: x['g'], list)
    118120        }
    119121
     
    127129        if is_live:
    128130            postdata_common.update({'timeshift': 10800})
    129             url = '%s/zapi/watch/live/%s' % (self._HOST_URL, cid)
     131            url = '%s/zapi/watch/live/%s' % (self._host_url(), cid)
    130132        elif record_id:
    131             url = '%s/zapi/watch/recording/%s' % (self._HOST_URL, record_id)
     133            url = '%s/zapi/watch/recording/%s' % (self._host_url(), record_id)
    132134        else:
    133             url = '%s/zapi/watch/recall/%s/%s' % (self._HOST_URL, cid, video_id)
     135            url = '%s/zapi/watch/recall/%s/%s' % (self._host_url(), cid, video_id)
    134136
    135137        formats = []
     
    202204
    203205
    204 class QuicklineBaseIE(ZattooBaseIE):
     206class QuicklineBaseIE(ZattooPlatformBaseIE):
    205207    _NETRC_MACHINE = 'quickline'
    206     _HOST_URL = 'https://mobiltv.quickline.com'
     208    _HOST = 'mobiltv.quickline.com'
    207209
    208210
    209211class QuicklineIE(QuicklineBaseIE):
    210     _VALID_URL = r'https?://(?:www\.)?mobiltv\.quickline\.com/watch/(?P<channel>[^/]+)/(?P<id>[0-9]+)'
     212    _VALID_URL = r'https?://(?:www\.)?%s/watch/(?P<channel>[^/]+)/(?P<id>[0-9]+)' % re.escape(QuicklineBaseIE._HOST)
    211213
    212214    _TEST = {
     
    221223
    222224class QuicklineLiveIE(QuicklineBaseIE):
    223     _VALID_URL = r'https?://(?:www\.)?mobiltv\.quickline\.com/watch/(?P<id>[^/]+)'
     225    _VALID_URL = r'https?://(?:www\.)?%s/watch/(?P<id>[^/]+)' % re.escape(QuicklineBaseIE._HOST)
    224226
    225227    _TEST = {
     
    237239
    238240
     241class ZattooBaseIE(ZattooPlatformBaseIE):
     242    _NETRC_MACHINE = 'zattoo'
     243    _HOST = 'zattoo.com'
     244
     245
     246def _make_valid_url(tmpl, host):
     247    return tmpl % re.escape(host)
     248
     249
    239250class ZattooIE(ZattooBaseIE):
    240     _VALID_URL = r'https?://(?:www\.)?zattoo\.com/watch/(?P<channel>[^/]+?)/(?P<id>[0-9]+)[^/]+(?:/(?P<recid>[0-9]+))?'
     251    _VALID_URL_TEMPLATE = r'https?://(?:www\.)?%s/watch/(?P<channel>[^/]+?)/(?P<id>[0-9]+)[^/]+(?:/(?P<recid>[0-9]+))?'
     252    _VALID_URL = _make_valid_url(_VALID_URL_TEMPLATE, ZattooBaseIE._HOST)
    241253
    242254    # Since regular videos are only available for 7 days and recorded videos
     
    270282        channel_name = video_id = self._match_id(url)
    271283        return self._extract_video(channel_name, video_id, is_live=True)
     284
     285
     286class NetPlusIE(ZattooIE):
     287    _NETRC_MACHINE = 'netplus'
     288    _HOST = 'netplus.tv'
     289    _API_HOST = 'www.%s' % _HOST
     290    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     291
     292    _TESTS = [{
     293        'url': 'https://www.netplus.tv/watch/abc/123-abc',
     294        'only_matching': True,
     295    }]
     296
     297
     298class MNetTVIE(ZattooIE):
     299    _NETRC_MACHINE = 'mnettv'
     300    _HOST = 'tvplus.m-net.de'
     301    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     302
     303    _TESTS = [{
     304        'url': 'https://tvplus.m-net.de/watch/abc/123-abc',
     305        'only_matching': True,
     306    }]
     307
     308
     309class WalyTVIE(ZattooIE):
     310    _NETRC_MACHINE = 'walytv'
     311    _HOST = 'player.waly.tv'
     312    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     313
     314    _TESTS = [{
     315        'url': 'https://player.waly.tv/watch/abc/123-abc',
     316        'only_matching': True,
     317    }]
     318
     319
     320class BBVTVIE(ZattooIE):
     321    _NETRC_MACHINE = 'bbvtv'
     322    _HOST = 'bbv-tv.net'
     323    _API_HOST = 'www.%s' % _HOST
     324    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     325
     326    _TESTS = [{
     327        'url': 'https://www.bbv-tv.net/watch/abc/123-abc',
     328        'only_matching': True,
     329    }]
     330
     331
     332class VTXTVIE(ZattooIE):
     333    _NETRC_MACHINE = 'vtxtv'
     334    _HOST = 'vtxtv.ch'
     335    _API_HOST = 'www.%s' % _HOST
     336    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     337
     338    _TESTS = [{
     339        'url': 'https://www.vtxtv.ch/watch/abc/123-abc',
     340        'only_matching': True,
     341    }]
     342
     343
     344class MyVisionTVIE(ZattooIE):
     345    _NETRC_MACHINE = 'myvisiontv'
     346    _HOST = 'myvisiontv.ch'
     347    _API_HOST = 'www.%s' % _HOST
     348    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     349
     350    _TESTS = [{
     351        'url': 'https://www.myvisiontv.ch/watch/abc/123-abc',
     352        'only_matching': True,
     353    }]
     354
     355
     356class GlattvisionTVIE(ZattooIE):
     357    _NETRC_MACHINE = 'glattvisiontv'
     358    _HOST = 'iptv.glattvision.ch'
     359    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     360
     361    _TESTS = [{
     362        'url': 'https://iptv.glattvision.ch/watch/abc/123-abc',
     363        'only_matching': True,
     364    }]
     365
     366
     367class SAKTVIE(ZattooIE):
     368    _NETRC_MACHINE = 'saktv'
     369    _HOST = 'saktv.ch'
     370    _API_HOST = 'www.%s' % _HOST
     371    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     372
     373    _TESTS = [{
     374        'url': 'https://www.saktv.ch/watch/abc/123-abc',
     375        'only_matching': True,
     376    }]
     377
     378
     379class EWETVIE(ZattooIE):
     380    _NETRC_MACHINE = 'ewetv'
     381    _HOST = 'tvonline.ewe.de'
     382    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     383
     384    _TESTS = [{
     385        'url': 'https://tvonline.ewe.de/watch/abc/123-abc',
     386        'only_matching': True,
     387    }]
     388
     389
     390class QuantumTVIE(ZattooIE):
     391    _NETRC_MACHINE = 'quantumtv'
     392    _HOST = 'quantum-tv.com'
     393    _API_HOST = 'www.%s' % _HOST
     394    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     395
     396    _TESTS = [{
     397        'url': 'https://www.quantum-tv.com/watch/abc/123-abc',
     398        'only_matching': True,
     399    }]
     400
     401
     402class OsnatelTVIE(ZattooIE):
     403    _NETRC_MACHINE = 'osnateltv'
     404    _HOST = 'tvonline.osnatel.de'
     405    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     406
     407    _TESTS = [{
     408        'url': 'https://tvonline.osnatel.de/watch/abc/123-abc',
     409        'only_matching': True,
     410    }]
     411
     412
     413class EinsUndEinsTVIE(ZattooIE):
     414    _NETRC_MACHINE = '1und1tv'
     415    _HOST = '1und1.tv'
     416    _API_HOST = 'www.%s' % _HOST
     417    _VALID_URL = _make_valid_url(ZattooIE._VALID_URL_TEMPLATE, _HOST)
     418
     419    _TESTS = [{
     420        'url': 'https://www.1und1.tv/watch/abc/123-abc',
     421        'only_matching': True,
     422    }]
  • youtube-dl/trunk/fuentes/youtube_dl/version.py

    r8096 r8258  
    11from __future__ import unicode_literals
    22
    3 __version__ = '2018.09.10'
     3__version__ = '2018.11.23'
Note: See TracChangeset for help on using the changeset viewer.