package onlinestream_providers var AnimepahePayload = "/// \n/// \n/// \n\ntype EpisodeData = {\n id: number; episode: number; title: string; snapshot: string; filler: number; session: string; created_at?: string\n}\n\ntype AnimeData = {\n id: number; title: string; type: string; year: number; poster: string; session: string\n}\n\nclass Provider {\n\n api = \"https://animepahe.ru\"\n headers = { Referer: \"https://kwik.si\" }\n\n getSettings(): Settings {\n return {\n episodeServers: [\"kwik\"],\n supportsDub: false,\n }\n }\n\n async search(opts: SearchOptions): Promise {\n const req = await fetch(`${this.api}/api?m=search&q=${encodeURIComponent(opts.query)}`, {\n headers: {\n Cookie: \"__ddg1_=;__ddg2_=;\",\n },\n })\n\n if (!req.ok) {\n return []\n }\n const data = (await req.json()) as { data: AnimeData[] }\n const results: SearchResult[] = []\n\n if (!data?.data) {\n return []\n }\n\n data.data.map((item: AnimeData) => {\n results.push({\n subOrDub: \"sub\",\n id: item.session,\n title: item.title,\n url: \"\",\n })\n })\n\n return results\n }\n\n async findEpisodes(id: string): Promise {\n let episodes: EpisodeDetails[] = []\n\n const req =\n await fetch(\n `${this.api}${id.includes(\"-\") ? `/anime/${id}` : `/a/${id}`}`,\n {\n headers: {\n Cookie: \"__ddg1_=;__ddg2_=;\",\n },\n },\n )\n\n const html = await req.text()\n\n\n function pushData(data: EpisodeData[]) {\n for (const item of data) {\n episodes.push({\n id: item.session + \"$\" + id,\n number: item.episode,\n title: item.title && item.title.length > 0 ? item.title : \"Episode \" + item.episode,\n url: req.url,\n })\n }\n }\n\n const $ = LoadDoc(html)\n\n const tempId = $(\"head > meta[property='og:url']\").attr(\"content\")!.split(\"/\").pop()!\n\n const { last_page, data } = (await (\n await fetch(`${this.api}/api?m=release&id=${tempId}&sort=episode_asc&page=1`, {\n headers: {\n Cookie: \"__ddg1_=;__ddg2_=;\",\n },\n })\n ).json()) as {\n last_page: number;\n data: EpisodeData[]\n }\n\n pushData(data)\n\n const pageNumbers = Array.from({ length: last_page - 1 }, (_, i) => i + 2)\n\n const promises = pageNumbers.map((pageNumber) =>\n fetch(`${this.api}/api?m=release&id=${tempId}&sort=episode_asc&page=${pageNumber}`, {\n headers: {\n Cookie: \"__ddg1_=;__ddg2_=;\",\n },\n }).then((res) => res.json()),\n )\n const results = (await Promise.all(promises)) as {\n data: EpisodeData[]\n }[]\n\n results.forEach((showData) => {\n for (const data of showData.data) {\n if (data) {\n pushData([data])\n }\n }\n });\n (data as any[]).sort((a, b) => a.number - b.number)\n\n if (episodes.length === 0) {\n throw new Error(\"No episodes found.\")\n }\n\n\n const lowest = episodes[0].number\n if (lowest > 1) {\n for (let i = 0; i < episodes.length; i++) {\n episodes[i].number = episodes[i].number - lowest + 1\n }\n }\n \n // Remove decimal episode numbers\n episodes = episodes.filter((episode) => Number.isInteger(episode.number))\n\n // for (let i = 0; i < episodes.length; i++) {\n // // If an episode number is a decimal, round it up to the nearest whole number\n // if (Number.isInteger(episodes[i].number)) {\n // continue\n // }\n // const original = episodes[i].number\n // episodes[i].number = Math.floor(episodes[i].number)\n // episodes[i].title = `Episode ${episodes[i].number} [{${original}}]`\n // }\n\n return episodes\n }\n\n async findEpisodeServer(episode: EpisodeDetails, _server: string): Promise {\n const episodeId = episode.id.split(\"$\")[0]\n const animeId = episode.id.split(\"$\")[1]\n\n console.log(`${this.api}/play/${animeId}/${episodeId}`)\n\n const req = await fetch(\n `${this.api}/play/${animeId}/${episodeId}`,\n {\n headers: {\n Cookie: \"__ddg1_=;__ddg2_=;\",\n },\n },\n )\n\n const html = await req.text()\n\n const regex = /https:\\/\\/kwik\\.si\\/e\\/\\w+/g\n const matches = html.match(regex)\n\n if (matches === null) {\n throw new Error(\"Failed to fetch episode server.\")\n }\n\n const $ = LoadDoc(html)\n\n const result: EpisodeServer = {\n videoSources: [],\n headers: this.headers ?? {},\n server: \"kwik\",\n }\n\n $(\"button[data-src]\").each(async (_, el) => {\n let videoSource: VideoSource = {\n url: \"\",\n type: \"m3u8\",\n quality: \"\",\n subtitles: [],\n }\n\n videoSource.url = el.data(\"src\")!\n if (!videoSource.url) {\n return\n }\n\n const fansub = el.data(\"fansub\")!\n const quality = el.data(\"resolution\")!\n\n videoSource.quality = `${quality}p - ${fansub}`\n\n if (el.data(\"audio\") === \"eng\") {\n videoSource.quality += \" (Eng)\"\n }\n\n if (videoSource.url === matches[0]) {\n videoSource.quality += \" (default)\"\n }\n\n result.videoSources.push(videoSource)\n })\n\n await Promise.all(result.videoSources.map(async (videoSource) => {\n try {\n const src_req = await fetch(videoSource.url, {\n headers: {\n Referer: this.headers.Referer,\n \"user-agent\":\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.56\",\n },\n })\n\n const src_html = await src_req.text()\n\n const scripts = src_html.match(/eval\\(f.+?\\}\\)\\)/g)\n if (!scripts) {\n return\n }\n\n for (const _script of scripts) {\n const scriptMatch = _script.match(/eval(.+)/)\n if (!scriptMatch || !scriptMatch[1]) {\n continue\n }\n\n try {\n const decoded = eval(scriptMatch[1])\n const link = decoded.match(/source='(.+?)'/)\n if (!link || !link[1]) {\n continue\n }\n\n videoSource.url = link[1]\n\n }\n catch (e) {\n console.error(\"Failed to extract kwik link\", e)\n }\n\n }\n\n }\n catch (e) {\n console.error(\"Failed to fetch kwik link\", e)\n }\n }))\n\n return result\n }\n}\n\n"