Repository: yt-dlp/yt-dlp

Issue:
Mocha video
### Checklist

- [X] I'm reporting a new site support request
- [X] I've verified that I'm running yt-dlp version **2022.04.08** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- [X] I've checked that all provided URLs are alive and playable in a browser
- [X] I've checked that none of provided URLs [violate any copyrights](https://github.com/ytdl-org/youtube-dl#can-you-add-support-for-this-anime-video-site-or-site-which-shows-current-movies-for-free) or contain any [DRM](https://en.wikipedia.org/wiki/Digital_rights_management) to the best of my knowledge
- [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 am willing to share it if required

### Region

Vietnam

### Example URLs

http://video.mocha.com.vn/chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039

### Description

There seems to be no playlist

### Verbose log

```shell
[debug] Command-line config: ['-vU', 'http://video.mocha.com.vn/chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039']
[debug] Encodings: locale cp1252, fs utf-8, out utf-8, err utf-8, pref cp1252
[debug] yt-dlp version 2022.04.08 [7884ade] (win_exe)
[debug] Python version 3.8.10 (CPython 64bit) - Windows-10-10.0.19044-SP0
[debug] Checking exe version: ffmpeg -bsfs
[debug] Checking exe version: avconv -bsfs
[debug] Checking exe version: ffprobe -bsfs
[debug] Checking exe version: avprobe -bsfs
[debug] exe versions: none
[debug] Optional libraries: brotli, certifi, Cryptodome, mutagen, sqlite, websockets
[debug] Proxy map: {}
Latest version: 2022.04.08, Current version: 2022.04.08
yt-dlp is up to date (2022.04.08)
[debug] [generic] Extracting URL: http://video.mocha.com.vn/chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039
[generic] chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039: Requesting header
WARNING: [generic] Falling back on generic information extractor.
[generic] chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039: Downloading webpage
[generic] chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039: Extracting information
[debug] Looking for video embeds
ERROR: Unsupported URL: http://video.mocha.com.vn/chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039
Traceback (most recent call last):
  File "yt_dlp\YoutubeDL.py", line 1408, in wrapper
  File "yt_dlp\YoutubeDL.py", line 1478, in __extract_info
  File "yt_dlp\extractor\common.py", line 641, in extract
  File "yt_dlp\extractor\generic.py", line 4039, in _real_extract
yt_dlp.utils.UnsupportedError: Unsupported URL: http://video.mocha.com.vn/chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039
```



Discussion:
Based on your example, the video is in `http://apivideo.mocha.com.vn:8081/onMediaBackendBiz/mochavideo/getVideoDetail?url=<video_url>&token=` it will return json and the video data is in `['data']['videoDetail']['list_resolution']` and from there, we can download the video in ['video_path']

Resolving patch:
diff --git a/yt_dlp/extractor/_extractors.py b/yt_dlp/extractor/_extractors.py
--- a/yt_dlp/extractor/_extractors.py
+++ b/yt_dlp/extractor/_extractors.py
@@ -943,6 +943,7 @@
 )
 from .mlssoccer import MLSSoccerIE
 from .mnet import MnetIE
+from .mocha import MochaVideoIE
 from .moevideo import MoeVideoIE
 from .mofosex import (
     MofosexIE,
diff --git a/yt_dlp/extractor/mocha.py b/yt_dlp/extractor/mocha.py
new file mode 100644
--- /dev/null
+++ b/yt_dlp/extractor/mocha.py
@@ -0,0 +1,66 @@
+from .common import InfoExtractor
+from ..utils import int_or_none, traverse_obj
+
+
+class MochaVideoIE(InfoExtractor):
+    _VALID_URL = r'https?://video.mocha.com.vn/(?P<video_slug>[\w-]+)'
+    _TESTS = [{
+        'url': 'http://video.mocha.com.vn/chuyen-meo-gia-su-tu-thong-diep-cuoc-song-v18694039',
+        'info_dict': {
+            'id': '18694039',
+            'title': 'Chuyện mèo giả sư tử | Thông điệp cuộc sống',
+            'ext': 'mp4',
+            'view_count': int,
+            'like_count': int,
+            'dislike_count': int,
+            'display_id': 'chuyen-meo-gia-su-tu-thong-diep-cuoc-song',
+            'thumbnail': 'http://mcvideomd1fr.keeng.net/playnow/images/20220505/ad0a055d-2f69-42ca-b888-4790041fe6bc_640x480.jpg',
+            'description': '',
+            'duration': 70,
+            'timestamp': 1652254203,
+            'upload_date': '20220511',
+            'comment_count': int,
+            'categories': ['Kids']
+        }
+    }]
+
+    def _real_extract(self, url):
+        video_slug = self._match_valid_url(url).group('video_slug')
+        json_data = self._download_json(
+            'http://apivideo.mocha.com.vn:8081/onMediaBackendBiz/mochavideo/getVideoDetail',
+            video_slug, query={'url': url, 'token': ''})['data']['videoDetail']
+        video_id = str(json_data['id'])
+        video_urls = (json_data.get('list_resolution') or []) + [json_data.get('original_path')]
+
+        formats, subtitles = [], {}
+        for video in video_urls:
+            if isinstance(video, str):
+                formats.extend([{'url': video, 'ext': 'mp4'}])
+            else:
+                fmts, subs = self._extract_m3u8_formats_and_subtitles(
+                    video.get('video_path'), video_id, ext='mp4')
+                formats.extend(fmts)
+                self._merge_subtitles(subs, target=subtitles)
+
+        self._sort_formats(formats)
+
+        return {
+            'id': video_id,
+            'display_id': json_data.get('slug') or video_slug,
+            'title': json_data.get('name'),
+            'formats': formats,
+            'subtitles': subtitles,
+            'description': json_data.get('description'),
+            'duration': json_data.get('durationS'),
+            'view_count': json_data.get('total_view'),
+            'like_count': json_data.get('total_like'),
+            'dislike_count': json_data.get('total_unlike'),
+            'thumbnail': json_data.get('image_path_thumb'),
+            'timestamp': int_or_none(json_data.get('publish_time'), scale=1000),
+            'is_live': json_data.get('isLive'),
+            'channel': traverse_obj(json_data, ('channels', '0', 'name')),
+            'channel_id': traverse_obj(json_data, ('channels', '0', 'id')),
+            'channel_follower_count': traverse_obj(json_data, ('channels', '0', 'numfollow')),
+            'categories': traverse_obj(json_data, ('categories', ..., 'categoryname')),
+            'comment_count': json_data.get('total_comment'),
+        }


Test patch: