feat: ajout du parametre auto download

This commit is contained in:
MasutaYunikon committed 2026-05-22 22:34:17 +02:00
1 parent 0544a515b6
commit 0ac48126aa
4 files changed
+127 -17

No files matched your search

+12 -4
View File
@@ -8,6 +8,7 @@ import {
} from '../requests.js'
import { dispatchDownload } from '../torrent-clients/index.js'
import { readSerieData } from '../lib/github-cache.js'
import { readSettings } from '../settings.js'
import { logger } from '../logger.js'
const router = Router()
@@ -56,10 +57,17 @@ router.patch('/requests/:id', requireAdmin, async (req, res) => {
const id = String(req.params.id)
if (action === 'approve') {
request = approveRequest(id)
// Lancer le(s) téléchargement(s) correspondant à la demande
autoDownloadRequest(request).catch(err =>
logger.warn('requests', `Auto-dl échoué pour "${request.serieName}" : ${err instanceof Error ? err.message : err}`)
)
// Lancer le(s) téléchargement(s) si au moins un requester est autorisé
const { requestAutoDownloadUsers } = readSettings()
const enabled = requestAutoDownloadUsers === 'all'
? true
: Array.isArray(requestAutoDownloadUsers) && requestAutoDownloadUsers.length > 0
&& request.requesters.some(r => (requestAutoDownloadUsers as string[]).includes(r.userId))
if (enabled) {
autoDownloadRequest(request).catch(err =>
logger.warn('requests', `Auto-dl échoué pour "${request.serieName}" : ${err instanceof Error ? err.message : err}`)
)
}
} else if (action === 'reject') request = rejectRequest(id, rejectionMessage)
else if (action === 'complete') request = completeRequest(id)
else { res.status(400).json({ error: 'Action invalide (approve | reject | complete)' }); return }
+11 -10
View File
@@ -10,17 +10,18 @@ router.get('/settings', requireAuth, (_req, res) => {
})
router.post('/settings', requireAuth, (req, res) => {
const { mediaPath, completePath, organizeMode, category, nfoSupport, autoImport, devMode, deleteTorrentOnMove, autoUnimportMissing } = req.body
const { mediaPath, completePath, organizeMode, category, nfoSupport, autoImport, devMode, deleteTorrentOnMove, autoUnimportMissing, requestAutoDownloadUsers } = req.body
const patch: Record<string, any> = {}
if (mediaPath !== undefined) patch.mediaPath = mediaPath
if (completePath !== undefined) patch.completePath = completePath
if (organizeMode !== undefined) patch.organizeMode = organizeMode
if (category !== undefined) patch.category = category
if (nfoSupport !== undefined) patch.nfoSupport = nfoSupport
if (autoImport !== undefined) patch.autoImport = autoImport
if (devMode !== undefined) patch.devMode = devMode
if (deleteTorrentOnMove !== undefined) patch.deleteTorrentOnMove = deleteTorrentOnMove
if (autoUnimportMissing !== undefined) patch.autoUnimportMissing = autoUnimportMissing
if (mediaPath !== undefined) patch.mediaPath = mediaPath
if (completePath !== undefined) patch.completePath = completePath
if (organizeMode !== undefined) patch.organizeMode = organizeMode
if (category !== undefined) patch.category = category
if (nfoSupport !== undefined) patch.nfoSupport = nfoSupport
if (autoImport !== undefined) patch.autoImport = autoImport
if (devMode !== undefined) patch.devMode = devMode
if (deleteTorrentOnMove !== undefined) patch.deleteTorrentOnMove = deleteTorrentOnMove
if (autoUnimportMissing !== undefined) patch.autoUnimportMissing = autoUnimportMissing
if (requestAutoDownloadUsers !== undefined) patch.requestAutoDownloadUsers = requestAutoDownloadUsers
const updated = writeSettings(patch)
logger.info('api', 'Paramètres mis à jour')
res.json(updated)
+2 -2
View File
@@ -13,7 +13,7 @@ export interface Settings {
autoImport : boolean
devMode : boolean
deleteTorrentOnMove : boolean
requestAutoImport : boolean // demandes users : import auto ou validation admin
requestAutoDownloadUsers: 'all' | string[] // IDs users autorisés au dl auto sur approbation ; [] = désactivé
jellyfinUrl : string // URL du serveur Jellyfin (ex: http://jellyfin:8096)
jellyfinAdminToken : string // Token admin Jellyfin pour la sync
}
@@ -27,7 +27,7 @@ const defaults: Settings = {
autoImport : true,
devMode : false,
deleteTorrentOnMove: false,
requestAutoImport : false,
requestAutoDownloadUsers: [],
jellyfinUrl : '',
jellyfinAdminToken : '',
}
+102 -1
View File
@@ -94,6 +94,61 @@
</div>
</section>
<!-- ── Téléchargement automatique des demandes ──────────── -->
<section class="flex flex-col gap-4">
<div>
<h2 class="text-base font-semibold text-primary">Téléchargement automatique</h2>
<p class="text-sm text-muted mt-1">
Quand une demande est approuvée, lancer automatiquement le téléchargement pour les utilisateurs sélectionnés.
</p>
</div>
<div class="settings-card flex flex-col gap-4">
<!-- Tous les utilisateurs -->
<label class="flex items-center gap-3 cursor-pointer">
<input
type="checkbox"
:checked="autoDownloadAll"
@change="toggleAutoDownloadAll"
class="w-4 h-4 rounded border-border accent-accent"
/>
<div>
<p class="text-sm text-primary font-medium">Tous les utilisateurs</p>
<p class="text-xs text-muted">Chaque approbation déclenche un téléchargement, quel que soit le demandeur.</p>
</div>
</label>
<!-- Séparateur -->
<div v-if="!autoDownloadAll && users.length > 0" class="border-t border-border/50" />
<!-- Par utilisateur -->
<template v-if="!autoDownloadAll">
<label
v-for="u in users" :key="u.id"
class="flex items-center gap-3 cursor-pointer"
>
<input
type="checkbox"
:checked="autoDownloadUserIds.includes(u.id)"
@change="toggleAutoDownloadUser(u.id)"
class="w-4 h-4 rounded border-border accent-accent"
/>
<div class="flex items-center gap-2">
<span
class="w-6 h-6 rounded-full flex items-center justify-center text-xs font-semibold shrink-0"
:class="u.role === 'admin' ? 'bg-accent/20 text-accent' : 'bg-border text-muted'"
>{{ u.username[0].toUpperCase() }}</span>
<span class="text-sm text-primary">{{ u.username }}</span>
<span class="text-xs text-muted">{{ u.role === 'admin' ? 'Admin' : 'Utilisateur' }}</span>
</div>
</label>
<p v-if="users.length === 0" class="text-xs text-muted">Aucun utilisateur.</p>
</template>
<p v-if="autoDownloadSaved" class="text-xs text-green-400">Paramètre sauvegardé.</p>
</div>
</section>
<!-- ── Modal créer/modifier utilisateur ─────────────────── -->
<Teleport to="body">
<div v-if="userModal" class="fixed inset-0 bg-black/60 z-50 flex items-center justify-center px-4" @click.self="userModal = null">
@@ -203,6 +258,12 @@ const users = ref<User[]>([])
const invites = ref<Invite[]>([])
const copied = ref<string | null>(null)
// ── Téléchargement auto des demandes ──────────────────────────
const autoDownloadAll = ref(false)
const autoDownloadUserIds = ref<string[]>([])
const autoDownloadSaved = ref(false)
let autoDownloadTimer: ReturnType<typeof setTimeout> | null = null
// ── Modals ────────────────────────────────────────────────────
const userModal = ref<{
mode : 'create' | 'edit'
@@ -233,7 +294,47 @@ async function loadInvites() {
if (res.ok) invites.value = await res.json()
}
onMounted(() => { loadUsers(); loadInvites() })
async function loadAutoDownloadSetting() {
const res = await fetch('/api/settings', { credentials: 'include' })
if (!res.ok) return
const s = await res.json()
const val = s.requestAutoDownloadUsers ?? []
if (val === 'all') {
autoDownloadAll.value = true
autoDownloadUserIds.value = []
} else {
autoDownloadAll.value = false
autoDownloadUserIds.value = Array.isArray(val) ? val : []
}
}
async function saveAutoDownloadSetting() {
const value = autoDownloadAll.value ? 'all' : autoDownloadUserIds.value
await fetch('/api/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ requestAutoDownloadUsers: value }),
})
autoDownloadSaved.value = true
if (autoDownloadTimer) clearTimeout(autoDownloadTimer)
autoDownloadTimer = setTimeout(() => { autoDownloadSaved.value = false }, 2000)
}
function toggleAutoDownloadAll(e: Event) {
autoDownloadAll.value = (e.target as HTMLInputElement).checked
if (autoDownloadAll.value) autoDownloadUserIds.value = []
saveAutoDownloadSetting()
}
function toggleAutoDownloadUser(userId: string) {
const idx = autoDownloadUserIds.value.indexOf(userId)
if (idx >= 0) autoDownloadUserIds.value.splice(idx, 1)
else autoDownloadUserIds.value.push(userId)
saveAutoDownloadSetting()
}
onMounted(() => { loadUsers(); loadInvites(); loadAutoDownloadSetting() })
// ── Users ─────────────────────────────────────────────────────
function openCreateUser() {