| async function handle(request, connInfo) { |
| const corsHeaders = { |
| headers: { |
| "Access-Control-Allow-Origin": "*", |
| }, |
| }; |
| const corsOptionsHeaders = { |
| "Access-Control-Allow-Origin": "*", |
| "Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS", |
| "Access-Control-Max-Age": "86400", |
| }; |
|
|
| async function handleRequest(request, connInfo) { |
| const url = new URL(request.url); |
| let api_pos = url.origin.length + 1; |
| let api = url.href.substring(api_pos); |
| let proxy_url = url.href; |
| let proxy = ""; |
| let proxy_enc = ""; |
| let enc = ""; |
| let ip = "no"; |
| let redirect = request.method === "POST" ? "manual" : "follow"; |
| let get_cookie = false; |
| let cookie_plus = false; |
| let remove_compression = false; |
| let params = []; |
| let cdn_info = "cdn_c8Bc9aMo"; |
| let user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36"; |
|
|
| if (api === "headers") { |
| let body = ""; |
| request.headers.forEach((value, key) => body += key + " = " + value + "\n"); |
| if (connInfo && connInfo.remoteAddr) { |
| body += "connInfo" + " = " + JSON.stringify(connInfo.remoteAddr) + "\n"; |
| } |
| body += "request_url" + " = " + request.url + "\n"; |
| body += "apn_version = 1.11\n"; |
| return new Response(body, corsHeaders); |
| } |
|
|
| if (api.startsWith("?")) { |
| api_pos += 1; |
| api = api.substring(1); |
| } |
|
|
| let next_param = true; |
| while (next_param) { |
| if (api.startsWith("ip")) { |
| let pos = api.indexOf("/"); |
| if (pos !== -1) { |
| ip = api.substring(2, pos); |
| api_pos += pos + 1; |
| api = api.substring(pos + 1); |
| } else { |
| ip = api.substring(2); |
| api_pos += api.length; |
| api = ""; |
| } |
| } else if (api.startsWith("redirect=")) { |
| let pos = api.indexOf("/"); |
| if (pos !== -1) { |
| redirect = api.substring(9, pos); |
| api_pos += pos + 1; |
| api = api.substring(pos + 1); |
| } else { |
| redirect = api.substring(9); |
| api_pos += api.length; |
| api = ""; |
| } |
| } else if (api.startsWith("get_cookie/")) { |
| get_cookie = true; |
| api_pos += 11; |
| api = api.substring(11); |
| } else if (api.startsWith("cookie_plus/")) { |
| cookie_plus = true; |
| remove_compression = true; |
| api_pos += 12; |
| api = api.substring(12); |
| } else if (api.startsWith("param?") || api.startsWith("param/")) { |
| api_pos += 6; |
| api = api.substring(6); |
| let param; |
| let pos = api.indexOf("/"); |
| if (pos !== -1) { |
| param = api.substring(0, pos); |
| api_pos += pos + 1; |
| api = api.substring(pos + 1); |
| } else { |
| param = api.substring(0); |
| api_pos += api.length; |
| api = ""; |
| } |
| pos = param.indexOf("="); |
| if (pos !== -1) { |
| params.push([param.substring(0, pos), param.substring(pos + 1)]); |
| } else { |
| params.push([param]); |
| } |
| } else if (api.startsWith("enc/") || api.startsWith("enc1/") || api.startsWith("enc2/")) { |
| let cur_enc = api.substring(0, api.indexOf("/")); |
| if (enc) { |
| proxy_enc += proxy_url.substring(0, api_pos); |
| } else { |
| proxy += proxy_url.substring(0, api_pos); |
| enc = cur_enc; |
| } |
| api = api.substring(cur_enc.length + 1); |
| let pos = api.indexOf("/"); |
| if (pos !== -1) { |
| api = atob(decodeURIComponent(api.substring(0, pos))) + (cur_enc === "enc2" ? "" : api.substring(pos + 1)); |
| } else { |
| api = atob(decodeURIComponent(api.substring(0))); |
| } |
| proxy_url = api; |
| api_pos = 0; |
| } else { |
| next_param = false; |
| } |
| } |
|
|
| if (enc) { |
| proxy_enc += proxy_url.substring(0, api_pos); |
| } else { |
| proxy += proxy_url.substring(0, api_pos); |
| } |
|
|
| let forwarded_proto = request.headers.get("X-Forwarded-Proto"); |
| if (forwarded_proto) forwarded_proto = forwarded_proto.split(",")[0].trim(); |
| if (forwarded_proto === "https") proxy = proxy.replace("http://", "https://"); |
|
|
| if (!ip) { |
| let forwarded_for = request.headers.get("X-Forwarded-For"); |
| if (forwarded_for) ip = forwarded_for.split(",").map(s=>s.trim()).find(s=>s && !s.match(/^(127\.|10\.|172\.1[6-9]|172\.2[0-9]|172\.3[01]|192\.168\.)/)) || ""; |
| } |
| if (!ip) ip = request.headers.get("cf-connecting-ip"); |
| if (!ip) ip = request.headers.get("X-Real-IP"); |
| if (!ip) ip = connInfo && connInfo.remoteAddr && connInfo.remoteAddr.hostname || ""; |
|
|
| if (!api || !/^https?:\/\/[^\/]/.test(api)) { |
| let error = "Malformed URL"; |
| return new Response(error + ": " + api, { |
| ...corsHeaders, |
| status: 404, |
| statusText: error, |
| }); |
| } |
| const apiUrl = new URL(api); |
| let apiBase = apiUrl.href.substring(0, apiUrl.href.lastIndexOf("/") + 1); |
|
|
| let clientUserAgent = request.headers.get("User-Agent") || ''; |
| let clientOrigin = request.headers.get("Origin") || ''; |
| if( |
| (/\blampishe\b|\bprisma_client\b/).test(clientUserAgent) || |
| clientOrigin.endsWith("lampishe.cc") || |
| clientOrigin.endsWith("prisma.ws") || |
| clientOrigin.endsWith("bylampa.online") |
| ) { |
| let error = "Malformed URL"; |
| return new Response(error + ": " + api, { |
| ...corsHeaders, |
| status: 404, |
| statusText: error, |
| }); |
| } |
|
|
| |
| |
| |
| request = new Request(api, request); |
|
|
| let cdn_loop = request.headers.get("CDN-Loop"); |
| if (cdn_loop && cdn_loop.indexOf(cdn_info) !== -1) { |
| let error = "CDN-Loop detected"; |
| return new Response(error, { |
| ...corsHeaders, |
| status: 403, |
| statusText: error, |
| }); |
| } else { |
| request.headers.append("CDN-Loop", cdn_info); |
| } |
|
|
| request.headers.set("Origin", apiUrl.origin); |
| request.headers.set("Referer", apiUrl.origin + "/"); |
| if (true) { |
| request.headers.delete("Sec-Fetch-Dest"); |
| request.headers.delete("Sec-Fetch-Mode"); |
| request.headers.delete("Sec-Fetch-Site"); |
| request.headers.delete("Sec-Fetch-User"); |
| request.headers.delete("Sec-CH-UA"); |
| request.headers.delete("Sec-CH-UA-Mobile"); |
| request.headers.delete("Sec-CH-UA-Platform"); |
| request.headers.delete("Host"); |
| } |
| if (true) { |
| request.headers.delete("X-Forwarded-For"); |
| request.headers.delete("X-Forwarded-Proto"); |
| |
| |
| request.headers.delete("cf-ipcountry"); |
| request.headers.delete("cf-ray"); |
| request.headers.delete("cf-visitor"); |
| } |
| if (ip && ip !== "no") { |
| request.headers.set("X-Forwarded-For", ip); |
| request.headers.set("X-Forwarded-Proto", "https"); |
| request.headers.set("X-Real-IP", ip); |
| request.headers.set("cf-connecting-ip", ip); |
| } |
| if (apiUrl.hostname === "rezka.ag" || apiUrl.hostname === "hdrezka.ag" || apiUrl.hostname === "hdrezka.me" || apiUrl.hostname === "hdrezka.sh" || apiUrl.hostname === "hdrezka.cm" || apiUrl.hostname === "hdrezka.kim" || apiUrl.hostname === "hdrezka.la" || apiUrl.hostname === "rezka.pub" || apiUrl.hostname === "kinopub.me") { |
| request.headers.set("User-Agent", user_agent); |
| } |
| if (apiUrl.hostname.endsWith(".svetacdn.in")) { |
| request.headers.set("Origin", "https://videocdn.tv"); |
| request.headers.set("Referer", "https://videocdn.tv/"); |
| } |
| if (apiUrl.hostname === ("huaren.live")) { |
| |
| request.headers.set("Cookie", "CF_HUAREN_LIVE=0.QrB7D5f-9p7YlmEZ6ymIP0sJQ5MsFapWKJLKT9Q5Dz6frtplEmWxCFujxZsEtzz52ed4VV2ekf3aOcQOGnOEGY_jCCNboSyaEg3ntNJLGqgRkdrfzCSOBI_0qmZS6y_1adbNlhKzezqa7hMiCR286X0IgGlShIUONbSlXOuy2GoWh56uurfHlcRY16-IDKmpmjOgB7OLC1MaQNlYADdvkIsA0qncFVcbyS48EuswXYBOumzqatxsEDwv6uh0YbqeHnCpOU1Bp0yyVl8iCm0-YXLSjRISFWO6dcUMpOacjz8eHQiuvnoxvLN-26EiZzRjqDd1A8fdViCv5HXfLlTP43nN9z_JA9BZ0D16CjNK_EHv8FjEldBj19V9ENNCb0hPu-jMJ3pgcQUWtexM3mF_myReYWx9qfO6mWT1wwtRpQHAcFQDlagTNdNPhCuFQOTLCzGabPCQMf-un4gM1EJUQg0llhz75wlaQY10pduitVhb95uI99D1oV-uBt9QaXOasOUjSgmLYqYwGM7hG6FlQJwX6EDwJFTMjLetC4rg6AEskVvENSKsw68dcTPecEP0jVtIYujc83xG2Ij8K7uXbsl8dDKgmJK8_1JWxlEWbQuQ6top3uwskdU0wwfjDrZRqwt_wp4Y4PbrxYgv6WHw1YtBdqpqW4uXESAnPhih78KcabKBfVQnTHU1f6v-RZ3B-RIiMVjKeqAn63EaLsEMGwDF26Jgz_RJVLH9Iltgu33_yRv-7TdKSyo-3WVLlqRDNp6wpAL9B3SgyOM5LlTj15m_u82zZt7nXBES0uOwxgrwThDeOhmZ3UqOTiUwCQiC-GtDnqUddPYBxcUFlvBEGRBGl7JzIEN6U9NCKZyfEFlWjple-DX_N6jWJM2ZnH1V.SL7Vt4Fyb55NhZDE8eVaBw.20c6a876734a4527a144bb56d523c9dfa3b2f397b45e31734ed8984440d423f8; ecPopup=1"); |
| } |
| if (apiUrl.hostname === "api.lumex.pw") { |
| request.headers.set("User-Agent", user_agent); |
| request.headers.set("Origin", "https://p.lumex.pw"); |
| request.headers.set("Referer", "https://p.lumex.pw/"); |
| request.headers.set("Sec-Fetch-Dest", "empty"); |
| request.headers.set("Sec-Fetch-Mode", "cors"); |
| request.headers.set("Sec-Fetch-Site", "same-site"); |
| } |
| if (apiUrl.hostname.endsWith("cdnmovies-stream.online") || apiUrl.hostname.endsWith("cdnmovies-hls-stream.online") || apiUrl.hostname.endsWith(".sarnage.cc")) { |
| request.headers.set("Origin", "https://cdnmovies.net"); |
| request.headers.set("Referer", "https://cdnmovies.net/"); |
| } |
| if (apiUrl.hostname.endsWith(".bazon.site")) { |
| request.headers.set("User-Agent", user_agent); |
| request.headers.set("Origin", "https://bazon.cc"); |
| request.headers.set("Referer", "https://bazon.cc/"); |
| } |
| if (["kodikapi.com", "kodik.biz", "kodik.info"].indexOf(apiUrl.hostname) !== -1) { |
| request.headers.delete("Origin"); |
| request.headers.delete("Referer"); |
| } |
| if (apiUrl.hostname === "kinoplay.site" || apiUrl.hostname === "kinoplay1.site" || apiUrl.hostname === "kinoplay2.site") { |
| request.headers.set("Cookie", "invite=a246a3f46c82fe439a45c3dbbbb24ad5"); |
| } |
| if (apiUrl.pathname.endsWith(".m3u8") || apiUrl.pathname.endsWith(".m3u") || apiUrl.pathname.endsWith(".M3U8") || apiUrl.pathname.endsWith(".M3U") || apiUrl.pathname.endsWith(".mpd") || apiUrl.pathname.endsWith(".MPD")) { |
| request.headers.delete("Range"); |
| remove_compression = true; |
| } |
| if (remove_compression) { |
| let encoding = (request.headers.get("Accept-Encoding") || ""); |
| if (encoding.includes("zstd") || encoding.includes("deflate")) { |
| encoding = encoding.split(",").filter(enc=>!(enc.includes("zstd") || enc.includes("deflate"))).join(",") || "identity"; |
| request.headers.set("Accept-Encoding", encoding); |
| } |
| } |
| params.forEach(param => { |
| if (param[0]) { |
| if (param[1]) { |
| request.headers.set(decodeURIComponent(param[0]), decodeURIComponent(param[1] || "")); |
| } else { |
| request.headers.delete(decodeURIComponent(param[0])); |
| } |
| } |
| }); |
| let response = await fetch(request, { |
| redirect: redirect, |
| }); |
|
|
| |
| response = new Response(response.body, response); |
|
|
| |
| response.headers.set("Access-Control-Allow-Origin", "*"); |
|
|
| |
| response.headers.append("Vary", "Origin"); |
|
|
| if (response.status >= 200 && response.status < 300) { |
| let ctype = (response.headers.get("Content-Type") || "").split(";")[0].toLowerCase(); |
| if (get_cookie || cookie_plus) { |
| let json = {}; |
| json.cookie = response.headers.getSetCookie(); |
| if (cookie_plus) { |
| let headers = {}; |
| for (let key of response.headers.keys()) { |
| if (key === "set-cookie") { |
| headers[key] = json.cookie; |
| } else { |
| headers[key] = response.headers.get(key); |
| } |
| } |
| json.headers = headers; |
| if (ctype.startsWith("text/") || ["application/json", "application/xml", "application/x-mpegurl", "application/vnd.apple.mpegurl", "application/dash+xml"].indexOf(ctype) !== -1) { |
| json.body = await response.text(); |
| } |
| } |
| return new Response(JSON.stringify(json), { |
| headers: { |
| "Access-Control-Allow-Origin": "*", |
| "Vary": "Origin", |
| "Content-Type": "application/json; charset=utf-8", |
| }, |
| }); |
| } |
| if (["application/x-mpegurl", "application/vnd.apple.mpegurl"].indexOf(ctype) !== -1) { |
| let body = edit_m3u8(await response.text(), apiUrl, apiBase, proxy, proxy_enc, enc); |
| response.headers.delete("Content-Length"); |
| response.headers.delete("Content-Range"); |
| response.headers.set("Accept-Ranges", "none"); |
| return new Response(body, response); |
| } |
| if (["application/dash+xml"].indexOf(ctype) !== -1) { |
| let body = edit_mpd(await response.text(), apiUrl, apiBase, proxy, proxy_enc, enc); |
| response.headers.delete("Content-Length"); |
| response.headers.delete("Content-Range"); |
| response.headers.set("Accept-Ranges", "none"); |
| return new Response(body, response); |
| } |
| } |
|
|
| |
| if (response.status >= 300 && response.status < 400) { |
| let target = response.headers.get("Location"); |
| if (target) { |
| response.headers.set("Location", proxyLink(fixLink(target, apiUrl, apiBase), proxy, proxy_enc, enc)); |
| } |
| } |
|
|
| return response; |
| } |
|
|
| function fixLink(link, url, base) { |
| if (link) { |
| if (link.indexOf("://") !== -1) return link; |
| if (link.startsWith("//")) return url.protocol + link; |
| if (link.startsWith("/")) return url.origin + link; |
| if (link.startsWith("?")) return url.origin + url.pathname + link; |
| if (link.startsWith("#")) return url.origin + url.pathname + url.search + link; |
| return base + link; |
| } |
| return link; |
| } |
|
|
| function proxyLink(link, proxy, proxy_enc, enc) { |
| if (link) { |
| if (enc === "enc") { |
| let pos = link.indexOf("/"); |
| if (pos !== -1 && link.charAt(pos + 1) === "/") pos++; |
| let part1 = pos !== -1 ? link.substring(0, pos + 1) : ""; |
| let part2 = pos !== -1 ? link.substring(pos + 1) : link; |
| return proxy + "enc/" + encodeURIComponent(btoa(proxy_enc + part1)) + "/" + part2; |
| } |
| if (enc === "enc1") { |
| let pos = link.lastIndexOf("/"); |
| let part1 = pos !== -1 ? link.substring(0, pos + 1) : ""; |
| let part2 = pos !== -1 ? link.substring(pos + 1) : link; |
| return proxy + "enc1/" + encodeURIComponent(btoa(proxy_enc + part1)) + "/" + part2; |
| } |
| if (enc === "enc2") { |
| let posEnd = link.lastIndexOf("?"); |
| let posStart = link.lastIndexOf("://"); |
| if (posEnd === -1 || posEnd <= posStart) posEnd = link.length; |
| if (posStart === -1) posStart = -3; |
| let name = link.substring(posStart + 3, posEnd); |
| posStart = name.lastIndexOf("/"); |
| name = posStart !== -1 ? name.substring(posStart + 1) : ""; |
| return proxy + "enc2/" + encodeURIComponent(btoa(proxy_enc + link)) + "/" + name; |
| } |
| return proxy + proxy_enc + link; |
| } |
| return link; |
| } |
|
|
| function edit_m3u8(m3u8, url, base, proxy, proxy_enc, enc) { |
| try { |
| return m3u8.split("\n").map(org_line => { |
| let line = org_line.trim(); |
| if (line.charAt(0) === "#") { |
| return org_line.replace(/\bURI="([^"]*)"/g, (str, link) => { |
| link = link.trim(); |
| if (link) { |
| return 'URI="' + proxyLink(fixLink(link, url, base), proxy, proxy_enc, enc) + '"'; |
| } |
| return str; |
| }); |
| } else if(line) { |
| return proxyLink(fixLink(line, url, base), proxy, proxy_enc, enc); |
| } |
| return org_line; |
| }).join("\n"); |
| } catch (err) { |
| return m3u8; |
| } |
| } |
|
|
| function unescapeXml(str) { |
| return str.replace(/<|>|&|'|"/g, function (c) { |
| switch (c) { |
| case "<": return "<"; |
| case ">": return ">"; |
| case "&": return "&"; |
| case "'": return "'"; |
| case """: return '"'; |
| } |
| }); |
| } |
|
|
| function escapeXml(str) { |
| return str.replace(/[<>&'"]/g, function (c) { |
| switch (c) { |
| case "<": return "<"; |
| case ">": return ">"; |
| case "&": return "&"; |
| case "'": return "'"; |
| case '"': return """; |
| } |
| }); |
| } |
|
|
| function edit_mpd(mpd, url, base, proxy, proxy_enc, enc) { |
| try { |
| return mpd.replace(/<BaseURL>([^<]*)/g, (str, link) => { |
| link = link.trim(); |
| if (link) { |
| return "<BaseURL>" + escapeXml(proxyLink(fixLink(unescapeXml(link), url, base), proxy, proxy_enc, (enc === "enc2" ? "enc1" : enc))); |
| } |
| return str; |
| }); |
| } catch (err) { |
| return mpd; |
| } |
| } |
|
|
| async function handleOptions(request, connInfo) { |
| if ( |
| request.headers.get("Origin") !== null && |
| request.headers.get("Access-Control-Request-Method") !== null && |
| request.headers.get("Access-Control-Request-Headers") !== null |
| ) { |
| |
| return new Response(null, { |
| headers: { |
| ...corsOptionsHeaders, |
| "Access-Control-Allow-Headers": request.headers.get( |
| "Access-Control-Request-Headers" |
| ), |
| }, |
| }); |
| } else { |
| |
| return new Response(null, { |
| headers: { |
| Allow: "GET, HEAD, POST, OPTIONS", |
| }, |
| }); |
| } |
| } |
|
|
| try { |
| if (request.method === "OPTIONS") { |
| |
| return await handleOptions(request, connInfo); |
| } else if ( |
| request.method === "GET" || |
| request.method === "HEAD" || |
| request.method === "POST" |
| ) { |
| |
| return await handleRequest(request, connInfo); |
| } else { |
| let error = "Method Not Allowed"; |
| return new Response(error + ": " + request.method, { |
| ...corsHeaders, |
| status: 405, |
| statusText: error, |
| }); |
| } |
| } catch (err) { |
| let error = "Internal Server Error"; |
| return new Response(error + ": " + err + "\n" + (err.stack || ""), { |
| ...corsHeaders, |
| status: 500, |
| statusText: error, |
| }); |
| } |
| } |
|
|
| const port = parseInt(Deno.env.get("PORT") || "7860"); |
| Deno.serve({port: port}, handle); |