recycleactor commited on
Commit
127cc56
·
verified ·
1 Parent(s): cdbc84c

Upload server.js

Browse files
Files changed (1) hide show
  1. server.js +121 -85
server.js CHANGED
@@ -76,7 +76,7 @@ async function fetchRaw(url, headers = {}) {
76
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
77
  'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
78
  'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
79
- 'accept-encoding': 'gzip, deflate, br',
80
  'connection': 'close',
81
  ...headers
82
  },
@@ -88,29 +88,29 @@ async function fetchRaw(url, headers = {}) {
88
  resolve(fetchRaw(loc, headers));
89
  return;
90
  }
91
- let data = [];
92
- res.on('data', (chunk) => data.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
93
- res.on('end', () => {
94
- try {
95
- const buf = Buffer.concat(data);
96
- const enc = String(res.headers['content-encoding'] || '').toLowerCase();
97
- if (enc.includes('br')) {
98
- const zlib = require('zlib');
99
- return resolve(zlib.brotliDecompressSync(buf).toString('utf8'));
100
- }
101
- if (enc.includes('gzip')) {
102
- const zlib = require('zlib');
103
- return resolve(zlib.gunzipSync(buf).toString('utf8'));
104
- }
105
- if (enc.includes('deflate')) {
106
- const zlib = require('zlib');
107
- return resolve(zlib.inflateSync(buf).toString('utf8'));
108
- }
109
- resolve(buf.toString('utf8'));
110
- } catch (e) {
111
- resolve(Buffer.concat(data).toString('utf8'));
112
- }
113
- });
114
  });
115
  req.on('error', reject);
116
  req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
@@ -490,17 +490,17 @@ function handleHls(req, res) {
490
 
491
  const server = http.createServer(async (req, res) => {
492
  const { pathname, query } = parseQuery(req.url);
493
- const startedAt = Date.now();
494
- const shouldLog = pathname === '/health' || pathname.startsWith('/uakinogo/') || pathname.startsWith('/alloha/') || pathname.startsWith('/turbo/');
495
- if (shouldLog) {
496
- try {
497
- const q = (pathname === '/uakinogo/search' && query.q) ? (' q=' + String(query.q).slice(0, 120)) : '';
498
- console.log('[req]', req.method, pathname + q);
499
- } catch (e) {}
500
- res.on('finish', () => {
501
- try { console.log('[res]', req.method, pathname, res.statusCode, (Date.now() - startedAt) + 'ms'); } catch (e) {}
502
- });
503
- }
504
 
505
  if (req.method === 'OPTIONS') {
506
  res.writeHead(204, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': '*' });
@@ -671,58 +671,94 @@ const server = http.createServer(async (req, res) => {
671
  if (pathname === '/uakinogo/search') {
672
  const q = query.q || '';
673
  if (!q) { jsonResp(res, { ok: false, error: 'no query' }, 400); return; }
674
- const searchUrl = 'https://uakinogo.io/index.php?do=search&subaction=search&story=' + encodeURIComponent(q);
675
- const parseSearchHtml = (html) => {
 
 
676
  const results = [];
677
- const addResult = (rawUrl, id, slug) => {
678
- if (!rawUrl || !id) return;
679
- let url = rawUrl;
680
- if (url.startsWith('//')) url = 'https:' + url;
681
- if (url.startsWith('/')) url = 'https://uakinogo.io' + url;
682
- if (!url.startsWith('http')) return;
683
- if (!url.includes('uakinogo.io/')) return;
684
- if (url.includes('do=search') || url.includes('/index.php')) return;
685
- if (!results.find(r => r.id === id)) results.push({ url, id, slug: slug || '' });
686
- };
687
-
688
- const reAbs = /href="(https?:\/\/uakinogo\.io\/[^"]*?\/(\d+)-([^"\/]+)\.html)"/g;
689
- const reRel = /href="(\/[^"]*?\/(\d+)-([^"\/]+)\.html)"/g;
 
690
  let m;
691
- while ((m = reAbs.exec(html)) !== null) addResult(m[1], m[2], m[3]);
692
- while ((m = reRel.exec(html)) !== null) addResult(m[1], m[2], m[3]);
693
- return results;
694
- };
695
-
696
- const looksLikeChallenge = (html) => {
697
- const t = String(html || '');
698
- if (!t) return true;
699
- if (t.includes('cf-challenge') || t.includes('cf-browser-verification')) return true;
700
- if (/Just a moment/i.test(t) && /Cloudflare/i.test(t)) return true;
701
- if (t.includes('data-sitekey') && t.includes('cf-turnstile')) return true;
702
- return false;
703
- };
704
-
705
- fetchRaw(searchUrl, { 'user-agent': 'Mozilla/5.0 Chrome/120', 'referer': 'https://uakinogo.io/' }).then(async html => {
706
- let results = parseSearchHtml(html);
707
- const challenged = looksLikeChallenge(html);
708
- if ((challenged || results.length === 0) && typeof getStreams === 'function' && getStreams.toString) {
709
- try {
710
- const { getBrowser } = require('./alloha');
711
- const browser = await getBrowser();
712
- const page = await browser.newPage();
713
- await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
714
- await page.setExtraHTTPHeaders({ 'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8', 'Referer': 'https://uakinogo.io/' });
715
- await page.goto(searchUrl, { waitUntil: 'networkidle2', timeout: 25000 });
716
- await new Promise(r => setTimeout(r, 1200));
717
- const html2 = await page.content();
718
- await page.close();
719
- results = parseSearchHtml(html2);
720
- } catch (e) {}
721
- }
722
-
723
- try { console.log('[uakinogo/search] results:', results.length, results[0] ? results[0].url : 'none'); } catch (e) {}
724
- jsonResp(res, { ok: true, results: results.slice(0, 10) });
725
- }).catch(e => jsonResp(res, { ok: false, error: e.message }, 500));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
726
  return;
727
  }
728
 
 
76
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
77
  'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
78
  'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
79
+ 'accept-encoding': 'gzip, deflate, br',
80
  'connection': 'close',
81
  ...headers
82
  },
 
88
  resolve(fetchRaw(loc, headers));
89
  return;
90
  }
91
+ let data = [];
92
+ res.on('data', (chunk) => data.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
93
+ res.on('end', () => {
94
+ try {
95
+ const buf = Buffer.concat(data);
96
+ const enc = String(res.headers['content-encoding'] || '').toLowerCase();
97
+ if (enc.includes('br')) {
98
+ const zlib = require('zlib');
99
+ return resolve(zlib.brotliDecompressSync(buf).toString('utf8'));
100
+ }
101
+ if (enc.includes('gzip')) {
102
+ const zlib = require('zlib');
103
+ return resolve(zlib.gunzipSync(buf).toString('utf8'));
104
+ }
105
+ if (enc.includes('deflate')) {
106
+ const zlib = require('zlib');
107
+ return resolve(zlib.inflateSync(buf).toString('utf8'));
108
+ }
109
+ resolve(buf.toString('utf8'));
110
+ } catch (e) {
111
+ resolve(Buffer.concat(data).toString('utf8'));
112
+ }
113
+ });
114
  });
115
  req.on('error', reject);
116
  req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
 
490
 
491
  const server = http.createServer(async (req, res) => {
492
  const { pathname, query } = parseQuery(req.url);
493
+ const startedAt = Date.now();
494
+ const shouldLog = pathname === '/health' || pathname.startsWith('/uakinogo/') || pathname.startsWith('/alloha/') || pathname.startsWith('/turbo/');
495
+ if (shouldLog) {
496
+ try {
497
+ const q = (pathname === '/uakinogo/search' && query.q) ? (' q=' + String(query.q).slice(0, 120)) : '';
498
+ console.log('[req]', req.method, pathname + q);
499
+ } catch (e) {}
500
+ res.on('finish', () => {
501
+ try { console.log('[res]', req.method, pathname, res.statusCode, (Date.now() - startedAt) + 'ms'); } catch (e) {}
502
+ });
503
+ }
504
 
505
  if (req.method === 'OPTIONS') {
506
  res.writeHead(204, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': '*' });
 
671
  if (pathname === '/uakinogo/search') {
672
  const q = query.q || '';
673
  if (!q) { jsonResp(res, { ok: false, error: 'no query' }, 400); return; }
674
+ const qEnc = encodeURIComponent(q);
675
+ const searchUrlSeo = 'https://uakinogo.io/search/' + qEnc;
676
+ const searchUrlLegacy = 'https://uakinogo.io/index.php?do=search&subaction=search&story=' + qEnc;
677
+ const parseSearchHtml = (html) => {
678
  const results = [];
679
+ const addResult = (rawUrl, id, slug) => {
680
+ if (!rawUrl || !id) return;
681
+ let url = rawUrl;
682
+ if (url.startsWith('//')) url = 'https:' + url;
683
+ if (url.startsWith('/')) url = 'https://uakinogo.io' + url;
684
+ if (!url.startsWith('http')) return;
685
+ if (!url.includes('uakinogo.io/')) return;
686
+ if (url.includes('do=search') || url.includes('/index.php')) return;
687
+ if (!results.find(r => r.id === id)) results.push({ url, id, slug: slug || '' });
688
+ };
689
+
690
+ const reHref = /href\s*=\s*["']([^"']*?\/(\d+)-([^"'/]+)\.html(?:#[^"']*)?)["']/g;
691
+ const reEscAbs = /(https?:\\\\\/\\\\\/uakinogo\.io\\\\\/[^"']*?\\\\\/(\d+)-([^"\\\/]+)\.html)/g;
692
+ const reEscRel = /(\\\\\/[^"']*?\\\\\/(\d+)-([^"\\\/]+)\.html)/g;
693
  let m;
694
+ while ((m = reHref.exec(html)) !== null) addResult(m[1], m[2], m[3]);
695
+ while ((m = reEscAbs.exec(html)) !== null) addResult(m[1].replace(/\\\\\//g, '/'), m[2], m[3]);
696
+ while ((m = reEscRel.exec(html)) !== null) addResult(m[1].replace(/\\\\\//g, '/'), m[2], m[3]);
697
+ return results;
698
+ };
699
+
700
+ const looksLikeChallenge = (html) => {
701
+ const t = String(html || '');
702
+ if (!t) return true;
703
+ if (t.includes('cf-challenge') || t.includes('cf-browser-verification')) return true;
704
+ if (/Just a moment/i.test(t) && /Cloudflare/i.test(t)) return true;
705
+ if (t.includes('data-sitekey') && t.includes('cf-turnstile')) return true;
706
+ return false;
707
+ };
708
+
709
+ const fetchAndParse = async (url) => {
710
+ const html = await fetchRaw(url, { 'user-agent': 'Mozilla/5.0 Chrome/120', 'referer': 'https://uakinogo.io/' });
711
+ return { html, results: parseSearchHtml(html), challenged: looksLikeChallenge(html) };
712
+ };
713
+
714
+ fetchAndParse(searchUrlSeo).then(async (first) => {
715
+ let html = first.html;
716
+ let results = first.results;
717
+ let challenged = first.challenged;
718
+
719
+ if (challenged || results.length === 0) {
720
+ try {
721
+ const second = await fetchAndParse(searchUrlLegacy);
722
+ if (second.results.length > results.length) {
723
+ html = second.html;
724
+ results = second.results;
725
+ challenged = challenged || second.challenged;
726
+ }
727
+ } catch (e) {}
728
+ }
729
+
730
+ if ((challenged || results.length === 0) && typeof getStreams === 'function' && getStreams.toString) {
731
+ try {
732
+ const { getBrowser } = require('./alloha');
733
+ const browser = await getBrowser();
734
+ const page = await browser.newPage();
735
+ await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
736
+ await page.setExtraHTTPHeaders({ 'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8', 'Referer': 'https://uakinogo.io/' });
737
+
738
+ await page.goto(searchUrlSeo, { waitUntil: 'networkidle2', timeout: 25000 });
739
+ try { await page.waitForSelector('a[href*=".html"]', { timeout: 8000 }); } catch (e) {}
740
+ await new Promise(r => setTimeout(r, 1200));
741
+ const html2 = await page.content();
742
+ await page.close();
743
+
744
+ const parsed = parseSearchHtml(html2);
745
+ if (parsed.length >= results.length) {
746
+ html = html2;
747
+ results = parsed;
748
+ challenged = looksLikeChallenge(html2);
749
+ }
750
+ } catch (e) {}
751
+ }
752
+
753
+ try { console.log('[uakinogo/search] results:', results.length, results[0] ? results[0].url : 'none'); } catch (e) {}
754
+ if (results.length === 0) {
755
+ try {
756
+ const t = String(html || '');
757
+ console.log('[uakinogo/search] html:', 'len=' + t.length, 'cf=' + (looksLikeChallenge(t) ? '1' : '0'), 'sample=' + t.slice(0, 160).replace(/\s+/g, ' '));
758
+ } catch (e) {}
759
+ }
760
+ jsonResp(res, { ok: true, results: results.slice(0, 10) });
761
+ }).catch(e => jsonResp(res, { ok: false, error: e.message }, 500));
762
  return;
763
  }
764