|
28 | 28 | from app.adapters.web.security.access import verify_token, verify_apitoken |
29 | 29 | from app.api.deps import get_current_active_user, get_current_active_superuser |
30 | 30 | from app.schemas.category import CategoryConfig |
| 31 | +from app.schemas.event import MediaSourceInfo as _SchemaMediaSourceInfo |
31 | 32 | from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaSource, MediaType |
32 | 33 | from app.domain.media import is_music_media_source, normalize_music_type, parse_media_source_selection |
33 | 34 | from app.schemas.media import normalize_media_source, resolve_media_identity |
34 | 35 |
|
35 | 36 | router = ResponseAPIRouter() |
36 | 37 |
|
37 | 38 |
|
| 39 | +_BUILTIN_MEDIA_SOURCES = ( |
| 40 | + _SchemaMediaSourceInfo(name="TheMovieDb", media_source=MediaSource.TMDB), |
| 41 | + _SchemaMediaSourceInfo(name="豆瓣", media_source=MediaSource.Douban), |
| 42 | + _SchemaMediaSourceInfo(name="Bangumi", media_source=MediaSource.Bangumi), |
| 43 | + _SchemaMediaSourceInfo(name="AniList", media_source=MediaSource.AniList), |
| 44 | + _SchemaMediaSourceInfo(name="IMDb", media_source=MediaSource.IMDb), |
| 45 | + _SchemaMediaSourceInfo(name="TVDB", media_source=MediaSource.TVDB), |
| 46 | + _SchemaMediaSourceInfo( |
| 47 | + name="MusicBrainz", |
| 48 | + media_source=MediaSource.MusicBrainz, |
| 49 | + media_types=[MediaType.MUSIC], |
| 50 | + ), |
| 51 | + _SchemaMediaSourceInfo( |
| 52 | + name="TheAudioDB", |
| 53 | + media_source=MediaSource.TheAudioDB, |
| 54 | + media_types=[MediaType.MUSIC], |
| 55 | + ), |
| 56 | + _SchemaMediaSourceInfo( |
| 57 | + name="豆瓣音乐", |
| 58 | + media_source=MediaSource.DoubanMusic, |
| 59 | + media_types=[MediaType.MUSIC], |
| 60 | + ), |
| 61 | + _SchemaMediaSourceInfo(name="哔哩哔哩", media_source=MediaSource.Bilibili), |
| 62 | + _SchemaMediaSourceInfo(name="芒果TV", media_source=MediaSource.MangoTV), |
| 63 | + _SchemaMediaSourceInfo(name="咪咕视频", media_source=MediaSource.MiguVideo), |
| 64 | + _SchemaMediaSourceInfo(name="腾讯视频", media_source=MediaSource.TencentVideo), |
| 65 | + _SchemaMediaSourceInfo(name="爱奇艺", media_source=MediaSource.Iqiyi), |
| 66 | +) |
| 67 | + |
| 68 | + |
| 69 | +def _registered_media_sources() -> list[_SchemaMediaSourceInfo]: |
| 70 | + """合并内置与启用插件声明的媒体来源,并按来源标识去重。""" |
| 71 | + from app.runtime.extensions.plugin_manager import PluginManager |
| 72 | + |
| 73 | + result = list(_BUILTIN_MEDIA_SOURCES) |
| 74 | + seen = {source.media_source for source in result} |
| 75 | + for raw_source in PluginManager().get_media_sources(): |
| 76 | + try: |
| 77 | + source = _SchemaMediaSourceInfo.model_validate(raw_source) |
| 78 | + except Exception: |
| 79 | + continue |
| 80 | + if source.media_source in seen: |
| 81 | + continue |
| 82 | + result.append(source) |
| 83 | + seen.add(source.media_source) |
| 84 | + return result |
| 85 | + |
| 86 | + |
38 | 87 | def _split_media_source_query(value: object) -> tuple[str, ...]: |
39 | 88 | """展开重复或逗号分隔的来源参数,并在枚举校验前规范历史别名。""" |
40 | 89 | if value in (None, ""): |
@@ -324,6 +373,16 @@ def __get_source(obj: Union[_SchemaMediaInfo, _SchemaMediaPerson, dict]): |
324 | 373 | return sorted_result[(page - 1) * count : page * count] |
325 | 374 |
|
326 | 375 |
|
| 376 | +@router.get( |
| 377 | + "/source", |
| 378 | + summary="获取媒体数据源", |
| 379 | + response_model=list[_SchemaMediaSourceInfo], |
| 380 | +) |
| 381 | +def source(_: _SchemaTokenPayload = Depends(verify_token)) -> list[_SchemaMediaSourceInfo]: |
| 382 | + """返回内置及启用插件注册的媒体数据源,供前端统一构造来源选项。""" |
| 383 | + return _registered_media_sources() |
| 384 | + |
| 385 | + |
327 | 386 | @router.post( |
328 | 387 | "/scrape/{storage}", summary="刮削媒体信息", response_model=_SchemaResponse[None] |
329 | 388 | ) |
|
0 commit comments