この記事を作った動機

 最近ニコニコ動画を久しぶりに見てみて、動画をいくつか yt-dlp コマンドによってダウンロードしようとしたところ、パスワードとユーザ名によるログイン機能がうまく機能しない場合があることが分かった。

 普段であれば、誰かが勝手に issue でも立てるだろうと放置していただろうが、何を血迷ったのか issue を自分で立てたので、そのことについて記録したい。Issue に関してはすでに yt-dlp の方を見ればわかることなので、周辺情報について適当に書きたい。

前回の記事

issue へのリンク

yt-dlp をコンパイルする

 前提条件として、すでに作業ディレクトを作成して移動しており、anaconda 環境であることと、Linux 環境であることを置く。ニコニコ動画に関していくつか API エンドポイントの URL について候補があり試したかったというのがあり、コードを改変したあと、コンパイルする必要がったことが背景にある。結局どれもうまくいかなかったが。

リポジトリをクローン

git clone https://github.com/yt-dlp/yt-dlp.git
cd yt-dlp

環境を作成

conda create -n ytDlp
conda activate ytDlp
conda install python
conda install pip

依存関係のインストールやコンパイル、バイナリ生成

 yt-dlpリポジトリのコンパイルの項目を参考に、以下のようにして yt-dlp のバイナリを生成する。

python devscripts/install_deps.py --include-group pyinstaller
python devscripts/make_lazy_extractors.py
python -m bundle.pyinstaller
make yt-dlp

実際に起動する

./yt-dlp

# Usage: yt-dlp [OPTIONS] URL [URL...]
# 
# yt-dlp: error: You must provide at least one URL.
# Type yt-dlp --help to see a list of all options.

まとめ

# リポジトリクローン
git clone https://github.com/yt-dlp/yt-dlp.git
cd yt-dlp

# 環境作成
conda create -n ytDlp
conda activate ytDlp
conda install python
conda install pip

# コンパイル
python devscripts/install_deps.py --include-group pyinstaller
python devscripts/make_lazy_extractors.py
python -m bundle.pyinstaller
make yt-dlp

# 起動
./yt-dlp

# Usage: yt-dlp [OPTIONS] URL [URL...]
# 
# yt-dlp: error: You must provide at least one URL.
# Type yt-dlp --help to see a list of all options.

 yt-dlpコマンドで、年齢制限を何とかするyt-dlpコマンドで、年齢制限を何とかするの追記に書いていた一年以上前のときは、まともに動作していなかった気がするが、今は Google-Chrome でもクッキーを復号して認証情報を正しく利用できるようになっていそうなことが分かった。Issue を作成するために、少なくともニコニコ動画に関してはログインしないと見れない年齢制限のかかった動画でテストしたところ機能した。YouTube については未検証だが、多分今は動作するのではないかと思われる。なおpython-secretstorageが必要である。

 なお以下のログの例は、すでにブラウザ側でニコニコ動画へのログインを済ませていることを前提としている。

Google-Chrome

長いログ
[debug] Command-line config: ['https://www.nicovideo.jp/watch/sm34400723', '--merge-output-format', 'mp4', '--cookies-from-browser', 'chrome', '--embed-thumbnail', '-vU']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2026.08.19 from yt-dlp/yt-dlp [594bd50c2] (zip)
[debug] Python 3.14.7 (CPython x86_64 64bit) - Linux-7.1.10-arch1-1-x86_64-with-glibc2.44 (OpenSSL 3.5.8 25 Aug 2026, glibc 2.44)
[debug] exe versions: ffmpeg 9.0.1 (setts), ffprobe 9.0.1, rtmpdump 2.6
[debug] Optional libraries: Cryptodome-3.23.0, brotli-1.2.0, certifi-2026.07.22, mutagen-1.48.1, requests-2.34.2, secretstorage-3.5.0, sqlite3-3.53.4, urllib3-2.7.0, websockets-17.1, yt_dlp_ejs-0.8.0
[debug] JS runtimes: deno-2.9.6
[debug] Proxy map: {}
Extracting cookies from chrome
[debug] Extracting cookies from: "/home/main/.config/google-chrome/Default/Cookies"
[Cookies] Loading cookie      0/   563[debug] detected desktop environment: GNOME
[debug] Chosen keyring: GNOMEKEYRING
Extracted 508 cookies from chrome
[debug] cookie version breakdown: {'v10': 0, 'v11': 563, 'other': 0, 'unencrypted': 0}
[debug] Request Handlers: urllib, requests, websockets
[debug] Plugin directories: none
[debug] Loaded 1745 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: stable@2026.08.19 from yt-dlp/yt-dlp
yt-dlp is up to date (stable@2026.08.19 from yt-dlp/yt-dlp)
[niconico] Extracting URL: https://www.nicovideo.jp/watch/sm34400723
[niconico] sm34400723: Downloading API JSON
[niconico] sm34400723: Downloading JSON metadata
[niconico] sm34400723: Downloading m3u8 information
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec, channels, acodec, size, br, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] sm34400723: Downloading 1 format(s): video-h264-720p-1+audio-aac-192kbps
[info] Downloading video thumbnail ogp ...
[info] Writing video thumbnail ogp to: 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].jpg
[debug] Invoking hlsnative downloader on "https://delivery.domand.nicovideo.jp/hlsbid/653621994da97b3db03d5913/playlists/media/video-h264-720p.m3u8?session=bd3d666836cc261fc66512edc651c84d0b18257cb885a062000000006aa4cffc7b5851ed993b8b6d&Expires=1789186044&Signature=MEYCIQCcYuaRq~SBhWNXd63cwZ1iTVDfArDIvx7FxTcawmkT0wIhAK8a8~bNARBRI~OaDi-~-qtEE5e~kBUjpcBCMn1TMbiA&Key-Pair-Id=K2BJYD8B5280J4"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 105
[download] Destination: 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].fvideo-h264-720p-1.mp4
[download] 100% of  149.66MiB in 00:00:09 at 15.96MiB/s
[debug] Invoking hlsnative downloader on "https://delivery.domand.nicovideo.jp/hlsbid/653621994da97b3db03d5913/playlists/media/audio-aac-192kbps.m3u8?session=bd3d666836cc261fc66512edc651c84d0b18257cb885a062000000006aa4cffc7b5851ed993b8b6d&Expires=1789186044&Signature=MEUCIH7JNUOxgoJewA0c~I332y5SdU1FyBvE3dshIr7NQkglAiEA1~9AhVPBOlnCR~e8AaTeEY8jEIDmRGH0Y7v69QzsIiE_&Key-Pair-Id=K2BJYD8B5280J4"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 105
[download] Destination: 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].faudio-aac-192kbps.mp4
[download] 100% of   14.64MiB in 00:00:04 at 3.25MiB/s
[debug] ffmpeg command line: ffprobe -show_streams 'file:【合作】New Year'"'"'s Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].faudio-aac-192kbps.mp4'
[Merger] Merging formats into "【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].mp4"
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i 'file:【合作】New Year'"'"'s Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].fvideo-h264-720p-1.mp4' -i 'file:【合作】New Year'"'"'s Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].faudio-aac-192kbps.mp4' -c copy -map 0:v:0 -map 1:a:0 -bsf:a:0 aac_adtstoasc -movflags +faststart 'file:【合作】New Year'"'"'s Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].temp.mp4'
Deleting original file 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].fvideo-h264-720p-1.mp4 (pass -k to keep)
Deleting original file 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].faudio-aac-192kbps.mp4 (pass -k to keep)
[EmbedThumbnail] mutagen: Adding thumbnail to "【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].mp4"

Firefox

長いログ
[debug] Command-line config: ['https://www.nicovideo.jp/watch/sm34400723', '--merge-output-format', 'mp4', '--cookies-from-browser', 'firefox', '--embed-thumbnail', '-vU']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2026.08.19 from yt-dlp/yt-dlp [594bd50c2] (zip)
[debug] Python 3.14.7 (CPython x86_64 64bit) - Linux-7.1.10-arch1-1-x86_64-with-glibc2.44 (OpenSSL 3.5.8 25 Aug 2026, glibc 2.44)
[debug] exe versions: ffmpeg 9.0.1 (setts), ffprobe 9.0.1, rtmpdump 2.6
[debug] Optional libraries: Cryptodome-3.23.0, brotli-1.2.0, certifi-2026.07.22, mutagen-1.48.1, requests-2.34.2, secretstorage-3.5.0, sqlite3-3.53.4, urllib3-2.7.0, websockets-17.1, yt_dlp_ejs-0.8.0
[debug] JS runtimes: deno-2.9.6
[debug] Proxy map: {}
Extracting cookies from firefox
[debug] Extracting cookies from: "/home/main/.mozilla/firefox/dy4q59za.default-release/cookies.sqlite"
[debug] Firefox cookies database version: 17
Extracted 919 cookies from firefox
[debug] Request Handlers: urllib, requests, websockets
[debug] Plugin directories: none
[debug] Loaded 1745 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: stable@2026.08.19 from yt-dlp/yt-dlp
yt-dlp is up to date (stable@2026.08.19 from yt-dlp/yt-dlp)
[niconico] Extracting URL: https://www.nicovideo.jp/watch/sm34400723
[niconico] sm34400723: Downloading API JSON
[niconico] sm34400723: Downloading JSON metadata
[niconico] sm34400723: Downloading m3u8 information
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec, channels, acodec, size, br, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] sm34400723: Downloading 1 format(s): video-h264-720p-1+audio-aac-192kbps
[info] Downloading video thumbnail ogp ...
[info] Writing video thumbnail ogp to: 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].jpg
[debug] Invoking hlsnative downloader on "https://delivery.domand.nicovideo.jp/hlsbid/653621994da97b3db03d5913/playlists/media/video-h264-720p.m3u8?session=369e874ec15a42000c3a8a6cc8e9eaed0b18257cb885a062000000006aa4d00f6f24ad3b5c2bfa22&Expires=1789186063&Signature=MEUCIQCkCspoCQ4lfo~9NtSQTe4hQNdTq985riN~rUsDyarYRQIgJPGc1~w1DjXeFE1WYlh-n1n6SS5R3Sy0SVpOBTl6tTs_&Key-Pair-Id=K2BJYD8B5280J4"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 105
[download] Destination: 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].fvideo-h264-720p-1.mp4
[download] 100% of  149.66MiB in 00:00:12 at 12.05MiB/s
[debug] Invoking hlsnative downloader on "https://delivery.domand.nicovideo.jp/hlsbid/653621994da97b3db03d5913/playlists/media/audio-aac-192kbps.m3u8?session=369e874ec15a42000c3a8a6cc8e9eaed0b18257cb885a062000000006aa4d00f6f24ad3b5c2bfa22&Expires=1789186063&Signature=MEUCIQC~qbGwGKyJRmBhsJgBr3O38O8ZMZTdk8guX19DEmvjPQIgLOnBXr9mbn7Pou5p6tDgrU-6Q4pIHFt7IY2l8dYhWk0_&Key-Pair-Id=K2BJYD8B5280J4"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 105
[download] Destination: 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].faudio-aac-192kbps.mp4
[download] 100% of   14.64MiB in 00:00:04 at 2.98MiB/s
[debug] ffmpeg command line: ffprobe -show_streams 'file:【合作】New Year'"'"'s Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].faudio-aac-192kbps.mp4'
[Merger] Merging formats into "【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].mp4"
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i 'file:【合作】New Year'"'"'s Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].fvideo-h264-720p-1.mp4' -i 'file:【合作】New Year'"'"'s Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].faudio-aac-192kbps.mp4' -c copy -map 0:v:0 -map 1:a:0 -bsf:a:0 aac_adtstoasc -movflags +faststart 'file:【合作】New Year'"'"'s Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].temp.mp4'
Deleting original file 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].fvideo-h264-720p-1.mp4 (pass -k to keep)
Deleting original file 【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].faudio-aac-192kbps.mp4 (pass -k to keep)
[EmbedThumbnail] mutagen: Adding thumbnail to "【合作】New Year's Dreams 2018 ~ YA☆RI☆MA☆SU☆NE [sm34400723].mp4"

試したエンドポイント

 調べて分かったことと、ネットなど色々すでに情報がないかあさってだめだったエンドポイントを上げる。

調べて見て分かった、現行の ログイン API エンドポイントっぽいもの

 https://account.nicovideo.jp/spa/login/index.html(通常のログインページ)にて色々実験したところ、Cloudflare の anti-bot をパスさせた状態で、かつユーザ名とパスワードを入力した状態にした上で、開発者タブからオフライン状態を再現することで、現行のエンドポイントらしいものが発見された。

 ただ、anti-bot 対策がされているので、かなり厄介なことになっていそうである。また、既存の yt-dlp の実装と照らし合わせると、今のニコニコ動画の認証系はだいぶ変わっているように見受けられ、大幅な改修が必要なのではないかと思われる。

URL

https://api.id.nicovideo.jp/v1/auth/with-password

Content Type

application/json

Content of JSON

{
    "identifier": "[email address]",
    "password": "[password]",
    "identifierType": "emailOrPhone",
    "redirectUri": "https://www.nicovideo.jp/watch/sm28146938?",
    "sec": "header_pc"
}

ブラウザにおける fetch の詳細

リクエスト URL
https://api.id.nicovideo.jp/v1/auth/with-password
参照ポリシー
strict-origin-when-cross-origin
content-type
application/json
dnt
1
referer
https://account.nicovideo.jp/
sec-ch-ua
"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"
sec-ch-ua-mobile
?0
sec-ch-ua-platform
"Linux"
user-agent
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36
x-frontend-id
8
x-frontend-version
2
x-turnstile-response
1.77t9pUpfG3HnPqZkFckfoecWLIGau3aMvH44SmzyauHm8O1sW-c-e4tnZ0AVKADmNuVQT0JW6J-JZQjQpHq8zJTmCkXE5ws0Twf6LnlrytJd8pD-7IziQS-1NTCR-bHzuqbdKpPY6odFudHohFVcesUNxUEMcHAvu3H7kvac0I-6rch1hFOB4w13rbfZrO48tDEBy4WI0r3ZJPpY7Sg176PsG6vSYYIeiVEIxYcYD87pLcCqPb17A-7P8vaTpj9ZD0EJreT1W9-OdfglFeaOSfj7fGxffdEalR-GZOGada9ZSUzBVhQfUH3G0zCVDnmnlYl1oB04IvP4oDzdt9ZNw4-BY1iRAGr_lv6hBnIdDX3OYLd9FI5DTyBs83hOlYJEWcQwGCandnOQE0RAaCFNFod4d4EmVGsAb8ibhojcGASOlEYFVaR5y7grOlbFd2YFJHD3D7yg1jf-kmjcKbsqBL9X4OrEcS3mf-Z2jcTfK3TSAh-t7eE-kUM0X1fezM5GlwBvEYyy5fgGRiWj19m5pZkeKTXhcYOJYp_amy2iS4FffuFrc-tZVsEhPiyhzz4OTDcrnfddjzlimi74Nn25f9ig_RwSwHYgyFOTUgBDAIUDdDoGJ_Iz87PKs2LCuGNpmXbEQy35TcDmi_nz5oKOGGZGanMM2j0VQ1JkLPKKeek.IzNXUQKsg48UtknNP1UMsQ.b64d0bb91d1f3bdf37917b2b7a54306edce307ca4ca855c84f048409ece8a6c3
x-turnstile-sitekey
0x4AAAAAACMMWdSktHoD87sD

問題であると思われる yt-dlp の既存の実装(2026/9/11)

  • yt-dlp/yt_dlp/extractor/niconico.py

    長いコード

     以下は、yt-dlp/yt_dlp/extractor/niconico.py at master · yt-dlp/yt-dlp を一部引用したものである。

    class NiconicoBaseIE(InfoExtractor):
        _API_BASE = 'https://nvapi.nicovideo.jp'
        _BASE_URL = 'https://www.nicovideo.jp'
        _GEO_BYPASS = False
        _GEO_COUNTRIES = ['JP']
        _HEADERS = {
            'X-Frontend-ID': '6',
            'X-Frontend-Version': '0',
        }
        _LOGIN_BASE = 'https://account.nicovideo.jp'
        _NETRC_MACHINE = 'niconico'
    
        @property
        def is_logged_in(self):
            return bool(self._get_cookies('https://www.nicovideo.jp').get('user_session'))
    
        def _raise_login_error(self, message, expected=True):
            raise ExtractorError(f'Unable to login: {message}', expected=expected)
    
        def _perform_login(self, username, password):
            if self.is_logged_in:
                return
    
            self._request_webpage(
                f'{self._LOGIN_BASE}/login', None, 'Requesting session cookies')
            webpage = self._download_webpage(
                f'{self._LOGIN_BASE}/login/redirector', None,
                'Logging in', 'Unable to log in', headers={
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Referer': f'{self._LOGIN_BASE}/login',
                }, data=urlencode_postdata({
                    'mail_tel': username,
                    'password': password,
                }))
    
            if self.is_logged_in:
                return
            elif err_msg := traverse_obj(webpage, (
                {find_element(cls='notice error')}, {find_element(cls='notice__text')}, {clean_html},
            )):
                self._raise_login_error(err_msg or 'Invalid username or password')
            elif 'oneTimePw' in webpage:
                post_url = self._search_regex(
                    r'<form[^>]+action=(["\'])(?P<url>.+?)\1', webpage, 'post url', group='url')
                mfa, urlh = self._download_webpage_handle(
                    urljoin(self._LOGIN_BASE, post_url), None,
                    'Performing MFA', 'Unable to complete MFA', headers={
                        'Content-Type': 'application/x-www-form-urlencoded',
                    }, data=urlencode_postdata({
                        'otp': self._get_tfa_info('6 digit number shown on app'),
                    }))
                if self.is_logged_in:
                    return
                elif 'error-code' in parse_qs(urlh.url):
                    err_msg = traverse_obj(mfa, ({find_element(cls='pageMainMsg')}, {clean_html}))
                    self._raise_login_error(err_msg or 'MFA session expired')
                elif 'formError' in mfa:
                    err_msg = traverse_obj(mfa, (
                        {find_element(cls='formError')}, {find_element(tag='div')}, {clean_html}))
                    self._raise_login_error(err_msg or 'MFA challenge failed')
    
            self._raise_login_error('Unexpected login error', expected=False)
    

だめだったもの

  • account.nicovideo.jp/api/v1/login
{
    "meta": {
        "status": 404,
        "error-code": "NOT_FOUND",
        "error-message": "requested uri is not found on routes. URL: /api/v1/login"
    }
}
  • secure.nicovideo.jp/secure/login
ping secure.nicovideo.jp 
# ping: secure.nicovideo.jp: 名前またはサービスが不明です
  • https://account.nicovideo.jp/login/redirector(yt-dlp 2026/9/11 時点で内蔵されているログイン URL) (404 NotFound)

    /login/redirector

  • https://account.nicovideo.jp/ (404 NotFound)

    noExtra

  • https://account.nicovideo.jp/login/ (404 NotFound)

    /login/

  • https://account.nicovideo.jp/login
     https://account.nicovideo.jp/spa/login/index.html(通常のログインページ)へリダイレクトされる。

    /login/

参考にしたサイトとか