Compare commits

...

18 Commits

Author SHA1 Message Date
Timothy Mann
1a04daba06
Merge 96a49c7838 into c5098961b0 2024-08-21 22:33:22 -04:00
dirkf
c5098961b0 [Youtube] Rework n function extraction pattern
Now also succeeds with player b12cc44b
2024-08-06 20:59:09 +01:00
dirkf
dbc08fba83 [jsinterp] Improve slice implementation for player b12cc44b
Partly taken from yt-dlp/yt-dlp#10664, thx seproDev
        Fixes #32896
2024-08-06 20:51:38 +01:00
Aiur Adept
71223bff39
[Youtube] Fix nsig extraction for player 20dfca59 (#32891)
* dirkf's patch for nsig extraction
* add generic search per  yt-dlp/yt-dlp/pull/10611 - thx bashonly

---------

Co-authored-by: dirkf <fieldhouse@gmx.net>
2024-08-01 19:18:34 +01:00
Tim Mann
96a49c7838 Make the tests pass again
The md5sums of the test videos changed at some point.
2022-11-30 12:13:38 -08:00
Tim Mann
f4ef8145ef Make flake8 happy. This way is more readable. 2021-03-08 12:27:53 -08:00
Tim Mann
5987eb1302 Coding standard: Use try_get. 2021-03-08 12:24:00 -08:00
Tim Mann
d4512dfd52 Coding standard: use compat_str 2021-03-08 12:03:50 -08:00
Tim Mann
cec9f4bf3c Add support for live streams on event pages. 2021-02-20 17:47:48 -08:00
Tim Mann
10273fbd22 Add fallbacks for id and title, just in case. 2021-02-13 17:49:58 -08:00
Tim Mann
d900bd96b4 flake8 cleanup 2021-02-13 17:36:31 -08:00
Tim Mann
fb35bd50b0 Finished rewrite to parse JSON as JSON. This looks much better. 2021-02-13 17:34:34 -08:00
Tim Mann
fd61f317bf Step 1 of a rewrite to find and parse embedded JSON instead of just
running a regexp over the whole page.  This version passes the tests,
but more work is needed.
2021-02-13 16:26:33 -08:00
Tim Mann
ad49e65d1e Cleanup after running flake8 again. 2021-02-13 12:44:54 -08:00
Tim Mann
1ac23b7d8c Cleanup for pull request. Both tests still pass, successfully
fetching the video and description.
2021-02-13 12:27:22 -08:00
Tim Mann
92a3cd37a6 Look harder for the description. Both tests pass now. 2021-01-30 22:50:18 -08:00
Tim Mann
f5e049fbc2 Add a test for a page that doesn't contain manifest_url itself, but
does contain an embed/vod-XXXXXXXX url for a page that does contain
manifest_url.  This test currently fails because the description on
the inner page isn't in the OpenGraph format.
2021-01-30 22:11:21 -08:00
Tim Mann
691d549938 youtube-dl support for https://pac-12.com.
Generally works on pages that have a free video, though in this commit
getting the description sometimes fails.  Does not work on the pages
that require a TV provider login.
2021-01-30 21:33:24 -08:00
6 changed files with 166 additions and 13 deletions

View File

@ -425,6 +425,34 @@ class TestJSInterpreter(unittest.TestCase):
self._test(jsi, [''], args=['', '-'])
self._test(jsi, [], args=['', ''])
def test_slice(self):
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice()}', [0, 1, 2, 3, 4, 5, 6, 7, 8])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(0)}', [0, 1, 2, 3, 4, 5, 6, 7, 8])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(5)}', [5, 6, 7, 8])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(99)}', [])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(-2)}', [7, 8])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(-99)}', [0, 1, 2, 3, 4, 5, 6, 7, 8])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(0, 0)}', [])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(1, 0)}', [])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(0, 1)}', [0])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(3, 6)}', [3, 4, 5])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(1, -1)}', [1, 2, 3, 4, 5, 6, 7])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(-1, 1)}', [])
self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(-3, -1)}', [6, 7])
self._test('function f(){return "012345678".slice()}', '012345678')
self._test('function f(){return "012345678".slice(0)}', '012345678')
self._test('function f(){return "012345678".slice(5)}', '5678')
self._test('function f(){return "012345678".slice(99)}', '')
self._test('function f(){return "012345678".slice(-2)}', '78')
self._test('function f(){return "012345678".slice(-99)}', '012345678')
self._test('function f(){return "012345678".slice(0, 0)}', '')
self._test('function f(){return "012345678".slice(1, 0)}', '')
self._test('function f(){return "012345678".slice(0, 1)}', '0')
self._test('function f(){return "012345678".slice(3, 6)}', '345')
self._test('function f(){return "012345678".slice(1, -1)}', '1234567')
self._test('function f(){return "012345678".slice(-1, 1)}', '')
self._test('function f(){return "012345678".slice(-3, -1)}', '67')
if __name__ == '__main__':
unittest.main()

View File

@ -174,6 +174,14 @@ _NSIG_TESTS = [
'https://www.youtube.com/s/player/5604538d/player_ias.vflset/en_US/base.js',
'7X-he4jjvMx7BCX', 'sViSydX8IHtdWA',
),
(
'https://www.youtube.com/s/player/20dfca59/player_ias.vflset/en_US/base.js',
'-fLCxedkAk4LUTK2', 'O8kfRq1y1eyHGw',
),
(
'https://www.youtube.com/s/player/b12cc44b/player_ias.vflset/en_US/base.js',
'keLa5R2U00sR9SQK', 'N1OGyujjEwMnLw',
),
]

View File

@ -907,6 +907,7 @@ from .orf import (
ORFRadioCollectionIE,
)
from .outsidetv import OutsideTVIE
from .pac12 import Pac12IE
from .packtpub import (
PacktPubIE,
PacktPubCourseIE,

View File

@ -0,0 +1,80 @@
# coding: utf-8
from __future__ import unicode_literals
from .common import InfoExtractor
from ..compat import compat_str
from ..utils import try_get
class Pac12IE(InfoExtractor):
_VALID_URL = r'https?://(?:[a-z]+\.)?pac-12.com/(?:embed/)?(?P<id>.*)'
_TESTS = [{
'url': 'https://pac-12.com/videos/2020-pac-12-womens-basketball-media-day-arizona-cal-stanford',
'md5': 'c134cb64fc884658497690dca50094a3',
'info_dict': {
'id': 'vod-VGQNKGlo9Go',
'ext': 'mp4',
'title': '2020 Pac-12 Women\'s Basketball Media Day - Arizona, Cal & Stanford',
'description': 'During the 2020 Pac-12 Women\'s Basketball Media Day, Ros Gold-Onwude moderates a discussion with Arizona\'s Adia Barnes & Aari McDonald, Cal\'s Charmin Smith & Evelien Lutje Schipholt & Stanford\'s Tara VanDerveer & Kiana Williams. ',
}
}, {
'url': 'https://pac-12.com/article/2020/11/24/sonoran-dog-dish-presented-tums',
'md5': 'a91ae1eaf05cea2c5dbe6c1ab7997cc3',
'info_dict': {
'id': 'vod-YLMKpNLZvR0',
'ext': 'mp4',
'title': 'Sonoran Dog | The Dish, presented by TUMS',
'description': 'Pac-12 Networks introduces "The Dish," presented by Tums. Jaymee Sire is bringing fans a closeup to game day treats from around the Conference with each treat connecting to a Pac-12 school, bringing the flavor and recipes fans know and love right to the dish! As Arizona and USC basketball seasons tip off, the first feature item from "The Dish" is the Sonoran Dog, a beloved treat by Trojans & Wildcat fans.',
}
}]
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
drupal_settings = self._parse_json(
self._search_regex(
r'<script[^>]+type="application/json"[^>]*data-drupal-selector="drupal-settings-json">([^<]+)</script>',
webpage, 'drupal settings'), video_id)
cv = drupal_settings.get('currentVideo')
if cv is False:
# May be an event page; look for the live stream.
network = try_get(drupal_settings,
lambda x: x['pac12_react'][
'pac12_react_event_widget']['event'][
'broadcast_info']['broadcast_networks'][0][
'id'], int)
if network is not None:
cv = try_get(drupal_settings,
lambda x: x['pac12_react']['networks'][
str(network)], dict)
if not cv or 'manifest_url' not in cv:
# Video may be embedded one level deeper; look for embed URL.
vod_url = self._search_regex(
r'(https?://(?:embed\.)?pac-12\.com/(?:embed/)?vod-\w+)',
webpage, 'url', default=None)
if vod_url is None:
# Failure; no video found.
return None
return self.url_result(vod_url)
return {
# cv['id'] might be an integer, string, or missing.
'id': compat_str(cv.get('id') or video_id),
'title': (cv.get('title')
or self._html_search_meta(
['og:title', 'twitter:title',
'branch.deeplink.title'], webpage)
or self._html_search_regex(r'<title>(.+?)</title>',
webpage, 'title')),
'description': (cv.get('description')
or self._html_search_meta(
['og:description', 'twitter:description',
'description'], webpage, fatal=False)),
'url': cv['manifest_url'],
'ext': 'mp4',
}

View File

@ -1659,17 +1659,46 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
def _extract_n_function_name(self, jscode):
func_name, idx = self._search_regex(
# new: (b=String.fromCharCode(110),c=a.get(b))&&c=nfunc[idx](c)
# or: (b="nn"[+a.D],c=a.get(b))&&(c=nfunc[idx](c)s
# old: .get("n"))&&(b=nfunc[idx](b)
# older: .get("n"))&&(b=nfunc(b)
# or: (b="nn"[+a.D],c=a.get(b))&&(c=nfunc[idx](c)
# or: (PL(a),b=a.j.n||null)&&(b=nfunc[idx](b)
# or: (b="nn"[+a.D],vL(a),c=a.j[b]||null)&&(c=narray[idx](c),a.set(b,c),narray.length||nfunc("")
# old: (b=a.get("n"))&&(b=nfunc[idx](b)(?P<c>[a-z])\s*=\s*[a-z]\s*
# older: (b=a.get("n"))&&(b=nfunc(b)
r'''(?x)
(?:\(\s*(?P<b>[a-z])\s*=\s*(?:
String\s*\.\s*fromCharCode\s*\(\s*110\s*\)|
"n+"\[\s*\+?s*[\w$.]+\s*]
)\s*,(?P<c>[a-z])\s*=\s*[a-z]\s*)?
\.\s*get\s*\(\s*(?(b)(?P=b)|"n{1,2}")(?:\s*\)){2}\s*&&\s*\(\s*(?(c)(?P=c)|b)\s*=\s*
(?P<nfunc>[a-zA-Z_$][\w$]*)(?:\s*\[(?P<idx>\d+)\])?\s*\(\s*[\w$]+\s*\)
''', jscode, 'Initial JS player n function name', group=('nfunc', 'idx'))
\((?:[\w$()\s]+,)*?\s* # (
(?P<b>[a-z])\s*=\s* # b=
(?:
(?: # expect ,c=a.get(b) (etc)
String\s*\.\s*fromCharCode\s*\(\s*110\s*\)|
"n+"\[\s*\+?s*[\w$.]+\s*]
)\s*(?:,[\w$()\s]+(?=,))*|
(?P<old>[\w$]+) # a (old[er])
)\s*
(?(old)
# b.get("n")
(?:\.\s*[\w$]+\s*|\[\s*[\w$]+\s*]\s*)*?
(?:\.\s*n|\[\s*"n"\s*]|\.\s*get\s*\(\s*"n"\s*\))
| # ,c=a.get(b)
,\s*(?P<c>[a-z])\s*=\s*[a-z]\s*
(?:\.\s*[\w$]+\s*|\[\s*[\w$]+\s*]\s*)*?
(?:\[\s*(?P=b)\s*]|\.\s*get\s*\(\s*(?P=b)\s*\))
)
# interstitial junk
\s*(?:\|\|\s*null\s*)?(?:\)\s*)?&&\s*(?:\(\s*)?
(?(c)(?P=c)|(?P=b))\s*=\s* # [c|b]=
# nfunc|nfunc[idx]
(?P<nfunc>[a-zA-Z_$][\w$]*)(?:\s*\[(?P<idx>\d+)\])?\s*\(\s*[\w$]+\s*\)
''', jscode, 'Initial JS player n function name', group=('nfunc', 'idx'),
default=(None, None))
# thx bashonly: yt-dlp/yt-dlp/pull/10611
if not func_name:
self.report_warning('Falling back to generic n function search')
return self._search_regex(
r'''(?xs)
(?:(?<=[^\w$])|^) # instead of \b, which ignores $
(?P<name>(?!\d)[a-zA-Z\d_$]+)\s*=\s*function\((?!\d)[a-zA-Z\d_$]+\)
\s*\{(?:(?!};).)+?["']enhanced_except_
''', jscode, 'Initial JS player n function name', group='name')
if not idx:
return func_name

View File

@ -925,9 +925,16 @@ class JSInterpreter(object):
obj.reverse()
return obj
elif member == 'slice':
assertion(isinstance(obj, list), 'must be applied on a list')
assertion(len(argvals) == 1, 'takes exactly one argument')
return obj[argvals[0]:]
assertion(isinstance(obj, (list, compat_str)), 'must be applied on a list or string')
# From [1]:
# .slice() - like [:]
# .slice(n) - like [n:] (not [slice(n)]
# .slice(m, n) - like [m:n] or [slice(m, n)]
# [1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
assertion(len(argvals) <= 2, 'takes between 0 and 2 arguments')
if len(argvals) < 2:
argvals += (None,)
return obj[slice(*argvals)]
elif member == 'splice':
assertion(isinstance(obj, list), 'must be applied on a list')
assertion(argvals, 'takes one or more arguments')