feat(api): Prime Video scraping ve saglayiciya duyarlı metadata destegi ekle

This commit is contained in:
2026-03-01 01:13:41 +03:00
parent 96d8a66a97
commit 84131576cf
11 changed files with 515 additions and 166 deletions

View File

@@ -6,21 +6,29 @@ import { MetricsService } from './metrics.service.js';
import { CacheService } from './cache.service.js';
import { ContentService } from './content.service.js';
import type { AdminActionResponse, AdminOverviewResponse } from '../types/index.js';
import { parseSupportedContentUrl } from '../utils/contentUrl.js';
const CACHE_PREFIX = 'netflix:content:';
const CACHE_PREFIX = 'content:';
const MAX_CACHE_KEYS_FOR_ANALYSIS = 1000;
function formatCacheKeyLabel(key: string): string {
return key.replace(CACHE_PREFIX, '');
}
function extractTitleIdFromCacheKey(key: string): string | null {
function extractProviderIdFromCacheKey(key: string): { provider: string; id: string } | null {
const normalized = formatCacheKeyLabel(key);
return /^\d+$/.test(normalized) ? normalized : null;
const match = normalized.match(/^(netflix|primevideo):([A-Za-z0-9]+)$/);
if (!match) return null;
const provider = match[1];
const id = match[2];
if (!provider || !id) return null;
return { provider, id };
}
function extractTitleIdFromUrl(url: string): string | null {
return url.match(/\/title\/(\d+)/)?.[1] ?? null;
function extractProviderIdFromUrl(url: string): { provider: string; id: string } | null {
const parsed = parseSupportedContentUrl(url);
if (!parsed) return null;
return { provider: parsed.provider, id: parsed.id };
}
function parseRedisInfoValue(info: string, key: string): number | null {
@@ -144,16 +152,25 @@ export class AdminService {
min30Plus: 0,
};
const cacheTitleIds = Array.from(
new Set(cacheKeys.map((key) => extractTitleIdFromCacheKey(key)).filter((id): id is string => Boolean(id)))
const cacheProviderIds = Array.from(
new Set(
cacheKeys
.map((key) => extractProviderIdFromCacheKey(key))
.filter((item): item is { provider: string; id: string } => Boolean(item))
.map((item) => `${item.provider}:${item.id}`)
)
);
const relatedContent = cacheTitleIds.length
const relatedContent = cacheProviderIds.length
? await prisma.content.findMany({
where: {
OR: cacheTitleIds.map((id) => ({
url: { contains: `/title/${id}` },
})),
OR: cacheProviderIds.map((providerId) => {
const [provider, id] = providerId.split(':');
if (provider === 'primevideo') {
return { url: { contains: `/detail/${id}` } };
}
return { url: { contains: `/title/${id}` } };
}),
},
select: {
url: true,
@@ -164,9 +181,12 @@ export class AdminService {
const titleMap = new Map<string, string>();
for (const item of relatedContent) {
const id = extractTitleIdFromUrl(item.url);
if (id && !titleMap.has(id)) {
titleMap.set(id, item.title);
const parsed = extractProviderIdFromUrl(item.url);
if (parsed) {
const key = `${parsed.provider}:${parsed.id}`;
if (!titleMap.has(key)) {
titleMap.set(key, item.title);
}
}
}
@@ -196,7 +216,7 @@ export class AdminService {
if (ttlValue > 0) {
const formattedKey = formatCacheKeyLabel(cacheKeys[i] || '');
const titleId = extractTitleIdFromCacheKey(cacheKeys[i] || '');
const providerId = extractProviderIdFromCacheKey(cacheKeys[i] || '');
const rawValue = valueResults?.[i]?.[1];
let cachedAt: number | null = null;
if (typeof rawValue === 'string') {
@@ -209,7 +229,9 @@ export class AdminService {
}
expiringSoon.push({
key: formattedKey,
mediaTitle: titleId ? titleMap.get(titleId) ?? null : null,
mediaTitle: providerId
? titleMap.get(`${providerId.provider}:${providerId.id}`) ?? null
: null,
cachedAt,
ttlSeconds: ttlValue,
});
@@ -450,6 +472,23 @@ export class AdminService {
details: `Stale content refresh queued for items older than ${days} days`,
};
}
static async purgeAllContent(): Promise<AdminActionResponse> {
const totalContent = await prisma.content.count();
await prisma.$transaction([
prisma.content.deleteMany({}),
prisma.genre.deleteMany({}),
]);
await CacheService.clearAll();
return {
queued: totalContent,
skipped: 0,
details: 'Tum icerik verileri veritabanindan silindi',
};
}
}
export default AdminService;