Repository: yt-dlp/yt-dlp

Issue:
[niconico] Some metadata extraction is broken
### Checklist

- [X] I'm reporting a broken site
- [X] I've verified that I'm running yt-dlp version **2022.03.08.1**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
- [X] I've checked that all provided URLs are alive and playable in a browser
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/ytdl-org/youtube-dl#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)

### Description

It seems niconico made some changes that break some metadata extraction. I've noticed the following 2 problems: 

1) thumbnail extraction is broken. It downloads a much lower quality than it should and the file extension is strange

2) the `uploader` field returns NA for ch.nicovideo links. Works as expected if replaced with `channel`.

Both of these were working normally as of 1 week ago.


### Verbose log

```shell
` yt-dlp --ignore-config --verbose --write-thumbnail -o '%(uploader)s %(upload_date)s].%(ext)s' https://www.nicovideo.jp/watch/so39722713
[debug] Command-line config: ['--ignore-config', '--verbose', '--write-thumbnail', '-o', '%(uploader)s %(upload_date)s].%(ext)s', 'https://www.nicovideo.jp/watch/so39722713']
[debug] Encodings: locale UTF-8, fs utf-8, out utf-8, err utf-8, pref UTF-8
[debug] yt-dlp version 2022.03.08.1 [c0c2c57d3]
[debug] Lazy loading extractors is disabled
[debug] Python version 3.10.3 (CPython 64bit) - Linux-5.16.16-arch1-1-x86_64-with-glibc2.35
[debug] Checking exe version: ffmpeg -bsfs
[debug] Checking exe version: ffprobe -bsfs
[debug] exe versions: ffmpeg 5.0 (setts), ffprobe 5.0
[debug] Optional libraries: brotli, certifi, Cryptodome, mutagen, sqlite, websockets
[debug] Proxy map: {}
[debug] [niconico] Extracting URL: https://www.nicovideo.jp/watch/so39722713
[niconico] so39722713: Downloading webpage
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec:vp9.2(10), acodec, filesize, fs_approx, tbr, vbr, abr, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] so39722713: Downloading 1 format(s): h264_720p-aac_192kbps-http
[info] Downloading video thumbnail 0 ...
[info] Writing video thumbnail 0 to: NA 20211207].84925062
[debug] Invoking downloader on "niconico_dmc:so39722713/archive_h264_720p/archive_aac_192kbps"
[niconico_dmc] Downloading from DMC
[niconico] so39722713: Downloading JSON metadata for h264_720p-aac_192kbps-http
[niconico] so39722713: Acquiring permission for downloading video
[niconico_dmc] Heartbeat with 40 second interval ...
[download] Destination: NA 20211207].mp4
`
```



Discussion:

Resolving patch:
diff --git a/yt_dlp/extractor/niconico.py b/yt_dlp/extractor/niconico.py
--- a/yt_dlp/extractor/niconico.py
+++ b/yt_dlp/extractor/niconico.py
@@ -25,7 +25,10 @@
     parse_duration,
     parse_filesize,
     parse_iso8601,
+    parse_resolution,
+    qualities,
     remove_start,
+    str_or_none,
     traverse_obj,
     try_get,
     unescapeHTML,
@@ -430,18 +433,25 @@ def get_video_info(*items, get_first=True, **kwargs):
             # find in json (logged in)
             tags = traverse_obj(api_data, ('tag', 'items', ..., 'name'))
 
+        thumb_prefs = qualities(['url', 'middleUrl', 'largeUrl', 'player', 'ogp'])
+
         return {
             'id': video_id,
             '_api_data': api_data,
             'title': get_video_info(('originalTitle', 'title')) or self._og_search_title(webpage, default=None),
             'formats': formats,
-            'thumbnail': get_video_info('thumbnail', 'url') or self._html_search_meta(
-                ('image', 'og:image'), webpage, 'thumbnail', default=None),
+            'thumbnails': [{
+                'id': key,
+                'url': url,
+                'ext': 'jpg',
+                'preference': thumb_prefs(key),
+                **parse_resolution(url, lenient=True),
+            } for key, url in (get_video_info('thumbnail') or {}).items() if url],
             'description': clean_html(get_video_info('description')),
-            'uploader': traverse_obj(api_data, ('owner', 'nickname')),
+            'uploader': traverse_obj(api_data, ('owner', 'nickname'), ('channel', 'name'), ('community', 'name')),
+            'uploader_id': str_or_none(traverse_obj(api_data, ('owner', 'id'), ('channel', 'id'), ('community', 'id'))),
             'timestamp': parse_iso8601(get_video_info('registeredAt')) or parse_iso8601(
                 self._html_search_meta('video:release_date', webpage, 'date published', default=None)),
-            'uploader_id': traverse_obj(api_data, ('owner', 'id')),
             'channel': traverse_obj(api_data, ('channel', 'name'), ('community', 'name')),
             'channel_id': traverse_obj(api_data, ('channel', 'id'), ('community', 'id')),
             'view_count': int_or_none(get_video_info('count', 'view')),
diff --git a/yt_dlp/utils.py b/yt_dlp/utils.py
--- a/yt_dlp/utils.py
+++ b/yt_dlp/utils.py
@@ -2418,11 +2418,14 @@ def parse_count(s):
         return str_to_int(mobj.group(1))
 
 
-def parse_resolution(s):
+def parse_resolution(s, *, lenient=False):
     if s is None:
         return {}
 
-    mobj = re.search(r'(?<![a-zA-Z0-9])(?P<w>\d+)\s*[xX×,]\s*(?P<h>\d+)(?![a-zA-Z0-9])', s)
+    if lenient:
+        mobj = re.search(r'(?P<w>\d+)\s*[xX×,]\s*(?P<h>\d+)', s)
+    else:
+        mobj = re.search(r'(?<![a-zA-Z0-9])(?P<w>\d+)\s*[xX×,]\s*(?P<h>\d+)(?![a-zA-Z0-9])', s)
     if mobj:
         return {
             'width': int(mobj.group('w')),


Test patch: