Repository: yt-dlp/yt-dlp

Issue:
[Twitcasting] Download failing on protected videos
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting a broken site
- [X] I've verified that I'm running yt-dlp version **2022.11.11** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [X] I've searched the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [X] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

_No response_

### Provide a description that is worded well enough to be understood

There is an issue trying to download Twitcast videos and more specifically password protected videos. The issue may appear to be an extractor error when searching through the request form.  Protected videos can not be downloaded when providing a password nor will unlocking the videos manually and using the cookies from the browser work anymore.

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['-vU', '--cookies-from-browser', 'chrome', '--video-password', 'PRIVATE', '-o', 'test.mkv', 'https://twitcasting.tv/yuzukichococh/movie/661534618']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version 2022.11.11 [8b64402] (pip)
[debug] Python 3.11.0 (CPython AMD64 64bit) - Windows-10-10.0.22621-SP0 (OpenSSL 1.1.1q  5 Jul 2022)
[debug] exe versions: ffmpeg N-107100-g6a7c6ee93f-g4d45f5acbd (setts), ffprobe N-107100-g6a7c6ee93f-g4d45f5acbd
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-9.1
[Cookies] Extracting cookies from chrome
[debug] Extracting cookies from: "C:\Users\test\AppData\Local\Google\Chrome\User Data\Default\Network\Cookies"
[debug] Found local state file at "C:\Users\test\AppData\Local\Google\Chrome\User Data\Local State"
[Cookies] Extracted 2285 cookies from chrome
[debug] cookie version breakdown: {'v10': 2285, 'other': 0, 'unencrypted': 0}
[debug] Proxy map: {}
[debug] Loaded 1723 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: 2022.11.11, Current version: 2022.11.11
yt-dlp is up to date (2022.11.11)
[debug] [TwitCasting] Extracting URL: https://twitcasting.tv/yuzukichococh/movie/661534618
[TwitCasting] 661534618: Downloading webpage
ERROR: [TwitCasting] 661534618: This video is protected by a password, use the --video-password option
  File "C:\Users\test\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\common.py", line 674, in extract
    ie_result = self._real_extract(url)
                ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\test\AppData\Local\Programs\Python\Python311\Lib\site-packages\yt_dlp\extractor\twitcasting.py", line 107, in _real_extract
    raise ExtractorError('This video is protected by a password, use the --video-password option', expected=True)
```



Discussion:
This patch works with the password-protected test case in the extractor. Maybe you want to test it with your example URL as well:
```diff
diff --git a/yt_dlp/extractor/twitcasting.py b/yt_dlp/extractor/twitcasting.py
index 735cb0bb0..d015f5b18 100644
--- a/yt_dlp/extractor/twitcasting.py
+++ b/yt_dlp/extractor/twitcasting.py
@@ -88,15 +88,18 @@ def _parse_data_movie_playlist(self, dmp, video_id):
     def _real_extract(self, url):
         uploader_id, video_id = self._match_valid_url(url).groups()
 
+        webpage, urlh = self._download_webpage_handle(url, video_id)
         video_password = self.get_param('videopassword')
         request_data = None
         if video_password:
             request_data = urlencode_postdata({
                 'password': video_password,
+                **self._hidden_inputs(webpage),
             }, encoding='utf-8')
-        webpage, urlh = self._download_webpage_handle(
-            url, video_id, data=request_data,
-            headers={'Origin': 'https://twitcasting.tv'})
+            webpage, urlh = self._download_webpage_handle(
+                url, video_id, data=request_data,
+                headers={'Origin': 'https://twitcasting.tv'},
+                note='Trying video password')
         if urlh.geturl() != url and request_data:
             webpage = self._download_webpage(
                 urlh.geturl(), video_id, data=request_data,
```

Unrelated to this patch: the password cookie is stored as a session cookie, so it would not be extracted/passed with `--cookies-from-browser`. You would need to manually extract cookies from a Chrome session where you've unlocked the video and use `--cookies cookies.txt`
Tested a couple of videos and looks like it's working. Thanks!
```
[debug] Command-line config: ['-vU', '-F', '--video-password', 'PRIVATE', 'https://twitcasting.tv/yuzukichococh/movie/661534618']
[debug] Encodings: locale cp65001, fs utf-8, pref cp65001, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version 2022.11.11 [8b644025b] (win_exe)
[debug] Lazy loading extractors is disabled
[debug] Python 3.11.0 (CPython AMD64 64bit) - Windows-10-10.0.22621-SP0 (OpenSSL 1.1.1q  5 Jul 2022)
[debug] exe versions: ffmpeg N-107100-g6a7c6ee93f-g4d45f5acbd (setts), ffprobe N-107100-g6a7c6ee93f-g4d45f5acbd
[debug] Optional libraries: Cryptodome-3.15.0, brotli-1.0.9, certifi-2022.06.15, mutagen-1.45.1, sqlite3-2.6.0, websockets-9.1
[debug] Proxy map: {}
[debug] Loaded 1740 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: 2022.11.11, Current version: 2022.11.11
yt-dlp is up to date (2022.11.11)
[TwitCasting] Extracting URL: https://twitcasting.tv/yuzukichococh/movie/661534618
[TwitCasting] 661534618: Downloading webpage
[TwitCasting] 661534618: Trying video password
[TwitCasting] 661534618: Downloading live info
[TwitCasting] 661534618: Downloading m3u8 information
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec:vp9.2(10), channels, acodec, filesize, fs_approx, tbr, vbr, abr, asr, proto, vext, aext, hasaud, source, id
[info] Available formats for 661534618:
ID  EXT RESOLUTION │   FILESIZE  TBR PROTO │ VCODEC       VBR ACODEC     ABR
────────────────────────────────────────────────────────────────────────────
615 mp4 unknown    │ ~490.34MiB 615k m3u8  │ avc1.64001f 615k mp4a.40.29  0k
```
I see, that's good to know. Thanks for the extra info.


Resolving patch:
diff --git a/yt_dlp/extractor/twitcasting.py b/yt_dlp/extractor/twitcasting.py
--- a/yt_dlp/extractor/twitcasting.py
+++ b/yt_dlp/extractor/twitcasting.py
@@ -38,7 +38,7 @@ class TwitCastingIE(InfoExtractor):
             'description': 'Twitter Oficial da cantora brasileira Ivete Sangalo.',
             'thumbnail': r're:^https?://.*\.jpg$',
             'upload_date': '20110822',
-            'timestamp': 1314010824,
+            'timestamp': 1313978424,
             'duration': 32,
             'view_count': int,
         },
@@ -52,10 +52,10 @@ class TwitCastingIE(InfoExtractor):
             'ext': 'mp4',
             'title': 'Live playing something #3689740',
             'uploader_id': 'mttbernardini',
-            'description': 'Salve, io sono Matto (ma con la e). Questa è la mia presentazione, in quanto sono letteralmente matto (nel senso di strano), con qualcosa in più.',
+            'description': 'md5:1dc7efa2f1ab932fcd119265cebeec69',
             'thumbnail': r're:^https?://.*\.jpg$',
-            'upload_date': '20120212',
-            'timestamp': 1329028024,
+            'upload_date': '20120211',
+            'timestamp': 1328995624,
             'duration': 681,
             'view_count': int,
         },
@@ -64,15 +64,22 @@ class TwitCastingIE(InfoExtractor):
             'videopassword': 'abc',
         },
     }, {
-        'note': 'archive is split in 2 parts',
         'url': 'https://twitcasting.tv/loft_heaven/movie/685979292',
         'info_dict': {
             'id': '685979292',
             'ext': 'mp4',
-            'title': '南波一海のhear_here “ナタリー望月哲さんに聞く編集と「渋谷系狂騒曲」”',
-            'duration': 6964.599334,
+            'title': '【無料配信】南波一海のhear/here “ナタリー望月哲さんに聞く編集と「渋谷系狂騒曲」”',
+            'uploader_id': 'loft_heaven',
+            'description': 'md5:3a0c7b53019df987ce545c935538bacf',
+            'upload_date': '20210604',
+            'timestamp': 1622802114,
+            'thumbnail': r're:^https?://.*\.jpg$',
+            'duration': 6964,
+            'view_count': int,
+        },
+        'params': {
+            'skip_download': True,
         },
-        'playlist_mincount': 2,
     }]
 
     def _parse_data_movie_playlist(self, dmp, video_id):
@@ -88,15 +95,18 @@ def _parse_data_movie_playlist(self, dmp, video_id):
     def _real_extract(self, url):
         uploader_id, video_id = self._match_valid_url(url).groups()
 
+        webpage, urlh = self._download_webpage_handle(url, video_id)
         video_password = self.get_param('videopassword')
         request_data = None
         if video_password:
             request_data = urlencode_postdata({
                 'password': video_password,
+                **self._hidden_inputs(webpage),
             }, encoding='utf-8')
-        webpage, urlh = self._download_webpage_handle(
-            url, video_id, data=request_data,
-            headers={'Origin': 'https://twitcasting.tv'})
+            webpage, urlh = self._download_webpage_handle(
+                url, video_id, data=request_data,
+                headers={'Origin': 'https://twitcasting.tv'},
+                note='Trying video password')
         if urlh.geturl() != url and request_data:
             webpage = self._download_webpage(
                 urlh.geturl(), video_id, data=request_data,
@@ -122,7 +132,7 @@ def _real_extract(self, url):
         duration = (try_get(video_js_data, lambda x: sum(float_or_none(y.get('duration')) for y in x) / 1000)
                     or parse_duration(clean_html(get_element_by_class('tw-player-duration-time', webpage))))
         view_count = str_to_int(self._search_regex(
-            (r'Total\s*:\s*([\d,]+)\s*Views', r'総視聴者\s*:\s*([\d,]+)\s*</'), webpage, 'views', None))
+            (r'Total\s*:\s*Views\s*([\d,]+)', r'総視聴者\s*:\s*([\d,]+)\s*</'), webpage, 'views', None))
         timestamp = unified_timestamp(self._search_regex(
             r'data-toggle="true"[^>]+datetime="([^"]+)"',
             webpage, 'datetime', None))


Test patch: