Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53c226eba8 | ||
|
|
3b74d93b74 | ||
|
|
ff54ab4ef6 | ||
|
|
a7c90b63df | ||
|
|
872962c435 | ||
|
|
b9c4627a77 | ||
|
|
eff7a288cf | ||
|
|
94d419cf01 | ||
|
|
4760d576f3 | ||
|
|
800c9f3f02 | ||
|
|
6c7def3184 | ||
|
|
962279db29 | ||
|
|
bffe286f40 | ||
|
|
abc96dd648 |
No files matched your search
@@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## [3.11.5](https://github.com/Masutayunikon/FanKarr/compare/v3.11.4...v3.11.5) (2026-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* le folder picker affiche tous les disques depuis le bouton homes sous windows ([7149022](https://github.com/Masutayunikon/FanKarr/commit/7149022c8701f79d194c675da87c6cb2d5793a35))
|
||||
|
||||
## [3.11.4](https://github.com/Masutayunikon/FanKarr/compare/v3.11.3...v3.11.4) (2026-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ajout de la mise a jour des noms toutes les 1h ([0fe5c8c](https://github.com/Masutayunikon/FanKarr/commit/0fe5c8ccb7ecdc1643b5e69de3957c39dfd8085e))
|
||||
|
||||
## [3.11.3](https://github.com/Masutayunikon/FanKarr/compare/v3.11.2...v3.11.3) (2026-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* dockerfile node version to 22 ([5983494](https://github.com/Masutayunikon/FanKarr/commit/598349407750c729579bd639680ebc6a8ebcc12f))
|
||||
|
||||
## [3.11.2](https://github.com/Masutayunikon/FanKarr/compare/v3.11.1...v3.11.2) (2026-04-26)
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
FROM node:20-slim AS base
|
||||
FROM node:22-slim AS base
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
@@ -15,7 +15,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
RUN pnpm run build
|
||||
|
||||
# ── Production ─────────────────────────────────────────────────
|
||||
FROM node:20-slim
|
||||
FROM node:22-slim
|
||||
RUN apt-get update && apt-get install -y gosu && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
@@ -28,4 +28,4 @@ RUN mkdir -p /config
|
||||
|
||||
EXPOSE 3001
|
||||
ENV NODE_ENV=production
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
+14
-1
@@ -11,7 +11,7 @@ import transmissionDriver from './torrent-clients/transmission.js'
|
||||
import synologyDsDriver from './torrent-clients/synology-ds.js'
|
||||
import utorrentDriver from './torrent-clients/utorrent.js'
|
||||
import rtorrentDriver from './torrent-clients/rtorrent.js'
|
||||
import { autoOrganizeAll, scanMediaPath } from './organize.js'
|
||||
import { autoOrganizeAll, scanMediaPath, syncFilenameChanges } from './organize.js'
|
||||
import { logger } from './logger.js'
|
||||
import { DATA_DIR, BASE_DIR } from './config.js'
|
||||
import { readAvailable, readInfohashMap, loadEnrichedSeriesData } from './lib/github-cache.js'
|
||||
@@ -139,4 +139,17 @@ server.listen(PORT, async () => {
|
||||
checkNfoUpdates().catch(err => logger.error('nfo-update', `Vérif horaire échouée : ${err instanceof Error ? err.message : err}`))
|
||||
}, 60 * 60_000)
|
||||
}, 30_000)
|
||||
|
||||
// Sync automatique des noms de fichiers toutes les heures.
|
||||
// Le TTL du cache GitHub est de 1h — ce setInterval tire toujours sur des données fraîches.
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const seriesData = await loadEnrichedSeriesData()
|
||||
const { renamed } = await syncFilenameChanges(seriesData, path.join(DATA_DIR, 'organized.json'))
|
||||
if (renamed > 0)
|
||||
logger.info('api', `Sync noms auto — ${renamed} fichier(s) renommé(s)`)
|
||||
} catch (err) {
|
||||
logger.error('api', `Sync noms auto échoué : ${err instanceof Error ? err.message : err}`)
|
||||
}
|
||||
}, 60 * 60_000)
|
||||
})
|
||||
+27
-2
@@ -47,11 +47,36 @@ router.get('/version', (_req, res) => {
|
||||
|
||||
// ── Parcours fichiers ──────────────────────────────────────────
|
||||
router.get('/browse', requireAuth, (req, res) => {
|
||||
const dirPath = (req.query.path as string) || '/'
|
||||
const isWindows = process.platform === 'win32'
|
||||
const dirPath = (req.query.path as string) || '/'
|
||||
|
||||
// ── Racine virtuelle Windows : liste les lecteurs disponibles ──
|
||||
if (isWindows && dirPath === '/') {
|
||||
const drives: string[] = []
|
||||
for (const letter of 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') {
|
||||
const d = `${letter}:\\`
|
||||
try { fs.readdirSync(d); drives.push(d) } catch {}
|
||||
}
|
||||
res.json({ path: '/', parent: null, dirs: drives, drivesRoot: true })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const entries = fs.readdirSync(dirPath, { withFileTypes: true })
|
||||
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).filter(n => !n.startsWith('.')).sort((a, b) => a.localeCompare(b))
|
||||
res.json({ path: dirPath, parent: dirPath === '/' ? null : path.dirname(dirPath), dirs })
|
||||
|
||||
// Sur Windows, remonter à '/' quand on est à la racine d'un lecteur (ex: C:\)
|
||||
let parent: string | null
|
||||
if (dirPath === '/') {
|
||||
parent = null
|
||||
} else if (isWindows && /^[A-Za-z]:\\?$/.test(dirPath)) {
|
||||
parent = '/'
|
||||
} else {
|
||||
const up = path.dirname(dirPath)
|
||||
parent = up === dirPath ? null : up // dirname de C:\ retourne C:\ → null
|
||||
}
|
||||
|
||||
res.json({ path: dirPath, parent, dirs })
|
||||
} catch (err) {
|
||||
logger.warn('api', `Lecture dossier "${dirPath}" impossible : ${err instanceof Error ? err.message : err}`)
|
||||
res.status(400).json({ error: err instanceof Error ? err.message : 'Erreur lecture dossier' })
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<!-- Chemin éditable -->
|
||||
<div class="px-5 py-3 border-b border-border shrink-0 flex gap-2">
|
||||
<button @click="navigateTo('/')" class="btn-secondary px-2 text-muted hover:text-primary" title="Retour à la racine">
|
||||
<button @click="navigateTo('/')" class="btn-secondary px-2 text-muted hover:text-primary" :title="drivesRoot ? 'Lecteurs' : 'Retour à la racine'">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" fill="none">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||
@@ -85,12 +85,13 @@ import { ref, watch } from 'vue'
|
||||
const props = defineProps<{ initialPath?: string }>()
|
||||
const emit = defineEmits<{ select: [path: string]; cancel: [] }>()
|
||||
|
||||
const current = ref(props.initialPath || '/')
|
||||
const inputPath = ref(current.value)
|
||||
const dirs = ref<string[]>([])
|
||||
const parent = ref<string | null>(null)
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
const current = ref(props.initialPath || '/')
|
||||
const inputPath = ref(current.value)
|
||||
const dirs = ref<string[]>([])
|
||||
const parent = ref<string | null>(null)
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
const drivesRoot = ref(false) // true quand la liste affiche les lecteurs Windows
|
||||
|
||||
// FIX : la regex /\/+$/ dans un @click inline fait planter le parser Vue
|
||||
function selectCurrent() {
|
||||
@@ -98,8 +99,10 @@ function selectCurrent() {
|
||||
}
|
||||
|
||||
function joinPath(base: string, name: string): string {
|
||||
// Lecteur Windows complet (ex: "C:\") → chemin absolu, pas de jointure
|
||||
if (/^[A-Za-z]:\\$/.test(name)) return name
|
||||
if (base === '/') return `/${name}`
|
||||
const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base
|
||||
const cleanBase = base.replace(/[\\/]+$/, '')
|
||||
return `${cleanBase}/${name}`
|
||||
}
|
||||
|
||||
@@ -114,10 +117,11 @@ async function navigateTo(p: string) {
|
||||
return
|
||||
}
|
||||
const data = await res.json()
|
||||
current.value = data.path
|
||||
inputPath.value = data.path
|
||||
parent.value = data.parent
|
||||
dirs.value = data.dirs
|
||||
current.value = data.path
|
||||
inputPath.value = data.path
|
||||
parent.value = data.parent
|
||||
dirs.value = data.dirs
|
||||
drivesRoot.value = data.drivesRoot ?? false
|
||||
} catch {
|
||||
error.value = 'Impossible de lire ce dossier'
|
||||
} finally {
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3.11.2
|
||||
3.11.5
|
||||
Reference in new issue
Block a user