All of the endpoints below are available under the plugin base path: http(s)://{ShokoHost}:{ShokoPort}/api/plugin/ShokoRelay
They can be interacted with easily using /swagger/ at: http(s)://{ShokoHost}:{ShokoPort}/swagger
Endpoints managed by DashboardController
GET /dashboard/{*path} -> GetControllerPage
GET /config -> GetConfig
POST /config -> SaveConfig
GET /config/schema -> GetConfigSchema
GET /tasks/active -> GetActiveTasks
GET /tasks/completed -> GetCompletedTasks
POST /tasks/clear/{taskName} -> ClearTaskResult
GET /logs/{fileName} -> GetLog
GetControllerPageServes the plugin's frontend components and static assets from thedashboardfolder./dashboard(no path): Serves the main settings dashboard (dashboard.cshtml)./dashboard/player: Serves the stand-alone AnimeThemes video player (player.cshtml)./dashboard/{assetPath}: Serves static assets (JS, CSS, fonts, images).- The controller uses
FileExtensionContentTypeProviderfor MIME mapping and automatically injects a<base>tag.
GetConfigreturns the current configuration payload (JSON) used by the dashboard page.- The
ConfigProviderhandles serialization and sanitization. Structure is nested intoAutomation,Playback, andAdvanced. - This also includes
anidb_vfs_overrides.csvin the response as a separate entry from the main payload.
- The
SaveConfigpersists automation/provider settings (tokens handled separately)./configdoes not expose the Plex token. Instead the response includesPlexLibrary.HasToken.
GetConfigSchemareturns a JSON schema representation ofRelayConfigproperties.- Properties within the
AdvancedConfigclass are automatically flagged withAdvanced: true.
- Properties within the
GetActiveTasksreturns a list of unique task identifiers currently running on the server.GetCompletedTasksreturns a dictionary of results for tasks that finished while the dashboard was disconnected or before a refresh.ClearTaskResultacknowledges and removes a stored result from the server's memory.GetLogserves report files created under the plugin'slogsdirectory.- This endpoint serves the file as
text/plainwithout a download name, allowing it to be viewed directly in a browser tab.
- This endpoint serves the file as
Notes:
All automation endpoints utilize the LogAndReturn helper to provide a direct logUrl in the response. Reports include:
/plex/collections/build -> collections-report.log
/plex/ratings/apply -> ratings-report.log
/vfs -> vfs-report.log
/shoko/remove-missing -> remove-missing-report.log
/sync-watched -> sync-watched-report.log
/animethemes/vfs/build -> at-vfs-report.log
/animethemes/vfs/map -> at-map-report.log
/animethemes/mp3?batch=true -> at-mp3-report.log
Endpoints managed by MetadataController
GET / -> GetMediaProvider
GET /matches?filename={path}&title={id}&manual=1 -> Match (for preview/testing)
POST /matches?filename={path}&title={id}&manual=1 -> Match
GET /collections/{groupId} -> GetCollection
GET /collections/user/{groupId}?t={ticks} -> GetCollectionPoster (image)
GET /metadata/{ratingKey}?includeChildren={0|1} -> GetMetadata
GET /metadata/{ratingKey}/children -> GetChildren
GET /metadata/{ratingKey}/grandchildren -> GetGrandchildren
GET /metadata/{ratingKey}/images -> GetImages
GET /metadata/{ratingKey}/extras -> GetExtras
GetMediaProviderreturns the agent descriptor describing supported types and features.Matchlooks up a series by filename or title. Priority is given to IDs found in the path.filename: The file path provided by Plex.title: The Shoko Series ID (used whenmanual=1).manual: (default 0) set to 1 to force identification via thetitleparameter.- Testing the
GETendpoint would use the following format:/matches?title={ShokoSeriesID}&manual=1
GetCollectionretrieves collection metadata for a given group ID.GetCollectionPosterreturns the poster image from the!CollectionPostersdirectory.t: (optional) timestamp ticks used for cache busting.
GetMetadatareturns full metadata for a ratingKey (series/season/episode).includeChildren: (default 0) set to 1 to embed immediate children in the response.
GetChildren/GetGrandchildrenreturn only the immediate or second-level child items respectively.GetImagesreturns aMediaContainerwith anImagearray used by Plex when fetching all artwork.GetExtrasreturns an emptyMediaContainerto satisfy Plex requirements and prevent 404 errors during metadata refreshes.
Notes:
- TMDB episode-numbering is honoured when enabled (uses
IShokoEpisode.TmdbEpisodes). - Hidden episodes are excluded from all metadata results.
- RatingKey formats supported:
123(Series)123s4(Season 4 of series 123)e56789(Episode)e56789p2(Episode 56789, Part 2)a123(AniDB ID 123 alias, resolves to Shoko Series)
- Crossover episodes (files belonging to multiple series) are skipped for local metadata/subtitle linking to avoid conflicts.
Endpoints are managed by PlexController
GET /plex/auth -> StartPlexAuth
GET /plex/auth/status?pinId={id} -> GetPlexAuthStatus
POST /plex/auth/refresh -> RefreshPlexLibraries
POST /plex/auth/unlink -> UnlinkPlex
StartPlexAuthinitiates the PIN-based OAuth flow by requesting a unique pairing code and authorization URL from Plex.tv.GetPlexAuthStatuspolls for PIN completion; upon success, it saves the authentication token and triggers the initial discovery of servers and Shoko Relay libraries.RefreshPlexLibrariesuses the saved token to force re-discovery of all accessible Plex servers then updates server URIs and the list of Shoko Relay libraries.UnlinkPlexrevokes the token at Plex.tv and deletes theplex.tokenfile.
GET /plex/collections/build?seriesId={id}&filter={csv} -> BuildPlexCollections
GET /plex/collections/posters?seriesId={id}&filter={csv} -> ApplyCollectionPosters
GET /plex/ratings/apply?seriesId={id}&filter={csv} -> ApplyAudienceRatings
GET /plex/automation/run -> RunPlexAutomationNow
BuildPlexCollectionsgenerate Plex collections for the specified series or filter.ApplyCollectionPostersupload or refresh posters for the same series set.ApplyAudienceRatingsupdate series/episode ratings based on the configured source (TMDB/AniDB).RunPlexAutomationNowtriggers collection building and rating application back-to-back for all series.
Notes:
- Each of the above (other than
RunPlexAutomationNow) accepts eitherseriesIdor a comma separatedfilter.- The
seriesIddefaults to Shoko but can be an AniDB ID if prefixed with an 'a'.
- The
- All operations respect the
Advanced.Parallelismsetting to prevent IO saturation. - The scheduler is governed by
Automation.PlexAutomationFrequencyHours.
POST /plex/webhook -> PluginPlexWebhook
PluginPlexWebhookhandles Plexmedia.scrobbleandmedia.rateevents.
Notes:
- Strict Validation:
- Validates the
Server.uuidagainst known servers to prevent leaks from shared libraries. - Distinguishes between the actual Admin account and managed users.
- Managed users are only permitted to scrobble if listed in
Automation.ExtraPlexUsers.
- Validates the
- Success logs use the format:
user='Name', series='Title', episode='S01E01'. - Rating events update Shoko episode ratings via
IUserDataService.RateEpisodeifAutomation.ShokoSyncWatchedIncludeRatingsis enabled.
Endpoints are managed by ShokoController
GET /vfs?run={true|false}&clean={true|false}&filter={csv} -> BuildVfs
POST /vfs/overrides -> SaveVfsOverrides
BuildVfs(all query parameters are optional)run: (default false) set to true to execute the VFS construction.clean: (default true) clear the existing root before building.filter: (optional) comma separated Shoko or AniDB (prefixed with an 'a') series IDs.
SaveVfsOverridesaccepts raw text foranidb_vfs_overrides.csv.
Notes:
- When
Automation.ScanOnVfsRefreshis enabled, the controller schedules library scans for affected series automatically. - When importing local metadata images, files named
Specials.<ext>are renamed toSeason-Specials-Poster.<ext>in the VFS. - Any folder name listed in the
Folder Exclusionssetting (plus system folders like !AnimeThemes) is ignored during VFS generation. - Overrides allow grouping multiple AniDB IDs under a single primary Shoko Series ID for Plex.
VfsWatcherautomatically triggers batch VFS builds when file events are detected.
GET /shoko/remove-missing?dryRun={true|false} -> RemoveMissingFiles (for preview/testing)
POST /shoko/remove-missing?dryRun={true|false} -> RemoveMissingFiles
POST /shoko/import -> RunShokoImport
GET /shoko/import/start -> StartShokoImportNow
GET /sync-watched -> SyncPlexWatched (for preview/testing)
POST /sync-watched -> SyncPlexWatched
[?dryRun={true|false}&sinceHours={int}&ratings={true|false}&import={true|false}&excludeAdmin={true|false}]
GET /sync-watched/start -> StartWatchedSyncNow
RemoveMissingFilesremoves missing files from Shoko and the AniDB MyList (physical files are never touched).dryRun: (default true) set to false to actually remove records from Shoko and AniDB MyList.
RunShokoImporttriggers a scan of managed folders marked as "Source".SyncPlexWatchedsynchronizes watched state between Plex and Shoko (Bi-directional).dryRun: (default true) set to false to write watched states/ratings to databases.sinceHours: (optional) limit processing to items viewed within this window.ratings: (default to configuration) set to true/false to override theAutomation.ShokoSyncWatchedIncludeRatingssetting.import: (default false) set to true forPlex←Shoko. Default isPlex→Shoko.excludeAdmin: (default to configuration) set to true/false to override theAutomation.ShokoSyncWatchedExcludeAdminsetting.- Direction and exclusion settings are read from
AutomationConfig.
Notes:
- Scheduled automations are anchored to UTC midnight using
Automation.UtcOffsetHours. - Managed user tokens are obtained transiently via Plex Home switching and are never persisted.
POST /map-symlinks?mapFile={path}&purgeLinks={true|false} -> ProcessSourceLinks
ProcessSourceLinksmanages relative symlinks from protected source folders to the library based on a text-based mapping file, or purges existing links.mapFile: (required if not purging) path to the.txtfile relative to the Import Root (e.g.,!Source/symlinks.txt).purgeLinks: (default false) set to true to recursively remove all symlinks and_attachfolders in the import roots.
Notes:
- If
purgeLinksistrue:- It explicitly excludes the configured VFS / AnimeThemes / Posters root folders and never deletes physical media files.
- If
purgeLinksisfalse(default):- The
mapFileparameter is the path to the.txtfile relative to the Import Root (e.g.,!Source/symlinks.txt). - Source paths are resolved relative to the directory containing the mapping file.
- Destination paths are resolved relative to the Import Root.
- Sidecar files (any file starting with
{baseName}) and attachment folders (directories named{baseName}_attachments) are automatically identified and renamed to match the destination.- The
_attachmentsfolders are renamed to_attachat the destination to allow thepurgeLinksoperation to delete them without touching the originals.
- The
- The
Mapping File Format:
The mapping file uses a pipe-delimited (|) and semicolon-delimited (;) structure. While designed for multiple scripts, this plugin specifically extracts the source path, destination path, and tags.
"original_path";comment;tag1,tag2|"symlink_path";comment;ext|title|subgroup|"audio_path";comment;lang;name
Plugin Logic:
- Segment 1 (Source):
Path: Extracted from the first double-quoted string.Tags: Extracted from the 3rd semicolon-separated group. Tags are split by commas and appended to the destination filename in brackets (e.g.,[tag1] [tag2]).
- Segment 2 (Destination):
Path: Extracted from the second double-quoted string. Used as the base for the symlink and sidecar renaming.
- Segments 3+ (Optional):
- Used by external scripts for title, subgroup, or external audio track info; ignored by this plugin.
Notes:
- Sidecar Renaming: Sidecars are renamed by replacing the source base name with the tagged destination base name.
- Attachment Handling:
- Source Convention: The original attachment folders must end in
_attachments(e.g.,Anime_attachments). - Destination Result: The plugin creates a physical folder at the destination ending in
_attach(e.g.,Anime_attach). - Internal contents (fonts) are linked as individual relative file symlinks.
- This distinction ensures the
purgeLinkscommand can safely remove generated links without touching original source files.
- Source Convention: The original attachment folders must end in
- Relative Pathing: Links are created with relative targets. They remain valid as long as the relative depth between the source and destination remains consistent.
- Bookkeeping: Lines that are successfully processed are automatically prefixed with
#to prevent redundant processing in future runs.
Endpoints managed by AnimeThemesController
GET /animethemes/vfs/build?filter={csv} -> AnimeThemesVfsBuild
GET /animethemes/vfs/map?testPath={filename} -> AnimeThemesVfsMap
POST /animethemes/vfs/import -> ImportAnimeThemesMapping
AnimeThemesVfsBuildapplies the mapping and generateswebm_animethemes.cache.filter: (optional) comma separated Shoko or AniDB (prefixed with an 'a') series IDs.- Cache Format:
VfsPath|VideoId|Bitmask. - Bitmask flags:
1:NC, 2:Lyrics, 4:Subs, 8:Uncen, 16:NSFW, 32:Spoil, 64:Trans, 128:Over.
AnimeThemesVfsMapgenerates the mapping CSV or tests a single filename mapping.testPath: (optional) provide a filename to preview its mapping result and generated name.- The filename generation respects the
Advanced.AnimeThemesAppendTagssetting.
GET /animethemes/webm/tree -> AnimeThemesWebmTree
GET /animethemes/webm/stream?path={path} -> AnimeThemesWebmStream
HEAD /animethemes/webm/stream?path={path} -> AnimeThemesWebmStream
GET /animethemes/webm/favourites -> GetAnimeThemesFavourites
POST /animethemes/webm/favourites -> UpdateAnimeThemesFavourite
AnimeThemesWebmTreereturns the hierarchical tree including bitmask flags andvideoId.AnimeThemesWebmStreamsupports HTTP range requests for seekable browser playback.GetAnimeThemesFavouritesreturns a list ofvideoIdfavourites fromfavs_animethemes.cache.UpdateAnimeThemesFavouritetoggles avideoIdin the favourites list using a raw integer body.
GET /animethemes/mp3 -> AnimeThemesMp3
[?path={path}&slug={slug}&offset={int}&batch={true|false}&force={true|false}&season={season}]
GET /animethemes/mp3/stream?path={path} -> AnimeThemesMp3Stream
HEAD /animethemes/mp3/stream?path={path} -> AnimeThemesMp3Stream
GET /animethemes/mp3/random?refresh={true|false} -> AnimeThemesMp3Random
AnimeThemesMp3generates or batches Theme.mp3 files using parallelism.path: (required) relative or absolute Shoko/Plex path.slug: (optional) specific theme identifier (e.g., OP1).offset: (default 0) selection index when multiple themes match.batch: (default false) set to true to recursively process subfolders.force: (default false) set to true to overwrite existingTheme.mp3files.season: (optional) filter by anime season using the format "Season Year" (e.g.,Spring 2025). This only works ifbatch=true.- Seasons:
Winter,Spring,Summer,Fall. - Validates against the series air date with a one-month early buffer.
- Seasons:
AnimeThemesMp3Streamembeds ID3v2 tags in response headers.- Headers:
X-Theme-Title,X-Theme-Slug,X-Theme-Artist,X-Theme-Album.
- Headers:
AnimeThemesMp3Randomuses a startup cache persisted inmp3_animethemes.cache.refresh: (default false) set to true to force a re-scan of managed roots for existing themes.
Notes:
- All paths may be Plex or Shoko relative; the controller translates them via
Advanced.PathMappings. - Mapping de-duplication logic:
- BD Prioritization: If metadata for multiple video files results in the same filename, BD (Blu-ray) sources are prioritized.
- If a BD source is available, all non-BD sources (TV, Web, etc.) for that specific filename are skipped.
- Numbering: If multiple sources of the same priority (e.g., multiple BDs or multiple TV rips) result in the same filename, they are de-duplicated by appending
(2),(3), etc. - Overrides: Themes originating from secondary series in an override group receive a prefix (e.g.,
P2 ❯,P3 ❯) to distinguish them from the primary series themes.
- BD Prioritization: If metadata for multiple video files results in the same filename, BD (Blu-ray) sources are prioritized.