Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/stacommu.py (Python)

Code before:
from ..utils import (
    int_or_none,
    traverse_obj,
    url_or_none,
)


class StacommuBaseIE(WrestleUniverseBaseIE):
    _NETRC_MACHINE = 'stacommu'
    _API_HOST = 'api.stacommu.jp'
    _LOGIN_QUERY = {'key': 'AIzaSyCR9czxhH2eWuijEhTNWBZ5MCcOYEUTAhg'}
    _LOGIN_HEADERS = {
        'Accept': '*/*',
        'Content-Type': 'application/json',
        'X-Client-Version': 'Chrome/JsCore/9.9.4/FirebaseCore-web',
        'Referer': 'https://www.stacommu.jp/',
        'Origin': 'https://www.stacommu.jp',
    }

    @WrestleUniverseBaseIE._TOKEN.getter
    def _TOKEN(self):
        if self._REAL_TOKEN and self._TOKEN_EXPIRY <= int(time.time()):
            self._refresh_token()

        return self._REAL_TOKEN

    def _extract_hls_key(self, data, path, decrypt):
        encryption_data = traverse_obj(data, path)
        if traverse_obj(encryption_data, ('encryptType', {int})) == 0:
            return None
        return traverse_obj(encryption_data, {'key': ('key', {decrypt}), 'iv': ('iv', {decrypt})})


class StacommuVODIE(StacommuBaseIE):
    _VALID_URL = r'https?://www\.stacommu\.jp/videos/episodes/(?P<id>[\da-zA-Z]+)'
    _TESTS = [{
        # not encrypted
        'url': 'https://www.stacommu.jp/videos/episodes/aXcVKjHyAENEjard61soZZ',
        'info_dict': {
            'id': 'aXcVKjHyAENEjard61soZZ',
            'ext': 'mp4',
            'title': 'スタコミュAWARDの裏側、ほぼ全部見せます！〜晴れ舞台の直前ドキドキ編〜',
            'description': 'md5:6400275c57ae75c06da36b06f96beb1c',
            'timestamp': 1679652000,
            'upload_date': '20230324',
            'thumbnail': 'https://image.stacommu.jp/6eLobQan8PFtBoU4RL4uGg/6eLobQan8PFtBoU4RL4uGg',
            'cast': 'count:11',
            'duration': 250,
        },
        'params': {
            'skip_download': 'm3u8',

Review comment (suggestion):
When a login is required, we need to let the users know that `--username`/`--password`/`--netrc` is needed and cookies won't work. This is admittedly a bit cringe, but `method='password'` doesn't belong anywhere in the wrestleuniverse baseclass, so I think it's what we need to do
```suggestion

    def _get_formats(self, data, path, video_id=None):
        if not traverse_obj(data, path) and not data.get('canWatch') and not self._TOKEN:
            self.raise_login_required(method='password')
        return super()._get_formats(data, path, video_id)

```

Code after:
from ..utils import (
    int_or_none,
    traverse_obj,
    url_or_none,
)


class StacommuBaseIE(WrestleUniverseBaseIE):
    _NETRC_MACHINE = 'stacommu'
    _API_HOST = 'api.stacommu.jp'
    _LOGIN_QUERY = {'key': 'AIzaSyCR9czxhH2eWuijEhTNWBZ5MCcOYEUTAhg'}
    _LOGIN_HEADERS = {
        'Accept': '*/*',
        'Content-Type': 'application/json',
        'X-Client-Version': 'Chrome/JsCore/9.9.4/FirebaseCore-web',
        'Referer': 'https://www.stacommu.jp/',
        'Origin': 'https://www.stacommu.jp',
    }

    @WrestleUniverseBaseIE._TOKEN.getter
    def _TOKEN(self):
        if self._REAL_TOKEN and self._TOKEN_EXPIRY <= int(time.time()):
            self._refresh_token()

        return self._REAL_TOKEN

    def _get_formats(self, data, path, video_id=None):
        if not traverse_obj(data, path) and not data.get('canWatch') and not self._TOKEN:
            self.raise_login_required(method='password')
        return super()._get_formats(data, path, video_id)

    def _extract_hls_key(self, data, path, decrypt):
        encryption_data = traverse_obj(data, path)
        if traverse_obj(encryption_data, ('encryptType', {int})) == 0:
            return None
        return traverse_obj(encryption_data, {'key': ('key', {decrypt}), 'iv': ('iv', {decrypt})})


class StacommuVODIE(StacommuBaseIE):
    _VALID_URL = r'https?://www\.stacommu\.jp/videos/episodes/(?P<id>[\da-zA-Z]+)'
    _TESTS = [{
        # not encrypted
        'url': 'https://www.stacommu.jp/videos/episodes/aXcVKjHyAENEjard61soZZ',
        'info_dict': {
            'id': 'aXcVKjHyAENEjard61soZZ',
            'ext': 'mp4',
            'title': 'スタコミュAWARDの裏側、ほぼ全部見せます！〜晴れ舞台の直前ドキドキ編〜',
            'description': 'md5:6400275c57ae75c06da36b06f96beb1c',
            'timestamp': 1679652000,
            'upload_date': '20230324',
            'thumbnail': 'https://image.stacommu.jp/6eLobQan8PFtBoU4RL4uGg/6eLobQan8PFtBoU4RL4uGg',