Repository: yt-dlp/yt-dlp

Issue:
[NSFW] erocast.me
### Checklist

- [X] I'm reporting a new site support request
- [X] I've verified that I'm running yt-dlp version **2022.05.18** ([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 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

Worldwide

### Example URLs

https://erocast.me/track/3212/conversational-audio-6-6-22

### Description

Hi there, I found eroshare.me for audio tracks but it seems yt-dlp doesn't support this site at this time. I'd love if support could be added :) Thanks all!

### Verbose log

```shell
[debug] Command-line config: ['-vU', 'https://erocast.me/track/3212/conversational-audio-6-6-22']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version 2022.05.18 [b14d52355]
[debug] Python version 3.10.4 (CPython 64bit) - macOS-12.4-arm64-arm-64bit
[debug] Checking exe version: ffprobe -bsfs
[debug] Checking exe version: ffmpeg -bsfs
[debug] exe versions: ffmpeg 5.0.1 (setts), ffprobe 5.0.1
[debug] Optional libraries: Cryptodome-3.14.1, brotli-1.0.9, certifi-2021.10.08, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
Latest version: 2022.05.18, Current version: 2022.05.18
yt-dlp is up to date (2022.05.18)
[debug] [generic] Extracting URL: https://erocast.me/track/3212/conversational-audio-6-6-22
[generic] conversational-audio-6-6-22: Requesting header
WARNING: [generic] Falling back on generic information extractor.
[generic] conversational-audio-6-6-22: Downloading webpage
[generic] conversational-audio-6-6-22: Extracting information
[debug] Looking for video embeds
ERROR: Unsupported URL: https://erocast.me/track/3212/conversational-audio-6-6-22
Traceback (most recent call last):
  File "/opt/homebrew/Cellar/yt-dlp/2022.5.18/libexec/lib/python3.10/site-packages/yt_dlp/YoutubeDL.py", line 1395, in wrapper
    return func(self, *args, **kwargs)
  File "/opt/homebrew/Cellar/yt-dlp/2022.5.18/libexec/lib/python3.10/site-packages/yt_dlp/YoutubeDL.py", line 1465, in __extract_info
    ie_result = ie.extract(url)
  File "/opt/homebrew/Cellar/yt-dlp/2022.5.18/libexec/lib/python3.10/site-packages/yt_dlp/extractor/common.py", line 642, in extract
    ie_result = self._real_extract(url)
  File "/opt/homebrew/Cellar/yt-dlp/2022.5.18/libexec/lib/python3.10/site-packages/yt_dlp/extractor/generic.py", line 4031, in _real_extract
    raise UnsupportedError(url)
yt_dlp.utils.UnsupportedError: Unsupported URL: https://erocast.me/track/3212/conversational-audio-6-6-22
```



Discussion:
> `https://erocast.me/track/3212/conversational-audio-6-6-22` » `https://erocast.me/stream/hls/3212` » `track.m3u8` » `ffmpeg -i "file:track.m3u8" -codec copy "file:track.mkv"`.
> 
> CloudFlare protects it with XSRF-TOKEN or "not a robot". it whitelists the IP half and hour or so. (how to work around cloudflare..?)

Did you try cookies?

```
$ ./yt-dlp.exe -v --cookies cookies.firefox-private.txt "https://erocast.me/stream/hls/3212"
[debug] Command-line config: ['-v', '--cookies', 'cookies.firefox-private.txt', 'https://erocast.me/stream/hls/3212']
[debug] Portable config "D:\ytdlp\yt-dlp.conf": ['--ffmpeg-location', '.\\ffmpeg\\bin', '--ignore-config']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out cp1252 (No ANSI), error cp1252 (No ANSI), screen cp1252 (No ANSI)
[debug] yt-dlp version 2022.05.18 [b14d523] (win_exe)
[debug] Python version 3.8.10 (CPython 64bit) - Windows-7-6.1.7601-SP1
[debug] Checking exe version: ".\ffmpeg\bin\ffprobe" -bsfs
[debug] Checking exe version: ".\ffmpeg\bin\ffmpeg" -bsfs
[debug] exe versions: ffmpeg N-105453-gcc5eb2e662-20220204 (setts), ffprobe N-105453-gcc5eb2e662-20220204
[debug] Optional libraries: Cryptodome-3.14.1, brotli-1.0.9, certifi-2021.10.08, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.3
[debug] Proxy map: {}
[debug] [generic] Extracting URL: https://erocast.me/stream/hls/3212
[generic] 3212: Requesting header
WARNING: [generic] Falling back on generic information extractor.
[generic] 3212: Downloading webpage
[debug] Identified a M3U playlist
[generic] 3212: Downloading m3u8 information
[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] 3212: Downloading 1 format(s): 0
[debug] Invoking hlsnative downloader on "https://erocast.me/stream/hls/3212"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 71
[download] Destination: 3212 [3212].mp4
[debug] File locking is not supported on this platform. Proceeding without locking
[download]   1.9% of ~24.00MiB at 216.71KiB/s ETA 01:32 (frag 1/71)
ERROR: Interrupted by user

```

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
@@ -574,6 +574,7 @@
 from .eplus import EplusIbIE
 from .epoch import EpochIE
 from .eporner import EpornerIE
+from .erocast import ErocastIE
 from .eroprofile import (
     EroProfileIE,
     EroProfileAlbumIE,
diff --git a/yt_dlp/extractor/erocast.py b/yt_dlp/extractor/erocast.py
new file mode 100644
--- /dev/null
+++ b/yt_dlp/extractor/erocast.py
@@ -0,0 +1,63 @@
+from .common import InfoExtractor
+from ..utils import (
+    int_or_none,
+    parse_iso8601,
+    str_or_none,
+    traverse_obj,
+    url_or_none,
+)
+
+
+class ErocastIE(InfoExtractor):
+    _VALID_URL = r'https?://(?:www\.)?erocast\.me/track/(?P<id>[0-9]+)'
+    _TESTS = [{
+        'url': 'https://erocast.me/track/9787/f',
+        'md5': 'af63b91f5f231096aba54dd682abea3b',
+        'info_dict': {
+            'id': '9787',
+            'title': '[F4M] Your roommate, who is definitely not possessed by an alien, suddenly wants to fuck you',
+            'url': 'https://erocast.s3.us-east-2.wasabisys.com/1220419/track.m3u8',
+            'ext': 'm4a',
+            'age_limit': 18,
+            'release_timestamp': 1696178652,
+            'release_date': '20231001',
+            'modified_timestamp': int,
+            'modified_date': str,
+            'description': 'ExtraTerrestrial Tuesday!',
+            'uploader': 'clarissaisshy',
+            'uploader_id': '8113',
+            'uploader_url': 'https://erocast.me/clarissaisshy',
+            'thumbnail': 'https://erocast.s3.us-east-2.wasabisys.com/1220418/conversions/1696179247-lg.jpg',
+            'duration': 2307,
+            'view_count': int,
+            'comment_count': int,
+            'webpage_url': 'https://erocast.me/track/9787/f4m-your-roommate-who-is-definitely-not-possessed-by-an-alien-suddenly-wants-to-fuck-you',
+        }
+    }]
+
+    def _real_extract(self, url):
+        video_id = self._match_id(url)
+        webpage = self._download_webpage(url, video_id)
+        data = self._search_json(
+            rf'<script>\s*var song_data_{video_id}\s*=', webpage, 'data', video_id, end_pattern=r'</script>')
+
+        return {
+            'id': video_id,
+            'formats': self._extract_m3u8_formats(
+                data.get('file_url') or data['stream_url'], video_id, 'm4a', m3u8_id='hls'),
+            'age_limit': 18,
+            **traverse_obj(data, {
+                'title': ('title', {str}),
+                'description': ('description', {str}),
+                'release_timestamp': ('created_at', {parse_iso8601}),
+                'modified_timestamp': ('updated_at', {parse_iso8601}),
+                'uploader': ('user', 'name', {str}),
+                'uploader_id': ('user', 'id', {str_or_none}),
+                'uploader_url': ('user', 'permalink_url', {url_or_none}),
+                'thumbnail': ('artwork_url', {url_or_none}),
+                'duration': ('duration', {int_or_none}),
+                'view_count': ('plays', {int_or_none}),
+                'comment_count': ('comment_count', {int_or_none}),
+                'webpage_url': ('permalink_url', {url_or_none}),
+            }),
+        }


Test patch: