add sonarr/radarr api

This commit is contained in:
jxxghp
2023-06-13 17:26:19 +08:00
parent a7cd0dd009
commit 4074a52600
6 changed files with 449 additions and 3 deletions

View File

@ -22,7 +22,7 @@ async def read_sites(db: Session = Depends(get_db),
return Site.list(db) return Site.list(db)
@router.post("/update", response_model=schemas.Site) @router.put("/", response_model=schemas.Site)
async def update_site( async def update_site(
*, *,
db: Session = Depends(get_db), db: Session = Depends(get_db),

View File

@ -47,7 +47,7 @@ async def create_subscribe(
return {"success": result} return {"success": result}
@router.post("/update", response_model=schemas.Subscribe) @router.put("/", response_model=schemas.Subscribe)
async def update_subscribe( async def update_subscribe(
*, *,
db: Session = Depends(get_db), db: Session = Depends(get_db),
@ -67,7 +67,7 @@ async def update_subscribe(
return subscribe return subscribe
@router.post("/delete", response_model=schemas.Response) @router.delete("/", response_model=schemas.Response)
async def delete_subscribe( async def delete_subscribe(
*, *,
db: Session = Depends(get_db), db: Session = Depends(get_db),

387
app/api/servarr.py Normal file
View File

@ -0,0 +1,387 @@
from typing import Any, List
from fastapi import APIRouter, HTTPException
from app import schemas
from app.core.config import settings
from version import APP_VERSION
arr_router = APIRouter()
@arr_router.get("/system/status")
async def arr_system_status(apiKey: str) -> Any:
"""
模拟Radarr、Sonarr系统状态
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
return {
"appName": "MoviePilot",
"instanceName": "moviepilot",
"version": APP_VERSION,
"urlBase": "/api/v3"
}
@arr_router.get("/qualityProfile")
async def arr_qualityProfile(apiKey: str) -> Any:
"""
模拟Radarr、Sonarr质量配置
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
return [
{
"id": 1,
"name": "默认"
}
]
@arr_router.get("/rootfolder")
async def arr_rootfolder(apiKey: str) -> Any:
"""
模拟Radarr、Sonarr根目录
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
return [
{
"id": 1,
"path": settings.LIBRARY_PATH,
"accessible": True,
"freeSpace": 0,
"unmappedFolders": []
}
]
@arr_router.get("/tag")
async def arr_tag(apiKey: str) -> Any:
"""
模拟Radarr、Sonarr标签
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
return [
{
"id": 1,
"label": "默认"
}
]
@arr_router.get("/languageprofile")
async def arr_languageprofile(apiKey: str) -> Any:
"""
模拟Radarr、Sonarr语言
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
return {
"id": 1,
"name": "中文"
}
@arr_router.get("/movie", response_model=List[schemas.RadarrMovie])
async def arr_movies(apiKey: str) -> Any:
"""
查询Rardar电影
"""
"""
[
{
"id": 0,
"title": "string",
"originalTitle": "string",
"originalLanguage": {
"id": 0,
"name": "string"
},
"secondaryYear": 0,
"secondaryYearSourceId": 0,
"sortTitle": "string",
"sizeOnDisk": 0,
"status": "tba",
"overview": "string",
"inCinemas": "2023-06-13T09:23:41.494Z",
"physicalRelease": "2023-06-13T09:23:41.494Z",
"digitalRelease": "2023-06-13T09:23:41.494Z",
"physicalReleaseNote": "string",
"images": [
{
"coverType": "unknown",
"url": "string",
"remoteUrl": "string"
}
],
"website": "string",
"remotePoster": "string",
"year": 0,
"hasFile": true,
"youTubeTrailerId": "string",
"studio": "string",
"path": "string",
"qualityProfileId": 0,
"monitored": true,
"minimumAvailability": "tba",
"isAvailable": true,
"folderName": "string",
"runtime": 0,
"cleanTitle": "string",
"imdbId": "string",
"tmdbId": 0,
"titleSlug": "string",
"rootFolderPath": "string",
"folder": "string",
"certification": "string",
"genres": [
"string"
],
"tags": [
0
],
"added": "2023-06-13T09:23:41.494Z",
"addOptions": {
"ignoreEpisodesWithFiles": true,
"ignoreEpisodesWithoutFiles": true,
"monitor": "movieOnly",
"searchForMovie": true,
"addMethod": "manual"
},
"popularity": 0
}
]
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.get("/movie/{mid}", response_model=schemas.RadarrMovie)
async def arr_movie(apiKey: str) -> Any:
"""
查询Rardar电影
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.get("/movie/lookup", response_model=List[schemas.RadarrMovie])
async def arr_movie_lookup(apiKey: str, term: str) -> Any:
"""
查询Rardar电影 term: `tmdb:${id}`
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.put("/movie", response_model=schemas.Response)
async def arr_add_movie(apiKey: str, title: str, tmdbId: int, year: int) -> Any:
"""
新增Rardar电影订阅
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.delete("/movie/{mid}", response_model=schemas.Response)
async def arr_remove_movie(apiKey: str, mid: int) -> Any:
"""
删除Rardar电影订阅
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.get("/series", response_model=List[schemas.SonarrSeries])
async def arr_series(apiKey: str) -> Any:
"""
查询Sonarr剧集
"""
"""
[
{
"id": 0,
"title": "string",
"sortTitle": "string",
"status": "continuing",
"ended": true,
"profileName": "string",
"overview": "string",
"nextAiring": "2023-06-13T09:08:17.624Z",
"previousAiring": "2023-06-13T09:08:17.624Z",
"network": "string",
"airTime": "string",
"images": [
{
"coverType": "unknown",
"url": "string",
"remoteUrl": "string"
}
],
"originalLanguage": {
"id": 0,
"name": "string"
},
"remotePoster": "string",
"seasons": [
{
"seasonNumber": 0,
"monitored": true,
"statistics": {
"nextAiring": "2023-06-13T09:08:17.624Z",
"previousAiring": "2023-06-13T09:08:17.624Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 0,
"sizeOnDisk": 0,
"releaseGroups": [
"string"
],
"percentOfEpisodes": 0
},
"images": [
{
"coverType": "unknown",
"url": "string",
"remoteUrl": "string"
}
]
}
],
"year": 0,
"path": "string",
"qualityProfileId": 0,
"seasonFolder": true,
"monitored": true,
"useSceneNumbering": true,
"runtime": 0,
"tvdbId": 0,
"tvRageId": 0,
"tvMazeId": 0,
"firstAired": "2023-06-13T09:08:17.624Z",
"seriesType": "standard",
"cleanTitle": "string",
"imdbId": "string",
"titleSlug": "string",
"rootFolderPath": "string",
"folder": "string",
"certification": "string",
"genres": [
"string"
],
"tags": [
0
],
"added": "2023-06-13T09:08:17.624Z",
"addOptions": {
"ignoreEpisodesWithFiles": true,
"ignoreEpisodesWithoutFiles": true,
"monitor": "unknown",
"searchForMissingEpisodes": true,
"searchForCutoffUnmetEpisodes": true
},
"ratings": {
"votes": 0,
"value": 0
},
"statistics": {
"seasonCount": 0,
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 0,
"sizeOnDisk": 0,
"releaseGroups": [
"string"
],
"percentOfEpisodes": 0
},
"episodesChanged": true
}
]
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.get("/series/{tid}")
async def arr_serie(apiKey: str) -> Any:
"""
查询Sonarr剧集
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.get("/series/lookup")
async def arr_series_lookup(apiKey: str, term: str) -> Any:
"""
查询Sonarr剧集 term: `tvdb:${id}` title
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.put("/series")
async def arr_add_series(apiKey: str, title: str, seasons: list, year: int) -> Any:
"""
新增Sonarr剧集订阅
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)
@arr_router.delete("/series/{tid}")
async def arr_remove_series(apiKey: str, tid: int) -> Any:
"""
删除Sonarr剧集订阅
"""
if not apiKey or apiKey != settings.API_TOKEN:
raise HTTPException(
status_code=403,
detail="认证失败!",
)

View File

@ -3,6 +3,7 @@ from fastapi import FastAPI
from uvicorn import Config from uvicorn import Config
from app.api.apiv1 import api_router from app.api.apiv1 import api_router
from app.api.servarr import arr_router
from app.command import Command from app.command import Command
from app.core.config import settings from app.core.config import settings
from app.core.module import ModuleManager from app.core.module import ModuleManager
@ -19,6 +20,9 @@ App = FastAPI(title=settings.PROJECT_NAME,
# API路由 # API路由
App.include_router(api_router, prefix=settings.API_V1_STR) App.include_router(api_router, prefix=settings.API_V1_STR)
# Radarr、Sonarr路由
App.include_router(arr_router, prefix="/api/v3")
# uvicorn服务 # uvicorn服务
Server = uvicorn.Server(Config(App, host=settings.HOST, port=settings.PORT, reload=settings.RELOAD)) Server = uvicorn.Server(Config(App, host=settings.HOST, port=settings.PORT, reload=settings.RELOAD))

View File

@ -4,3 +4,4 @@ from .response import Response
from .site import Site from .site import Site
from .subscribe import Subscribe from .subscribe import Subscribe
from .context import Context from .context import Context
from .servarr import RadarrMovie, SonarrSeries

54
app/schemas/servarr.py Normal file
View File

@ -0,0 +1,54 @@
from typing import Optional
from pydantic import BaseModel
class RadarrMovie(BaseModel):
id: int
title: str
isAvailable: bool
monitored: bool
tmdbId: Optional[int]
imdbId: Optional[str]
titleSlug: Optional[str]
folderName: Optional[str]
path: Optional[str]
profileId: Optional[int]
qualityProfileId: Optional[int]
added: Optional[str]
hasFile: bool
class SonarrSeries:
title: str
sortTitle: Optional[str]
seasonCount: Optional[int]
status: Optional[str]
overview: Optional[str]
network: Optional[str]
airTime: Optional[str]
images: Optional[list]
remotePoster: Optional[str]
seasons: Optional[list]
year: int
path: Optional[str]
profileId: Optional[int]
languageProfileId: Optional[int]
seasonFolder: Optional[bool]
monitored: Optional[bool]
useSceneNumbering: Optional[bool]
runtime: Optional[int]
tvdbId: Optional[int]
tvRageId: Optional[int]
tvMazeId: Optional[int]
firstAired: Optional[str]
seriesType: Optional[str]
cleanTitle: Optional[str]
imdbId: Optional[str]
titleSlug: Optional[str]
certification: Optional[str]
genres: Optional[list]
tags: Optional[list]
added: Optional[str]
ratings: Optional[dict]
qualityProfileId: Optional[int]
statistics: Optional[dict]