Skip to content

Instantly share code, notes, and snippets.

@pukkandan
Last active January 2, 2023 16:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pukkandan/24f13ff1ed385c5a390c1d7bd130d8f7 to your computer and use it in GitHub Desktop.
Save pukkandan/24f13ff1ed385c5a390c1d7bd130d8f7 to your computer and use it in GitHub Desktop.
yt-dlp plugin extractor to decrypt youtube nsig online
Moved to https://github.com/pukkandan/YT_NSigProxy
"""
SPDX-License-Identifier: MIT https://opensource.org/licenses/MIT
Copyright © 2022 pukkandan.ytdlp@gmail.com
yt-dlp plugin extractor to decrypt youtube nsig online
Needs yt-dlp 2022.09.17 or above
Usage: Import this file in ytdlp_plugins/extractor/__init__.py
See https://github.com/yt-dlp/yt-dlp#plugins for details
Solver Source:
https://github.com/pukkandan/yt-dlp-online-utils/blob/master/api/youtube/nparams/decrypt.js
Credits: @Lesmiscore for the implementation
Note: The solver has limited resources. Please do not abuse
"""
from yt_dlp.utils import ExtractorError, traverse_obj
from yt_dlp.extractor.youtube import YoutubeIE
SOLVER_URL = 'https://yt-dlp-online-utils.vercel.app/youtube/nparams/decrypt'
PREFER_SOLVER = False # Whether to prefer online solver over local solver
class Youtube_NsigProxyIE(YoutubeIE, plugin_name='NSIG'):
def __nsig_error(self, current, next, s, video_id, player_url, e):
self.report_warning(
f'{current} nsig extraction failed: Trying with {next}\n'
f' n = {s} ; player = {player_url}', video_id)
self.write_debug(e)
def _decrypt_nsig(self, s, video_id, player_url):
fallback = True
try:
if not player_url or not PREFER_SOLVER:
return super()._decrypt_nsig(s, video_id, player_url)
except Exception as e:
if not player_url:
raise
self.__nsig_error('Local', 'online solver', s, video_id, player_url, e)
fallback = False
try:
response_data = self._download_json(
SOLVER_URL, video_id, query={'player': player_url, 'n': s},
note='Requesting nsig decryption from online solver')
if response_data['status'] != 'ok':
raise ExtractorError(f'Failed at step "{response_data["step"]}":\n '
f'{traverse_obj(response_data, ("data", "message"))}')
self.write_debug(f'Decrypted nsig {s} => {response_data["data"]}')
return response_data['data']
except Exception as e:
if not fallback:
raise
self.__nsig_error('Online', 'local solver', s, video_id, player_url, e)
return super()._decrypt_nsig(s, video_id, player_url)
Copy link

ghost commented Sep 12, 2022

Not working with Youtube_AgeGateBypass.py

log without Youtube_AgeGateBypass:

[debug] yt-dlp version 2022.09.01 [5d7c7d656] (source)
[debug] Lazy loading extractors is disabled
[debug] Plugins: ['SamplePluginIE', 'Youtube_NsigProxyIE', 'SamplePluginPP']
[debug] Git HEAD: 22df97f9c
...skipped...
[debug] [youtube:NSIG] Extracting URL: https://www.youtube.com/watch?v=Cr381pDsSsA

log with Youtube_AgeGateBypass:

[debug] yt-dlp version 2022.09.01 [5d7c7d656] (source)
[debug] Lazy loading extractors is disabled
[debug] Plugins: ['SamplePluginIE', 'Youtube_AgeGateBypassIE', 'Youtube_NsigProxyIE', 'SamplePluginPP']
[debug] Git HEAD: 22df97f9c
...skipped...
[debug] [youtube:AGB] Extracting URL: https://www.youtube.com/watch?v=Cr381pDsSsA

notice it's youtube:AGB, not youtube:NSIG+AGB as expected

ytdlp_plugins/extractor/__init__.py :

# flake8: noqa: F401

# ℹ️ The imported name must end in "IE"
from .sample import SamplePluginIE
from .Youtube_AgeGateBypass import Youtube_AgeGateBypassIE
from .Youtube_NsigProxy import Youtube_NsigProxyIE

Or maybe i'm doing something wrong?

@pukkandan
Copy link
Author

What happens if you import them in reverse order?

Copy link

ghost commented Sep 13, 2022

What happens if you import them in reverse order?

like this?

# flake8: noqa: F401

# ℹ️ The imported name must end in "IE"
from .sample import SamplePluginIE
from .Youtube_NsigProxy import Youtube_NsigProxyIE
from .Youtube_AgeGateBypass import Youtube_AgeGateBypassIE

log:

[debug] yt-dlp version 2022.09.01 [5d7c7d656] (source)
[debug] Lazy loading extractors is disabled
[debug] Plugins: ['SamplePluginIE', 'Youtube_AgeGateBypassIE', 'Youtube_NsigProxyIE', 'SamplePluginPP']
[debug] Git HEAD: 22df97f9c
...skipped...
[debug] [youtube:AGB] Extracting URL: https://www.youtube.com/watch?v=Cr381pDsSsA

nothing changed

Copy link

ghost commented Sep 13, 2022

i can do this:

remove Youtube_AgeGateBypassIE import from ytdlp_plugins/extractor/__init__.py
and replace import in ytdlp_plugins/extractor/Youtube_NsigProxy.py to this:

from ytdlp_plugins.extractor.Youtube_AgeGateBypass import Youtube_AgeGateBypassIE as YoutubeIE

and then... it's working as expected

[debug] yt-dlp version 2022.09.01 [5d7c7d656] (source)
[debug] Lazy loading extractors is disabled
[debug] Plugins: ['SamplePluginIE', 'Youtube_NsigProxyIE', 'SamplePluginPP']
[debug] Git HEAD: 22df97f9c
...skipped...
[debug] [youtube:NSIG+AGB] Extracting URL: https://www.youtube.com/watch?v=Cr381pDsSsA

@pukkandan
Copy link
Author

hm.. The plugin system wasn't really designed with this kind of use-case in mind. I will have to see what can be changed in yt-dlp to make this easier

Copy link

ghost commented Sep 16, 2022

Everything good with latest commit, except two small things

  • small typo "Needs yt-dlp 2021.09.17 or above" => "Needs yt-dlp 2022.09.17 or above"
  • nsig always use online solver, even if PREFER_SOLVER = False

@pukkandan
Copy link
Author

@0xcc07c9 Thanks, fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment