mirror of
https://github.com/Viren070/AIOStreams.git
synced 2025-12-01 23:14:04 +01:00
feat(seadex): add release group fallback matching (#521)
Co-authored-by: Viren070 <viren070@protonmail.com>
This commit is contained in:
@@ -82,9 +82,7 @@ const SizeFilter = z.object({
|
||||
// max: z.number().min(1).optional(),
|
||||
// })
|
||||
.optional(),
|
||||
anime: z
|
||||
.tuple([z.number().min(0), z.number().min(0)])
|
||||
.optional(),
|
||||
anime: z.tuple([z.number().min(0), z.number().min(0)]).optional(),
|
||||
});
|
||||
|
||||
const SizeFilterOptions = z.object({
|
||||
|
||||
@@ -326,7 +326,7 @@ export abstract class BaseFormatter {
|
||||
network: stream.parsedFile?.network || null,
|
||||
container: stream.parsedFile?.container || null,
|
||||
extension: stream.parsedFile?.extension || null,
|
||||
seadex: (stream.seadex?.isSeadex && !stream.seadex?.isBest) ?? false,
|
||||
seadex: stream.seadex?.isSeadex ?? false,
|
||||
seadexBest: stream.seadex?.isBest ?? false,
|
||||
},
|
||||
addon: {
|
||||
|
||||
@@ -507,7 +507,7 @@ export abstract class StreamExpressionEngine {
|
||||
return streams.filter((stream) => stream.seadex?.isBest === true);
|
||||
}
|
||||
|
||||
// Return all SeaDex releases (best or regular)
|
||||
// Return all SeaDex releases (includes group fallback matches)
|
||||
return streams.filter((stream) => stream.seadex?.isSeadex === true);
|
||||
};
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ class StreamPrecomputer {
|
||||
|
||||
/**
|
||||
* Precompute SeaDex status for anime streams
|
||||
* Tags streams with seadex.isBest and seadex.isSeadex based on infoHash matching
|
||||
* Tags streams with seadex.isBest and seadex.isSeadex
|
||||
* First tries to match by infoHash, then falls back to release group matching
|
||||
*/
|
||||
private async precomputeSeaDex(
|
||||
streams: ParsedStream[],
|
||||
@@ -80,20 +81,22 @@ class StreamPrecomputer {
|
||||
|
||||
if (
|
||||
seadexResult.bestHashes.size === 0 &&
|
||||
seadexResult.allHashes.size === 0
|
||||
seadexResult.allHashes.size === 0 &&
|
||||
seadexResult.bestGroups.size === 0 &&
|
||||
seadexResult.allGroups.size === 0
|
||||
) {
|
||||
logger.debug(`No SeaDex releases found for AniList ID ${anilistId}`);
|
||||
return;
|
||||
}
|
||||
let seadexBestCount = 0;
|
||||
let seadexCount = 0;
|
||||
let seadexGroupFallbackCount = 0;
|
||||
|
||||
for (const stream of streams) {
|
||||
const infoHash = stream.torrent?.infoHash?.toLowerCase();
|
||||
if (!infoHash) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// First try hash matching
|
||||
if (infoHash) {
|
||||
const isBest = seadexResult.bestHashes.has(infoHash);
|
||||
const isSeadex = seadexResult.allHashes.has(infoHash);
|
||||
|
||||
@@ -107,12 +110,33 @@ class StreamPrecomputer {
|
||||
seadexBestCount++;
|
||||
}
|
||||
seadexCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to release group matching
|
||||
const releaseGroup = stream.parsedFile?.releaseGroup?.toLowerCase();
|
||||
if (releaseGroup) {
|
||||
const isBestGroup = seadexResult.bestGroups.has(releaseGroup);
|
||||
const isSeadexGroup = seadexResult.allGroups.has(releaseGroup);
|
||||
|
||||
if (isBestGroup || isSeadexGroup) {
|
||||
stream.seadex = {
|
||||
isBest: isBestGroup,
|
||||
isSeadex: true,
|
||||
};
|
||||
if (isBestGroup) {
|
||||
seadexBestCount++;
|
||||
}
|
||||
seadexCount++;
|
||||
seadexGroupFallbackCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (seadexCount > 0) {
|
||||
logger.info(
|
||||
`Tagged ${seadexCount} streams as SeaDex releases (${seadexBestCount} best) for AniList ID ${anilistId}`
|
||||
`Tagged ${seadexCount} streams as SeaDex releases (${seadexBestCount} best, ${seadexGroupFallbackCount} via group fallback) for AniList ID ${anilistId}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1082,9 +1082,9 @@ export const SORT_CRITERIA_DETAILS: Record<
|
||||
description:
|
||||
'Whether the stream is a SeaDex release (curated best anime releases from releases.moe)',
|
||||
ascendingDescription:
|
||||
'Non-SeaDex releases are preferred over SeaDex releases',
|
||||
'Streams that are not listed on SeaDex are preferred',
|
||||
descendingDescription:
|
||||
'SeaDex Best releases are preferred, then other SeaDex releases, then non-SeaDex releases',
|
||||
'Streams that are marked as the Best release on SeaDex are preferred, followed by the Alternative release',
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -19,11 +19,19 @@ const seadexCache = Cache.getInstance<string, SeaDexResult>(
|
||||
export interface SeaDexResult {
|
||||
bestHashes: Set<string>;
|
||||
allHashes: Set<string>;
|
||||
bestGroups: Set<string>;
|
||||
allGroups: Set<string>;
|
||||
}
|
||||
|
||||
export interface SeaDexTagResult {
|
||||
isBest: boolean;
|
||||
isSeadex: boolean;
|
||||
}
|
||||
|
||||
interface SeaDexTorrent {
|
||||
infoHash: string;
|
||||
isBest: boolean;
|
||||
releaseGroup?: string;
|
||||
}
|
||||
|
||||
interface SeaDexEntry {
|
||||
@@ -77,7 +85,12 @@ export class SeaDexApi {
|
||||
logger.warn(
|
||||
`SeaDex API returned ${response.status} for AniList ID ${anilistId}`
|
||||
);
|
||||
return { bestHashes: new Set(), allHashes: new Set() };
|
||||
return {
|
||||
bestHashes: new Set(),
|
||||
allHashes: new Set(),
|
||||
bestGroups: new Set(),
|
||||
allGroups: new Set(),
|
||||
};
|
||||
}
|
||||
|
||||
const data = (await response.json()) as SeaDexResponse;
|
||||
@@ -88,6 +101,8 @@ export class SeaDexApi {
|
||||
const emptyResult: SeaDexResult = {
|
||||
bestHashes: new Set(),
|
||||
allHashes: new Set(),
|
||||
bestGroups: new Set(),
|
||||
allGroups: new Set(),
|
||||
};
|
||||
await seadexCache.set(cacheKey, emptyResult, SEADEX_CACHE_TTL);
|
||||
return emptyResult;
|
||||
@@ -95,6 +110,8 @@ export class SeaDexApi {
|
||||
|
||||
const bestHashes = new Set<string>();
|
||||
const allHashes = new Set<string>();
|
||||
const bestGroups = new Set<string>();
|
||||
const allGroups = new Set<string>();
|
||||
|
||||
for (const item of items) {
|
||||
const trsArray = item.expand?.trs;
|
||||
@@ -114,13 +131,29 @@ export class SeaDexApi {
|
||||
bestHashes.add(infoHash);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect release groups
|
||||
for (const torrent of trsArray) {
|
||||
const releaseGroup = torrent.releaseGroup?.toLowerCase();
|
||||
if (!releaseGroup) continue;
|
||||
|
||||
allGroups.add(releaseGroup);
|
||||
if (torrent.isBest) {
|
||||
bestGroups.add(releaseGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`Found ${bestHashes.size} best and ${allHashes.size} total SeaDex hashes for AniList ID ${anilistId}`
|
||||
`Found ${bestHashes.size} best hashes, ${allHashes.size} total hashes, ${bestGroups.size} best groups, ${allGroups.size} total groups for AniList ID ${anilistId}`
|
||||
);
|
||||
|
||||
const result: SeaDexResult = { bestHashes, allHashes };
|
||||
const result: SeaDexResult = {
|
||||
bestHashes,
|
||||
allHashes,
|
||||
bestGroups,
|
||||
allGroups,
|
||||
};
|
||||
await seadexCache.set(cacheKey, result, SEADEX_CACHE_TTL);
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -131,6 +164,8 @@ export class SeaDexApi {
|
||||
return {
|
||||
bestHashes: new Set(),
|
||||
allHashes: new Set(),
|
||||
bestGroups: new Set(),
|
||||
allGroups: new Set(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user