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)
@router.post("/update", response_model=schemas.Site)
@router.put("/", response_model=schemas.Site)
async def update_site(
*,
db: Session = Depends(get_db),

View File

@ -47,7 +47,7 @@ async def create_subscribe(
return {"success": result}
@router.post("/update", response_model=schemas.Subscribe)
@router.put("/", response_model=schemas.Subscribe)
async def update_subscribe(
*,
db: Session = Depends(get_db),
@ -67,7 +67,7 @@ async def update_subscribe(
return subscribe
@router.post("/delete", response_model=schemas.Response)
@router.delete("/", response_model=schemas.Response)
async def delete_subscribe(
*,
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 app.api.apiv1 import api_router
from app.api.servarr import arr_router
from app.command import Command
from app.core.config import settings
from app.core.module import ModuleManager
@ -19,6 +20,9 @@ App = FastAPI(title=settings.PROJECT_NAME,
# API路由
App.include_router(api_router, prefix=settings.API_V1_STR)
# Radarr、Sonarr路由
App.include_router(arr_router, prefix="/api/v3")
# uvicorn服务
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 .subscribe import Subscribe
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]