docs(swagger): add JSDoc @openapi for status and history endpoints

- GET /api/status/status: admin-only, server/cache/polling/webhook metrics
- GET /api/history/recent: filtered by user tag, deduplication logic
- Document deduplication rules (imported suppresses failed)
- Document availableForUpgrade flag
- Include query parameters (days, showAll)
This commit is contained in:
2026-05-21 12:36:07 +01:00
parent 12effe17d3
commit a21bafa041
2 changed files with 224 additions and 30 deletions
+127 -29
View File
@@ -195,38 +195,136 @@ function getRadarrLink(movie) {
}
/**
* GET /api/history/recent
* @openapi
* /api/history/recent:
* get:
* tags: [History]
* summary: Get recent history
* description: |
* Returns Sonarr/Radarr history records (imported + failed) for the authenticated user,
* filtered to the last N days (default 7, max 90).
*
* Returns Sonarr/Radarr history records (imported + failed) for the
* authenticated user, filtered to the last RECENT_COMPLETED_DAYS days
* (default 7, overridable via env or ?days= query param).
* **Authentication:** Requires valid `emby_user` cookie.
*
* Response shape:
* {
* user: string,
* isAdmin: boolean,
* days: number,
* history: HistoryItem[]
* }
* **Filtering:**
* - Non-admin users: Only see history items tagged with their username
* - Admin users: Can see all history by setting query parameter `showAll=true`
* - Date range: Configurable via `?days=` query parameter (default: 7, max: 90)
*
* HistoryItem shape:
* {
* type: 'series'|'movie',
* outcome: 'imported'|'failed',
* title: string, // sourceTitle from arr record
* seriesName?: string, // series.title (Sonarr)
* movieName?: string, // movie.title (Radarr)
* coverArt: string|null,
* completedAt: string, // ISO date string from arr record
* quality: string|null,
* instanceName: string, // arr instance name
* arrLink: string|null, // link to item in Sonarr/Radarr UI
* allTags: string[],
* matchedUserTag: string|null,
* // admin-only:
* arrRecordId?: number,
* failureMessage?: string,
* }
* **Deduplication Rules:**
* For each unique content item (episode or movie), only the most recent record is shown:
* - If the most recent event is "imported" → show it; suppress older failures
* - If the most recent event is "failed" and the item has a file on disk → show with `availableForUpgrade=true`
* - If the most recent event is "failed" and no file exists → show normally
*
* **Event Classification:**
* - Sonarr: DownloadFolderImported, ImportFailed → included
* - Radarr: DownloadFolderImported, ImportFailed → included
* - Other event types (Rename, Health, etc.) → excluded
*
* **Response Structure:**
* - `type`: "series" or "movie"
* - `outcome`: "imported" or "failed"
* - `title`: Source title from *arr record
* - `seriesName`/`movieName`: Friendly media title
* - `coverArt`: Poster URL
* - `completedAt`: ISO 8601 timestamp
* - `quality`: Quality string (e.g., "HDTV-1080p")
* - `instanceName`: *arr instance name
* - `arrLink`: Link to item in *arr UI
* - `allTags`: All tags on the series/movie
* - `matchedUserTag`: Tag matching the requesting user
* - `availableForUpgrade`: True if failed but content is on disk (admin-only)
* - `failureMessage`: Failure details (admin-only)
*
* **x-integration-notes:** Used by the history tab to show recently completed downloads.
* Episodes are gathered from all history records sharing the same source title.
* security:
* - CookieAuth: []
* parameters:
* - name: days
* in: query
* schema:
* type: integer
* minimum: 1
* maximum: 90
* default: 7
* description: Number of days to look back (max 90)
* example: 7
* - name: showAll
* in: query
* schema:
* type: boolean
* default: false
* description: Admin-only: show all users' history
* responses:
* '200':
* description: History items
* content:
* application/json:
* schema:
* type: object
* properties:
* user:
* type: string
* example: "john"
* isAdmin:
* type: boolean
* example: false
* days:
* type: integer
* example: 7
* history:
* type: array
* items:
* $ref: '#/components/schemas/HistoryItem'
* example:
* user: "john"
* isAdmin: false
* days: 7
* history:
* - type: "series"
* outcome: "imported"
* title: "Show.Name.S01E01.1080p.WEB-DL"
* seriesName: "Show Name"
* episodes:
* - season: 1
* episode: 1
* title: "Pilot"
* coverArt: "http://sonarr:8989/media/poster.jpg"
* completedAt: "2026-05-21T10:00:00.000Z"
* quality: "HDTV-1080p"
* instanceName: "Main Sonarr"
* arrLink: "http://sonarr:8989/series/show-slug"
* allTags: ["user-john"]
* matchedUserTag: "user-john"
* '401':
* description: Not authenticated
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* '500':
* description: Server error
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* x-code-samples:
* - lang: curl
* label: cURL
* source: |
* curl -X GET "http://localhost:3001/api/history/recent?days=7" \
* -b cookies.txt
* - lang: JavaScript
* label: JavaScript (fetch)
* source: |
* const response = await fetch('http://localhost:3001/api/history/recent?days=7', {
* method: 'GET',
* credentials: 'include'
* });
* const data = await response.json();
* console.log('History items:', data.history.length);
*/
router.get('/recent', requireAuth, async (req, res) => {
try {