Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c87b7a4c7f | ||
|
|
a000e349c9 | ||
|
|
f23e3c04ec | ||
|
|
63146fdc27 | ||
|
|
7795598346 | ||
|
|
04252db0c4 | ||
|
|
aeb2e938ef | ||
|
|
3799d33c62 | ||
|
|
98b317d493 | ||
|
|
4292f96645 | ||
|
|
182c7cc807 | ||
|
|
53be057425 | ||
|
|
ac70dba927 | ||
|
|
f79cc244ef | ||
|
|
14137e1b1b | ||
|
|
43ee4597a9 | ||
|
|
f311c8e2f3 | ||
|
|
48933b4078 |
No files matched your search
@@ -1,5 +1,29 @@
|
||||
# Changelog
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **organize:** import manuel ne traite que les fichiers 100% complets ([f311c8e](https://github.com/Masutayunikon/FanKarr/commit/f311c8e2f3b9f53b6d03a327cf1b5bfd69cc6424))
|
||||
|
||||
## [3.20.0](https://github.com/Masutayunikon/FanKarr/compare/v3.19.1...v3.20.0) (2026-05-29)
|
||||
|
||||
|
||||
|
||||
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 |
@@ -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
|
||||
|
||||
|
||||
+6
-2
@@ -520,13 +520,17 @@ export async function organizeTorrent(
|
||||
hash : string,
|
||||
name : string,
|
||||
savePath : string,
|
||||
seriesData: any[]
|
||||
seriesData: any[],
|
||||
files? : { name?: string; progress: number; priority?: number }[],
|
||||
): Promise<OrganizeResult> {
|
||||
logger.info('organize', `Import manuel lancé pour "${name}" (${hash})`)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new Worker(resolveWorkerPath())
|
||||
const fakeTorrent = { hash, name, save_path: savePath, state: 'seeding' }
|
||||
// files : progression par fichier récupérée depuis le client torrent.
|
||||
// Permet au worker de ne traiter que les fichiers à 100% et d'éviter
|
||||
// les EBUSY sur Windows quand qBit est encore en train d'écrire les autres.
|
||||
const fakeTorrent = { hash, name, save_path: savePath, state: 'seeding', files: files ?? [] }
|
||||
const result: OrganizeResult = { total: 0, skipped: 0, done: 0, errors: [] }
|
||||
|
||||
worker.on('message', (msg: any) => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { logger } from '../logger.js'
|
||||
import { organizeTorrent, migrateOrganizedEpisodeIds } from '../organize.js'
|
||||
import { loadEnrichedSeriesData } from '../lib/github-cache.js'
|
||||
import { recentOrganized, pushNotif } from '../lib/notifs.js'
|
||||
import { dispatchGetFiles } from '../torrent-clients/index.js'
|
||||
import { DATA_DIR } from '../config.js'
|
||||
import path from 'path'
|
||||
|
||||
@@ -36,7 +37,13 @@ router.post('/organize', requireAuth, async (req, res) => {
|
||||
if (!hash || !name || !save_path) { res.status(400).json({ error: 'hash, name et save_path requis' }); return }
|
||||
try {
|
||||
const seriesData = await loadEnrichedSeriesData()
|
||||
const result = await organizeTorrent(hash, name, save_path, seriesData)
|
||||
|
||||
// Récupère la progression par fichier depuis le client torrent.
|
||||
// Permet au worker de sauter les fichiers encore en téléchargement (EBUSY sur Windows).
|
||||
// En cas d'échec (client injoignable, hash non trouvé), on continue sans filtre.
|
||||
const files = await dispatchGetFiles(hash).catch(() => [])
|
||||
|
||||
const result = await organizeTorrent(hash, name, save_path, seriesData, files)
|
||||
if (result.done > 0 || result.errors.length > 0) {
|
||||
pushNotif({ hash, name, done: result.done, skipped: result.skipped, errors: result.errors.length, errorFiles: result.errors, at: new Date().toISOString() })
|
||||
}
|
||||
|
||||
@@ -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)!
|
||||
|
||||
@@ -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({
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3.20.0
|
||||
3.20.3
|
||||
Reference in new issue
Block a user