94 lines
3.2 KiB
JavaScript
94 lines
3.2 KiB
JavaScript
const express = require('express');
|
|
const { APP_PORTS } = require('../../constants');
|
|
|
|
/**
|
|
* Plex routes factory
|
|
* @param {Object} deps - Explicit dependencies
|
|
* @param {Function} deps.fetchT - Timeout-wrapped fetch
|
|
* @param {Function} deps.asyncHandler - Async route handler wrapper
|
|
* @param {Function} deps.errorResponse - Error response helper
|
|
* @param {Object} deps.log - Logger instance
|
|
* @param {Object} deps.helpers - Arr helpers module
|
|
* @param {Object} deps.credentialManager - Credential manager
|
|
* @param {Object} deps.servicesStateManager - Services state manager
|
|
* @returns {express.Router}
|
|
*/
|
|
module.exports = function({ fetchT, asyncHandler, errorResponse, log: _log, helpers, credentialManager, servicesStateManager }) {
|
|
const router = express.Router();
|
|
|
|
const ctx = {
|
|
credentialManager,
|
|
servicesStateManager
|
|
};
|
|
|
|
// Plex Libraries endpoint
|
|
router.get('/plex/libraries', asyncHandler(async (req, res) => {
|
|
// Get Plex token
|
|
let plexToken = await helpers.getPlexToken('plex');
|
|
if (!plexToken) {
|
|
plexToken = await ctx.credentialManager.retrieve('arr.plex.token');
|
|
}
|
|
|
|
if (!plexToken) {
|
|
return errorResponse(res, 400, 'No Plex token available. Claim your Plex server first.', {
|
|
hint: 'Deploy Plex with a claim token or manually configure it.'
|
|
});
|
|
}
|
|
|
|
// Get Plex URL
|
|
let plexUrl = `http://localhost:${APP_PORTS.plex}`;
|
|
try {
|
|
const services = await ctx.servicesStateManager.read();
|
|
const svcList = Array.isArray(services) ? services : services.services || [];
|
|
const plexService = svcList.find(s => s.id === 'plex' || s.appTemplate === 'plex');
|
|
if (plexService?.url) {
|
|
plexUrl = plexService.url.replace('host.docker.internal', 'localhost');
|
|
}
|
|
} catch (e) { /* use default */ }
|
|
|
|
// Fetch libraries
|
|
const libRes = await fetchT(`${plexUrl}/library/sections`, {
|
|
headers: { 'X-Plex-Token': plexToken, 'Accept': 'application/json' },
|
|
signal: AbortSignal.timeout(10000)
|
|
});
|
|
|
|
if (!libRes.ok) {
|
|
return errorResponse(res, 502, `Plex returned ${libRes.status}`);
|
|
}
|
|
|
|
const data = await libRes.json();
|
|
const libraries = (data.MediaContainer?.Directory || []).map(dir => ({
|
|
key: dir.key,
|
|
title: dir.title,
|
|
type: dir.type,
|
|
count: parseInt(dir.count) || 0,
|
|
scannedAt: dir.scannedAt
|
|
}));
|
|
|
|
// Get server name
|
|
let serverName = 'Plex';
|
|
let version = null;
|
|
try {
|
|
const identityRes = await fetchT(`${plexUrl}/identity`, {
|
|
headers: { 'X-Plex-Token': plexToken, 'Accept': 'application/json' },
|
|
signal: AbortSignal.timeout(5000)
|
|
});
|
|
if (identityRes.ok) {
|
|
const identity = await identityRes.json();
|
|
serverName = identity.MediaContainer?.friendlyName || 'Plex';
|
|
version = identity.MediaContainer?.version;
|
|
}
|
|
} catch (e) { /* use default */ }
|
|
|
|
// Store token for future use
|
|
await ctx.credentialManager.store('arr.plex.token', plexToken, {
|
|
service: 'plex', source: 'local', url: plexUrl,
|
|
lastVerified: new Date().toISOString()
|
|
});
|
|
|
|
res.json({ success: true, serverName, version, libraries });
|
|
}, 'plex-libraries'));
|
|
|
|
return router;
|
|
};
|