Compare commits

..
18 Commits
Author SHA1 Message Date
Quentin Robert 3eb64b175d Merge pull request #137 from Masutayunikon/release-please--branches--main
chore(main): release 3.21.0
2026-06-28 12:25:54 +02:00
Quentin Robert 25a8adc91d chore(main): release 3.21.0 2026-06-28 12:11:12 +02:00
MasutaYunikon d533751ffb Merge remote-tracking branch 'origin/main' 2026-06-28 12:10:45 +02:00
MasutaYunikon 6f1e0dc844 feat(settings): ajout de englishDirectory qui permet d'avoir Season XX au lieu de Saison X 2026-06-28 12:10:34 +02:00
github-actions[bot] 894a7ed2b1 chore: update version.txt to v3.20.3 2026-06-26 13:25:13 +00:00
Quentin Robert c87b7a4c7f Merge pull request #136 from Masutayunikon/release-please--branches--main
chore(main): release 3.20.3
2026-06-26 15:24:47 +02:00
Quentin Robert a000e349c9 chore(main): release 3.20.3 2026-06-26 15:24:30 +02:00
MasutaYunikon f23e3c04ec Merge remote-tracking branch 'origin/main' 2026-06-26 15:23:45 +02:00
MasutaYunikon 63146fdc27 fix(serie): ajout du label de saisons avec les episodes 2026-06-26 15:21:55 +02:00
github-actions[bot] 7795598346 chore: update version.txt to v3.20.2 2026-06-26 12:52:07 +00:00
Quentin Robert 04252db0c4 Merge pull request #135 from Masutayunikon/release-please--branches--main
chore(main): release 3.20.2
2026-06-26 14:51:44 +02:00
Quentin Robert aeb2e938ef chore(main): release 3.20.2 2026-06-26 14:50:31 +02:00
MasutaYunikon 3799d33c62 fix(scraper): fallback on empty env for GITHUB_BASE
fix(client): add placeholder from config
fix(client): remove alldebrid
2026-06-26 14:49:53 +02:00
MasutaYunikon 98b317d493 fix(label): add season of episodes 2026-06-26 14:25:41 +02:00
Quentin Robert 4292f96645 Merge pull request #131 from Nackophilz/main
Replace favicon and add PNG logo
2026-06-09 21:44:35 +02:00
ElPouki 182c7cc807 add png logo 2026-06-09 21:42:14 +02:00
ElPouki 53be057425 replace favicon 2026-06-09 21:41:51 +02:00
github-actions[bot] ac70dba927 chore: update version.txt to v3.20.1 2026-06-08 00:23:47 +00:00
11 changed files with 77 additions and 30 deletions

No files matched your search

+24
View File
@@ -1,5 +1,29 @@
# Changelog
## [3.21.0](https://github.com/Masutayunikon/FanKarr/compare/v3.20.3...v3.21.0) (2026-06-28)
### Features
* **settings:** ajout de englishDirectory qui permet d'avoir Season XX au lieu de Saison X ([6f1e0dc](https://github.com/Masutayunikon/FanKarr/commit/6f1e0dc844e8f97b0966b223d558c09ab498ddc9))
## [3.20.3](https://github.com/Masutayunikon/FanKarr/compare/v3.20.2...v3.20.3) (2026-06-26)
### Bug Fixes
* **serie:** ajout du label de saisons avec les episodes ([63146fd](https://github.com/Masutayunikon/FanKarr/commit/63146fdc27d98acb70cf86c7890ea1236388d717))
## [3.20.2](https://github.com/Masutayunikon/FanKarr/compare/v3.20.1...v3.20.2) (2026-06-26)
### Bug Fixes
* **client:** add placeholder from config ([3799d33](https://github.com/Masutayunikon/FanKarr/commit/3799d33c625fe28eab4b46917ff32b1266cda1e3))
* **client:** remove alldebrid ([3799d33](https://github.com/Masutayunikon/FanKarr/commit/3799d33c625fe28eab4b46917ff32b1266cda1e3))
* **label:** add season of episodes ([98b317d](https://github.com/Masutayunikon/FanKarr/commit/98b317d493b7742c330d49ca816c0fecd983e82a))
* **scraper:** fallback on empty env for GITHUB_BASE ([3799d33](https://github.com/Masutayunikon/FanKarr/commit/3799d33c625fe28eab4b46917ff32b1266cda1e3))
## [3.20.1](https://github.com/Masutayunikon/FanKarr/compare/v3.20.0...v3.20.1) (2026-06-08)
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 231 KiB

+3 -2
View File
@@ -2,8 +2,9 @@ import { DATA_DIR } from '../config.js'
import path from 'path'
import fs from 'fs'
const GITHUB_BASE = process.env.GITHUB_BASE
?? 'https://raw.githubusercontent.com/masutayunikon/fankarr-scraper/main'
const GITHUB_BASE =
process.env.GITHUB_BASE?.trim() ||
'https://raw.githubusercontent.com/masutayunikon/fankarr-scraper/main'
const CACHE_TTL_MS = 1 * 60 * 60 * 1000
+5 -4
View File
@@ -35,12 +35,12 @@ export interface OrgEntry {
type Organized = Record<string, Record<string, OrgEntry>>
// ─── Settings ─────────────────────────────────────────────────
function readSettings(): { mediaPath: string; completePath: string; organizeMode: string; nfoSupport: boolean } {
function readSettings(): { mediaPath: string; completePath: string; organizeMode: string; nfoSupport: boolean, englishDirectory: boolean } {
try {
const p = path.join(DATA_DIR, 'settings.json')
if (!fs.existsSync(p)) return { mediaPath: '', completePath: '', organizeMode: 'hardlink', nfoSupport: false }
if (!fs.existsSync(p)) return { mediaPath: '', completePath: '', organizeMode: 'hardlink', nfoSupport: false, englishDirectory: false }
return JSON.parse(fs.readFileSync(p, 'utf-8'))
} catch { return { mediaPath: '', completePath: '', organizeMode: 'hardlink', nfoSupport: false } }
} catch { return { mediaPath: '', completePath: '', organizeMode: 'hardlink', nfoSupport: false , englishDirectory: false } }
}
// ─── Organized log ────────────────────────────────────────────
@@ -302,7 +302,8 @@ function swapExtension(filename: string, ext: string): string {
}
function seasonFolder(n: number): string {
return n === 0 ? 'Specials' : `Saison ${n}`
const { englishDirectory } = readSettings()
return n === 0 ? 'Specials' : (englishDirectory ? `Season ${String(n).padStart(2, '0')}` : `Saison ${n}`)
}
/**
+2 -1
View File
@@ -10,7 +10,7 @@ router.get('/settings', requireAuth, (_req, res) => {
})
router.post('/settings', requireAuth, (req, res) => {
const { mediaPath, completePath, organizeMode, category, nfoSupport, autoImport, devMode, deleteTorrentOnMove, autoUnimportMissing, requestAutoDownloadUsers } = req.body
const { mediaPath, completePath, organizeMode, category, nfoSupport, autoImport, devMode, deleteTorrentOnMove, autoUnimportMissing, requestAutoDownloadUsers, englishDirectory } = req.body
const patch: Record<string, any> = {}
if (mediaPath !== undefined) patch.mediaPath = mediaPath
if (completePath !== undefined) patch.completePath = completePath
@@ -22,6 +22,7 @@ router.post('/settings', requireAuth, (req, res) => {
if (deleteTorrentOnMove !== undefined) patch.deleteTorrentOnMove = deleteTorrentOnMove
if (autoUnimportMissing !== undefined) patch.autoUnimportMissing = autoUnimportMissing
if (requestAutoDownloadUsers !== undefined) patch.requestAutoDownloadUsers = requestAutoDownloadUsers
if (englishDirectory !== undefined) patch.englishDirectory = englishDirectory
const updated = writeSettings(patch)
logger.info('api', 'Paramètres mis à jour')
res.json(updated)
+2
View File
@@ -16,6 +16,7 @@ export interface Settings {
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
englishDirectory : boolean // Si true, les dossiers de séries sont en anglais (ex: "Season 1" au lieu de "Saison 1")
}
const defaults: Settings = {
@@ -30,6 +31,7 @@ const defaults: Settings = {
requestAutoDownloadUsers: [],
jellyfinUrl : '',
jellyfinAdminToken : '',
englishDirectory : false,
}
export function readSettings(): Settings {
+32 -16
View File
@@ -606,33 +606,49 @@ const _epChapCache = new Map<string | null | undefined, ReturnType<typeof _parse
*/
function _parseEpChap(plot: string | null | undefined): {
episodes: string | null
chapters: string | null
season: number | null
chapters: string |null
cleanPlot: string
} {
const text = plot ?? ''
const epMatch = text.match(/[éeÉE]pisodes?\s+(\d+)(?:\s+[àa]\s+(\d+))?/i)
const chapMatch = text.match(/chapitres?\s+(\d+)(?:\s+[àa]\s+(\d+))?/i)
const epMatch = text.match(
/[éeÉE]pisodes?\s+(\d+)(?:\s+[àa]\s+(\d+))?(?:\s+de\s+la\s+saison\s+(\d+))?/i
)
const seasonMatch = text.match(/saison\s+(\d+)/i)
const season = epMatch?.[3] ?? seasonMatch?.[1] ?? null
const chapMatch = text.match(
/chapitres?\s+(\d+)(?:\s+[àa]\s+(\d+))?/i
)
const episodes = epMatch
? (epMatch[2] ? `Ép. ${epMatch[1]}–${epMatch[2]}` : `Ép. ${epMatch[1]}`)
: null
const chapters = chapMatch
? (chapMatch[2] ? `Ch. ${chapMatch[1]}–${chapMatch[2]}` : `Ch. ${chapMatch[1]}`)
: null
? `${season ? `S${season} · ` : ''}${
epMatch[2]
? `Ép. ${epMatch[1]}–${epMatch[2]}`
: `Ép. ${epMatch[1]}`
}`
: null
const chapters = chapMatch
? (chapMatch[2] ? `Ch. ${chapMatch[1]}–${chapMatch[2]}` : `Ch. ${chapMatch[1]}`)
: null
// Retirer les lignes contenant les références d'épisodes ou chapitres
let cleanPlot = text
if (episodes || chapters) {
if (episodes || chapters || season) {
cleanPlot = text
.split(/\r?\n/)
.filter(line => !/[éeÉE]pisodes?\s+\d+|chapitres?\s+\d+/i.test(line))
.join('\n')
.replace(/\n{3,}/g, '\n\n')
.trim()
.split(/\r?\n/)
.filter(line => !/(?:[éeÉE]pisodes?\s+\d+|chapitres?\s+\d+|saison\s+\d+)/i.test(line))
.join('\n')
.replace(/\n{3,}/g, '\n\n')
.trim()
}
return { episodes, chapters, cleanPlot }
return { episodes, season, chapters, cleanPlot }
}
function parseEpChap(plot: string | null | undefined) {
if (_epChapCache.has(plot)) return _epChapCache.get(plot)!
+2 -6
View File
@@ -182,7 +182,7 @@
<input
v-model="modal.config[field.key]"
:type="field.type === 'password' ? 'password' : 'text'"
placeholder=""
:placeholder="field.placeholder ?? ''"
class="settings-input"
/>
</div>
@@ -254,11 +254,7 @@ const clientMatrix = [
{
id: 'real-debrid', label: 'Real-Debrid', version: 'API v1',
auth: 'Clé API', fileSelect: true, fileProgress: true, torrentUpload: 'proxy', categories: false, deleteFiles: true,
},
{
id: 'alldebrid', label: 'AllDebrid', version: 'API v4',
auth: 'Clé API', fileSelect: false, fileProgress: true, torrentUpload: 'proxy', categories: false, deleteFiles: true,
},
}
]
const modal = ref({
@@ -103,6 +103,11 @@
label="Désimporter si fichier manquant"
description="Si un fichier importé n'est plus trouvé sur le disque lors du scan, il est automatiquement retiré de la bibliothèque."
/>
<SettingsToggle
v-model="form.englishDirectory"
label="Utilise 'Season' au lieu de 'Saison' dans les dossiers"
description="Si activé, les dossiers de saisons seront nommés 'Season 01' au lieu de 'Saison 01'."
/>
</div>
<!-- Plex -->
@@ -215,6 +220,7 @@ const form = ref({
autoImport : true,
deleteTorrentOnMove : false,
autoUnimportMissing : false,
englishDirectory : false,
})
const picker = ref<{ open: boolean; field: 'completePath' | 'mediaPath'; currentPath: string }>({
+1 -1
View File
@@ -1 +1 @@
3.20.1
3.21.0