import { SearchResult, VideoLink, SeasonOption } from '../../src/types/source.js'; function getMediaTypeFromUrl(url: string): 'movie' | 'series' { return url.includes('/serie/') ? 'series' : 'movie'; } function unescapeHtml(html: string): string { return html .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, "'") .replace(/&/g, '&'); } export class FlixArtParser { static parseSearchAjax(htmlStr: string): SearchResult[] { const results: SearchResult[] = []; const cardRegex = /]*>([\s\S]*?)<\/a>/g; let match; while ((match = cardRegex.exec(htmlStr)) !== null) { const href = unescapeHtml(match[1]); const inner = match[2]; let title = ''; const titleMatch = inner.match(/([^<]+)<\/span>/); if (titleMatch) title = unescapeHtml(titleMatch[1].trim()); let year = null; const yearMatch = inner.match(/([^<]+)<\/span>/); if (yearMatch) year = yearMatch[1].trim(); let image = null; const imgMatch = inner.match(/]+src="([^"]+)"/); if (imgMatch) { image = unescapeHtml(imgMatch[1]); if (image.includes('&quality=')) image = image.split('&quality=')[0]; } if (title && href) { results.push({ title, year, image, hrefPath: href, type: getMediaTypeFromUrl(href), source: 'flixart' }); } } return results; } static parseTrending(htmlStr: string, isSeries: boolean): SearchResult[] { const results: SearchResult[] = []; const sectionTitle = isSeries ? 'Top 10 séries du jour' : 'Top 10 films du jour'; const fallbackTitle = isSeries ? 'Nouveautés séries' : 'Nouveautés films'; // Find section containing the title let sectionRegexStr = `
\\s*
\\s*

(${sectionTitle}|${fallbackTitle})<\\/h2>[\\s\\S]*?<\\/section>`; let sectionMatch = htmlStr.match(new RegExp(sectionRegexStr, 'i')); if (!sectionMatch) return results; const sectionHtml = sectionMatch[0]; const cardRegex = /
([\s\S]*?)<\/article>/g; let match; while ((match = cardRegex.exec(sectionHtml)) !== null) { const inner = match[1]; let href = null; let title = ''; const titleMatch = inner.match(/

]*>([^<]+)<\/a><\/h3>/); if (titleMatch) { href = unescapeHtml(titleMatch[1]); title = unescapeHtml(titleMatch[2].trim()); } let image = null; const imgMatch = inner.match(/]+class="[^"]*flixart-season-tab[^"]*"[^>]+data-season="([^"]+)"[^>]*>([\s\S]*?)<\/button>/g; let match; while ((match = seasonTabRegex.exec(htmlStr)) !== null) { isSeries = true; const val = match[1]; const inner = match[2]; const numMatch = inner.match(/([^<]+)<\/span>/); if (numMatch) { seasons.push({ label: `Saison ${numMatch[1].trim()}`, value: val }); } } const rowRegex = /
]*data-qualite="([^"]*)"[^>]*data-langue="([^"]*)"[^>]*>([\s\S]*?)<\/div>/g; while ((match = rowRegex.exec(htmlStr)) !== null) { const inner = match[3]; let episode = null; const episodeMatch = htmlStr.substring(match.index - 100, match.index).match(/data-episode="([^"]+)"/); if (episodeMatch) episode = episodeMatch[1]; const checkboxMatch = inner.match(/]+data-flixart-download-select[^>]+data-row-index="(\d+)"[^>]*data-download-title="([^"]*)"[^>]*data-download-meta="([^"]*)"/); if (checkboxMatch) { const rowIndex = checkboxMatch[1]; const title = unescapeHtml(checkboxMatch[2]); const meta = unescapeHtml(checkboxMatch[3]); let host = 'Inconnu'; const lowerMeta = meta.toLowerCase(); if (lowerMeta.includes('1fichier')) host = '1fichier'; else if (lowerMeta.includes('nitroflare')) host = 'nitroflare'; else if (lowerMeta.includes('ddownload')) host = 'ddownload'; links.push({ id: rowIndex, host, label: title, quality: meta, url: null, episode }); } } return { links, seasons, isSeries, postId, nonce }; } }