azot 5.0.0-alpha.20 → 5.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/azot.mjs +1 -1
- package/dist/{context--_LoC7SX.mjs → context-Bkk33DH6.mjs} +1 -1
- package/dist/context.mjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/package.json +1 -1
- package/dist/builtins/instagram/instagram.cjs +0 -121
- package/dist/builtins/ntv/ntv.cjs +0 -104
- package/dist/builtins/rbc/rbc.cjs +0 -37
- package/dist/builtins/rutube/rutube.cjs +0 -92
- package/dist/builtins/soundcloud/soundcloud.cjs +0 -94
- package/dist/builtins/tiktok/tiktok.cjs +0 -76
- package/dist/builtins/virtualroom/virtualroom.cjs +0 -46
- package/dist/builtins/vk/vk.cjs +0 -122
- package/dist/builtins/weibo/weibo.cjs +0 -64
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{closeSync as e,existsSync as t,mkdirSync as n,openSync as r,readSync as i,writeSync as a}from"node:fs";import o,{basename as s,dirname as c,join as l}from"node:path";import"urlpattern-polyfill";import u from"picocolors";import d,{readFile as f,readdir as p,rm as m,stat as h,unlink as g,writeFile as _}from"node:fs/promises";import{configureSync as ee,getConsoleSink as v,getLogger as te,withFilter as ne}from"@logtape/logtape";import{getFileSink as re}from"@logtape/file";import{getPrettyFormatter as ie}from"@logtape/pretty";import y,{EOL as ae,homedir as oe,tmpdir as se}from"node:os";import{arch as ce,platform as le,stdin as b,stdout as ue,version as de}from"node:process";import fe,{EventEmitter as x}from"node:events";import S from"conf";import{setTimeout as C}from"node:timers/promises";import{ALL_FORMATS as pe,DASH as me,DASH_FORMATS as he,HLS as ge,HLS_FORMATS as _e,Input as ve,MP3 as ye,MP4 as be,UrlSource as xe}from"dasha";import{createInterface as Se}from"node:readline/promises";import{Impit as Ce}from"impit";import we from"ky";import{Agent as Te,ProxyAgent as Ee}from"undici";import{parseSetCookie as De}from"cookie";import w from"metavm";import{confirm as Oe,input as ke,number as Ae,password as je,select as Me}from"@inquirer/prompts";var Ne=`azot`,T=`5.0.0-alpha.
|
|
1
|
+
import{closeSync as e,existsSync as t,mkdirSync as n,openSync as r,readSync as i,writeSync as a}from"node:fs";import o,{basename as s,dirname as c,join as l}from"node:path";import"urlpattern-polyfill";import u from"picocolors";import d,{readFile as f,readdir as p,rm as m,stat as h,unlink as g,writeFile as _}from"node:fs/promises";import{configureSync as ee,getConsoleSink as v,getLogger as te,withFilter as ne}from"@logtape/logtape";import{getFileSink as re}from"@logtape/file";import{getPrettyFormatter as ie}from"@logtape/pretty";import y,{EOL as ae,homedir as oe,tmpdir as se}from"node:os";import{arch as ce,platform as le,stdin as b,stdout as ue,version as de}from"node:process";import fe,{EventEmitter as x}from"node:events";import S from"conf";import{setTimeout as C}from"node:timers/promises";import{ALL_FORMATS as pe,DASH as me,DASH_FORMATS as he,HLS as ge,HLS_FORMATS as _e,Input as ve,MP3 as ye,MP4 as be,UrlSource as xe}from"dasha";import{createInterface as Se}from"node:readline/promises";import{Impit as Ce}from"impit";import we from"ky";import{Agent as Te,ProxyAgent as Ee}from"undici";import{parseSetCookie as De}from"cookie";import w from"metavm";import{confirm as Oe,input as ke,number as Ae,password as je,select as Me}from"@inquirer/prompts";var Ne=`azot`,T=`5.0.0-alpha.21`,Pe=`Azot`,E={name:Ne,version:T,description:`A powerful, extensible app for downloading videos`,homepage:`https://azot.mov`,author:`Vitaly Gashkov <vitalygashkov@vk.com>`,bin:{azot:`./dist/azot.mjs`,azt:`./dist/azt.mjs`},files:[`dist`,`types`],type:`module`,main:`./dist/api.mjs`,types:`./types/api.d.ts`,exports:{".":{types:`./types/api.d.ts`,import:`./dist/api.mjs`,"module-sync":`./dist/api.mjs`},"./context":{types:`./types/context.d.ts`,import:`./dist/context.mjs`,"module-sync":`./dist/context.mjs`},"./types/extension":`./types/extension.d.ts`,"./vitest":{import:`./dist/vitest.mjs`,"module-sync":`./dist/vitest.mjs`}},scripts:{start:`tsx --env-file-if-exists .env.local ./src/cli.ts`,dev:`tsx watch --env-file-if-exists .env.local ./src/cli.ts`,"clean:dist":`node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,"bundle:extensions":`node ./scripts/bundle-extensions.mjs`,build:`pnpm run clean:dist && pnpm run bundle:extensions && tsdown`,prepack:`node ./scripts/prepare-publish-package.mjs`,postpack:`node ./scripts/restore-publish-package.mjs`,typecheck:`tsc --noEmit -p tsconfig.json --composite false`,test:`vitest`},dependencies:{"@gitbeaker/rest":`^43.8.0`,"@inquirer/prompts":`^8.3.2`,"@logtape/file":`^2.0.4`,"@logtape/logtape":`^2.0.4`,"@logtape/pretty":`^2.0.4`,"@tanstack/query-core":`^5.90.20`,"@transcrobes/subs-convert":`^5.2.0`,"@tribute-tg/better-auth":`^2.1.10`,"better-auth":`^1.5.5`,conf:`^15.1.0`,cookie:`^1.1.1`,"cross-spawn":`^7.0.6`,dasha:`^4.2.0`,impit:`^0.13.0`,ky:`^1.14.3`,mediabunny:`^1.44.2`,metavm:`^1.4.5`,molnia:`workspace:*`,nanospinner:`^1.2.2`,okova:`^0.11.0`,open:`^11.0.0`,"p-queue":`^9.1.0`,picocolors:`^1.1.1`,"posthog-js":`^1.360.2`,semver:`^7.7.4`,shifro:`^1.1.4`,"telegram-better-auth":`^0.0.8`,undici:`^7.24.4`,"urlpattern-polyfill":`^10.1.0`,yargs:`^18.0.0`,yauzl:`^3.2.1`,zod:`^4.3.6`},devDependencies:{"@azot/shared":`workspace:*`,"@types/node":`^25.5.0`,"@types/semver":`^7.7.1`,"@types/yargs":`^17.0.35`,execa:`^9.6.1`,"javascript-obfuscator":`^4.1.1`,tsdown:`^0.22.0`,tsx:`^4.21.0`,typescript:`^6.0.3`},peerDependencies:{vitest:`^4.1.0`},engines:{node:`>=24.10`,pnpm:`>=10`},packageManager:`pnpm@11.0.0`,productName:Pe};`pkg`in process&&process.pkg,process.versions.electron,process.env.AZOT_E2E;const Fe=`v${T} ${le}-${ce} node-${de}`,Ie=`v${T}`,Le=Ne?.split(`/`)[0]?.split(`-`)[0]?.replace(`@`,``),D=Pe,Re={darwin:`macOS`,win32:`Windows`,linux:`Linux`}[process.platform],ze=`https://azot.mov/api`,Be=`LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFY243SFdZaXVyMWR3UU5pSmhFSGZHczZFM25rOAo4TXhOZVo5Ly85UWpaUStVNm5Ud0twMGJNTXJydGxHVVZ5ZWFGQS9lREtkL29QZHg0NXpmU0Rkc1lRPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg`,O=e=>{let r=typeof e==`string`?e:e[Re];return t(r)||n(r,{recursive:!0}),r},k=oe(),Ve=se(),A=O({Windows:process.env.APPDATA||l(k,`AppData`,`Roaming`),macOS:l(k,`Library`,`Application Support`),Linux:process.env.XDG_DATA_HOME||l(k,`.local`,`share`)}),j=O({Windows:process.env.APPDATA||l(k,`AppData`,`Roaming`),macOS:l(k,`Library`,`Application Support`),Linux:process.env.XDG_CONFIG_HOME||l(k,`.config`)});O({Windows:process.env.LOCALAPPDATA||l(k,`AppData`,`Local`),macOS:l(k,`Library`,`Caches`),Linux:process.env.XDG_CACHE_HOME||l(k,`.cache`)});const He=O({Windows:l(k,`Downloads`),macOS:l(k,`Downloads`),Linux:process.env.XDG_DOWNLOAD_DIR||l(k,`Downloads`)}),Ue=O({Windows:l(A,D),macOS:l(A,D),Linux:l(A,D.toLowerCase())}),We=O({Windows:l(j,D),macOS:l(j,D),Linux:l(j,D.toLowerCase())}),Ge=O({Windows:l(j,D,`logs`),macOS:l(k,`Library`,`Logs`,D),Linux:l(j,D.toLowerCase(),`logs`)}),Ke=l(Ve,D.toLowerCase()),M=O(l(Ue,`extensions`)),qe=O(l(M,`installed`)),Je=O(l(M,`work`)),Ye=l(M,`index.json`),Xe=l(We,`settings.json`),Ze=process.argv.includes(`-d`)||process.argv.includes(`--debug`)||process.env.NODE_ENV_ELECTRON_VITE===`development`||!!process.env.ELECTRON_CLI_ARGS;ee({sinks:{console:ne(v({formatter:ie({timestamp:`time`,messageColor:null,messageStyle:null,levelStyle:null,icons:!1,colors:!0,level:`FULL`,categoryWidth:0,categoryStyle:null,categoryTruncate:`end`,wordWrap:!0})}),Ze?`debug`:`info`),file:re(l(Ge,`Azot_${new Date().toISOString().split(`.`)[0].replace(`T`,`_`).replaceAll(`-`,``).replaceAll(`:`,``)}.log`),{flushInterval:0})},loggers:[{category:[],lowestLevel:`trace`,sinks:[`console`,`file`]},{category:[`logtape`,`meta`],lowestLevel:`error`,sinks:[`console`]}]});const N=te([]),Qe=async e=>{let t=await p(e).then(e=>e.filter(e=>e.endsWith(`.log`))),n=t=>l(e,t),r=t.map(e=>h(n(e)).catch(()=>null).then(t=>({stats:t,path:n(e)}))),i=(await Promise.all(r)).filter(Boolean);i.sort((e,t)=>t.stats.mtime.getTime()-e.stats.mtime.getTime());let a=i.slice(50).map(e=>g(e.path));await Promise.allSettled(a).catch(N.error)},$e=e=>{if(typeof e==`string`)return{message:e};if(e instanceof Error)return{message:e.message};if(e&&typeof e==`object`){let t=`message`in e?String(e.message):void 0,n=`code`in e?String(e.code):void 0;if(t||n)return{message:t||n||`Unknown error`,code:n}}return{message:`Unknown error`}},et=new fe,P=e=>new(`default`in S?S.default:S)(e);var F=class{#e;constructor(e){this.#e=P({cwd:c(e),configName:s(e,`.json`)})}get length(){return Object.keys(this.#e.store).length}clear(){this.#e.clear()}getItem(e){return this.#e.get(e)??null}key(e){return Object.keys(this.#e.store).at(e)??null}removeItem(e){this.#e.delete(e)}setItem(e,t){this.#e.set(e,t)}};const I=e=>{let t=[`}`,`{`,`%`,`>`,`<`,`^`,`;`,"`",`$`,`"`,`@`,`=`],n=e;for(let e in t)n=n.replaceAll(`/`,`_`).replaceAll(t[e],``);return n},L=(e,t,n)=>{let r={},i={};for(let a of n)for(let n of t){let t=new URLPattern(n,a).exec(e);t&&(Object.assign(r,t.pathname.groups),Object.assign(i,t.search.groups))}return{pathname:r,search:i}},R=(e=new Map)=>{let t=(t,n)=>{for(let r of e.keys())for(let i of e.get(r)||[]){let e=n===void 0||isNaN(n),a=t===void 0||isNaN(t),o=!1;if(o=a?r===n:(e?isNaN(r):r===n)&&i===t,o)return!0}return!1},n=(t,n)=>{let r=n||NaN,i=t||NaN;e.has(r)?e.get(r)?.add(i):e.set(r,new Set([i]))},r=()=>Array.from(e.values()).flatMap(e=>Array.from(e)),i=e.size,a=r();return{items:e,has:t,set:n,getMin:()=>Math.min(...a),getMax:()=>Math.max(...a),seasonsCount:i,episodesCount:a.length}},tt=new Intl.DateTimeFormat(`en-US`,{year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1}),nt=new Intl.DateTimeFormat(`en-US`,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1}),rt=()=>{let e=new Date;return tt.format(e).replaceAll(`/`,`-`).replace(`, `,`_`).replaceAll(`:`,`-`)},it=()=>{let e=new Date,t=e.getMilliseconds().toString().padStart(3,`0`);return`${nt.format(e)}.${t}`},at=e=>`${u.gray(it().slice(2))} ${e.padEnd(18,` `)}`,z=new class t extends x{static requestEventName=`form`;static responseEventName=`form:response`;title;#e=Promise.resolve();constructor(t={}){super(),this.title=t.title,this.listen(async t=>{let{title:n,description:i,fields:a,...o}=t,s={},c=Object.entries(a||o);if(!b.isTTY||process.platform===`win32`){let t=0,a=1,o=!1;if(process.platform===`win32`)try{t=r(`\\\\.\\CONIN$`,`r`),a=r(`\\\\.\\CONOUT$`,`w`),o=!0}catch{}try{for(let[e,{label:r,type:o}]of c){let c=o===`confirm`;s[e]=ct([n,i,r].filter(Boolean).join(`. `)+(c?` (y/n)`:``)+`: `,void 0,{inputFd:t,outputFd:a})??``}return s}finally{o&&(e(t),e(a))}}b.setEncoding&&b.setEncoding(`utf8`),b.isTTY&&b.setRawMode&&b.setRawMode(!1),b.resume();let l=Se({input:b,output:ue,terminal:!0});try{for(let[e,{label:t,type:r}]of c){let a=r===`confirm`,o=[n,i,t].filter(Boolean).join(`. `)+(a?` (y/n)`:``)+`: `;s[e]=await Promise.race([l.question(o),C(st,``)])}return s}finally{l.close()}})}async ask(e){let n=()=>new Promise(n=>{this.once(t.responseEventName,e=>{n(e)}),this.emit(t.requestEventName,e)}),r=this.#e.then(n,n);return this.#e=r.then(()=>void 0,()=>void 0),r}listen(e){this.addListener(t.requestEventName,async n=>{let r=await e(n);this.emit(t.responseEventName,r)})}},ot=async(e,t)=>{let n=t?.fields??{answer:{label:e}};return await z.ask({title:t?.title,description:e,fields:n})},st=12e4,ct=(e,t,n)=>{let r=n?.inputFd??0;a(n?.outputFd??1,e||``);let o=Buffer.alloc(1),s=``;for(;;){try{i(r,o,0,1,null)}catch(e){if(e.code===`EOF`)break;throw e}let e=o.toString(`utf-8`);if(e===`
|
|
2
2
|
`||e===`\r`){if(e===`\r`)try{i(r,o,0,1,null),o.toString(`utf-8`)}catch(e){if(e.code===`EOF`)break;throw e}break}s+=e}return s.trim()||t},B=e=>{let t=[];for(let n of e)try{let e=De(n),r={...e,expires:e.expires instanceof Date?e.expires.getTime():e.expires,sameSite:typeof e.sameSite==`boolean`?`strict`:e.sameSite};t.push(r)}catch(e){N.debug(e instanceof Error?e.stack??e.message:String(e))}return t},lt=async e=>{let t=await f(e,`utf8`).catch(()=>``);if(!t)return[];let n=t.split(ae).flatMap(e=>e.split(`
|
|
3
3
|
`)).filter(e=>!!e.trim()&&!e.startsWith(`# `)).map(e=>e.split(` `)),r=[];for(let e of n){let[t,n,i,a,o,s,c]=e;r.push({name:s,value:c,expires:Number(o),maxAge:void 0,domain:t.replace(`#HttpOnly_`,``),path:i,secure:a===`TRUE`,httpOnly:void 0,sameSite:void 0})}return r},ut=(e,t)=>e.name===t.name&&e.domain===t.domain&&e.path===t.path&&e.partitioned===t.partitioned,V=(e,t)=>{let n=[...e];for(let e of t){let t=n.findIndex(t=>ut(t,e));t>=0?n[t]=e:n.push(e)}return n},dt=(e,t)=>{if(typeof e!=`string`)return e;if(t===void 0)throw TypeError(`CookieStore.set(name, value) requires a value argument`);return{name:e,value:t}};var H=class{#e={};#t;#n;#r=!1;static parse(e){return B(e)}constructor({storagePath:e}={}){this.#n=e,this.#t=[]}async import(e,{removeSource:t=!0}={}){if(await this.#i(),!(await h(e).catch(()=>null))?.isFile())return 0;N.debug(`Importing cookies from ${e}`);let n=await lt(e);this.#t=V(this.#t,n);try{await this.#a(),t&&await m(e,{force:!0})}catch(e){throw e}return n.length}async#i(){if(!(!this.#n||this.#r)){if((await h(this.#n).catch(()=>null))?.isFile()){let e=await f(this.#n,`utf8`);this.#e=e?JSON.parse(e):{},this.#t=`cookies`in this.#e?this.#e.cookies:[]}this.#r=!0}}async#a(){if(!this.#n)return;let e=JSON.stringify({...this.#e,cookies:this.#t},null,2);await _(this.#n,e,`utf8`)}async get(e){await this.#i();let t=typeof e==`string`?e:e.name;return this.#t.find(e=>e.name===t)??null}async getAll(e){if(await this.#i(),!e)return this.#t;let t=typeof e==`string`?e:e.name;return this.#t.filter(e=>e.name===t)??null}async set(e,t){await this.#i();let n=dt(e,t);this.#t=V(this.#t,[n]),await this.#a()}async delete(e){if(await this.#i(),!e)this.#t=[];else{let t=typeof e==`string`?e:e.name;this.#t=this.#t.filter(e=>e.name!==t)}await this.#a()}toString(){return this.#t.map(e=>`${e.name}=${e.value}`).join(`; `)}};const U=we.default??we,ft=e=>e?e instanceof Headers?e.has(`User-Agent`):typeof e==`object`&&e?`User-Agent`in e||`user-agent`in e:!1:!1,W=e=>e instanceof URL?e:e instanceof Request?new URL(e.url):new URL(e);var G=class{cookieStore;headers;#e;#t;constructor(e={}){this.headers=new Headers,this.configure(e)}configure({maxRetries:e=3,proxyUrl:t,allowH2:n=!0,cookieStore:r,fetch:i}={}){this.cookieStore=r??this.cookieStore??new H;let a=t?new Ee({uri:t,allowH2:n}):new Te({allowH2:n}),o={retry:e};this.#e=U.create({dispatcher:a,proxy:t,fetch:i,...o});let s=new Ce({browser:`chrome142`,proxyUrl:t,ignoreTlsErrors:!0,followRedirects:!1}),c=async(e,t)=>{let n=await s.fetch.bind(s)(e,t);return new Response(n.body,n)};this.#t=U.create({fetch:this.#r.bind(this,i??c),...o})}async fetch(e,t={}){let n=await this.#o(e,t)??{},r=e instanceof Request?e:new Request(e,n),i=await this.#n(e,n.headers??r.headers),a=(ft(t?.headers)?this.#e:this.#t)[n.method?.toLowerCase()??r?.method?.toLowerCase()??`get`],o=n.body,s=await a(r.url,{...n,body:o,headers:i}),c=s.headers.getSetCookie();return c&&await this.setCookies(c),s}async#n(e,t){let n=this.appendHeaders(t),r=await this.cookieStore.getAll(),i=r.filter(t=>!t.domain||W(e).hostname.includes(t.domain));for(let e of r)i.find(t=>t.name===e.name)||e.domain||i.push(e);let a=i.map(e=>`${e.name}=${e.value}`).join(`; `);return a?(n.has(`cookie`)?n.get(`cookie`)||n.delete(`cookie`):n.set(`cookie`,a),n):(n.get(`cookie`)||n.delete(`cookie`),n)}async setCookies(e){let t=[];if(typeof e==`string`){let[n]=B([e]);n&&t.push(n)}else if(Array.isArray(e)&&typeof e.at(0)==`string`){let n=B(e);t.push(...n)}else Array.isArray(e)&&typeof e[0]!=`string`&&t.push(...e);if(!(!t||!t?.length))for(let e of t)await this.cookieStore.set(e)}appendHeaders(e){let t=new Headers(this.headers),n=e instanceof Headers?e.entries():Object.entries(e??{});for(let[e,r]of n)t.set(e,r);return t}setHeader(e,t){this.headers.set(e,t)}removeHeader(e){this.headers.delete(e)}async#r(e,t,n={}){let r=0,i=t instanceof Request?new URL(t.url):t,a=await this.#o(t,n)??{};for(a.redirect=`manual`;;){let t=await e(i,a),n=t.headers.getSetCookie();if(n.length&&await this.setCookies(n),!this.#a(t.status))return t;let o=t.headers.get(`location`);if(!o)return t;if(r>=20)throw Error(`Maximum redirect limit (20) exceeded`);r+=1,i=new URL(o,W(i)),a=this.#i(a,t.status)??{},a.headers=await this.#n(i,a.headers)}}#i(e={},t){let n=e.method?.toUpperCase()??`GET`;if(t===303||(t===301||t===302)&&n===`POST`){let t=new Headers(e.headers);return t.delete(`content-length`),t.delete(`content-type`),{...e,method:`GET`,body:void 0,headers:t,redirect:`manual`}}return{...e,redirect:`manual`}}#a(e){return[301,302,303,307,308].includes(e)}async#o(e,t={}){if(!(e instanceof Request))return{...t};let n=new Headers(e.headers);for(let[e,r]of new Headers(t.headers).entries())n.set(e,r);let r=(t.method??e.method).toUpperCase(),i={...t,method:r,headers:n};return t.body!==void 0||r===`GET`||r===`HEAD`?(i.body=t.body,i):(i.body=await e.clone().arrayBuffer(),i)}};const pt=new G,{COMMON_CONTEXT:mt}=w,ht=async e=>{let t=async e=>{let n=await d.readdir(e,{withFileTypes:!0});return(await Promise.all(n.map(async n=>{let r=n.name.endsWith(`.js`),i=n.name.endsWith(`.test.js`);return n.isDirectory()&&n.name!==`node_modules`?t(o.join(e,n.name)):n.isFile()&&r&&!i?[o.join(e,n.name)]:[]}))).flat()};return t(e)},gt=async(e,t={})=>{let n={};if(t.dirname){let e=await ht(t.dirname);for(let r of e)n[r.replace(t.dirname,`.`)]=!0}let r={context:w.createContext({...mt,...t.context}),dirname:t.dirname,access:{"node:crypto":!0,crypto:!0,azot:!0,...n,...t.access},type:t.format===`esm`?w.MODULE_TYPE.ECMA:w.MODULE_TYPE.COMMONJS};return await d.stat(e).then(()=>!0).catch(()=>!1)?await d.access(e).then(()=>!0).catch(()=>!1)?await w.readScript(e,r):w.createScript(t.name??`default`,e,r):_t(e,t.name??`default`,r)},_t=(e,t=`Eval`,n)=>{try{return w.createScript(t,e,n)}catch(t){return console.debug(t),console.debug(e),console.error(`Syntax Error: ${t.message}`),null}},vt=(e,t=1)=>typeof e==`string`?Array.from({length:t},()=>e[Math.floor(Math.random()*e.length)]):!Array.isArray(e)||e.length===0?[]:Array.from({length:t},()=>e[Math.floor(Math.random()*e.length)]),yt=new class e extends x{static requestEventName=`feedback`;static responseEventName=`feedback:response`;#e=Promise.resolve();async ask(t){let n=()=>new Promise(n=>{this.once(e.responseEventName,e=>{n(e)}),this.emit(e.requestEventName,t)}),r=this.#e.then(n,n);return this.#e=r.then(()=>void 0,()=>void 0),r}listen(t){this.addListener(e.requestEventName,async n=>{let r=await t(n);this.emit(e.responseEventName,r)})}},K=e=>{if(!e||typeof e!=`object`)return!1;let t=`name`in e?String(e.name):``;return t===`ExitPromptError`||t===`AbortPromptError`},bt=e=>e&&e[0].toUpperCase()+e.slice(1),q=(e,t=!1)=>{if(typeof e==`boolean`)return e;if(typeof e!=`string`)return t;let n=e.trim().toLowerCase();return[`1`,`true`,`yes`,`y`,`on`].includes(n)?!0:[`0`,`false`,`no`,`n`,`off`].includes(n)?!1:t},J=(e,t=0)=>{if(typeof e==`number`&&Number.isFinite(e))return e;if(typeof e!=`string`)return t;let n=Number(e);return Number.isFinite(n)?n:t},xt=e=>{switch(e.type){case`checkbox`:return q(e.defaultValue,!1);case`number`:return J(e.defaultValue,0);default:return e.defaultValue??``}},St=(e,t)=>{switch(e.type){case`checkbox`:return q(t,q(e.defaultValue,!1));case`number`:return J(t,J(e.defaultValue,0));default:return typeof t==`string`?t:t==null?e.defaultValue??``:String(t)}},Ct=e=>{let t=Object.entries(e).map(([e,t])=>[e,xt(t)]);return Object.fromEntries(t)},Y=(e,t)=>{let n=Object.entries(e).map(([e,n])=>[e,St(n,t[e])]);return Object.fromEntries(n)},wt=e=>!!e&&typeof e==`object`&&`fields`in e,Tt=e=>{switch(e){case`password`:case`number`:case`checkbox`:return e;default:return`text`}},Et=e=>{let t=Object.fromEntries(Object.entries(e.fields).map(([e,t])=>[e,{type:Tt(t.type),title:t.label||e,description:t.description,placeholder:t.placeholder,defaultValue:t.defaultValue??t.value,required:t.required,autoFocus:t.autoFocus}]));return{message:e.description??``,options:{title:e.title,form:t,primaryAction:e.actions?.primaryAction,secondaryAction:e.actions?.secondaryAction}}},X=async e=>{e?.onAction&&await e.onAction()},Z=async(e,t)=>{if(!t.length)return`dismiss`;try{return await Me({message:e,loop:!1,choices:t.map(e=>({name:e.action.title,value:e.kind}))})}catch(e){if(K(e))return`dismiss`;throw e}},Dt=new Set([`http:`,`https:`,`mailto:`]),Ot=e=>{try{return Dt.has(new URL(e).protocol)}catch{return!1}},kt=async(e,t)=>{if(!Ot(e)){N.warn(`Blocked unsupported external URL protocol: ${e}`);return}if(t){let{default:t}=await import(`open`);await t(e);return}let{shell:n}=await import(`electron`);await n.openExternal(e)},At=({isCLI:e,resolveTitle:t,requestPrompt:n})=>{let r=(t,n,r)=>{let i=typeof t==`string`?t:t?.toString();return i?.trim()&&kt(i,e).catch(e=>{N.error(`Failed to open URL: ${i}`),N.debug(e instanceof Error?e.message:String(e))}),null},i=async(n,r={})=>{let i=t(r.title)??`Azot`,a=[r.primaryAction?{kind:`primary`,action:r.primaryAction}:null,r.secondaryAction?{kind:`secondary`,action:r.secondaryAction}:null].filter(Boolean);if(e){if(!a.length)return N.info(n);let e=await Z(n,a);e===`primary`&&await X(r.primaryAction),e===`secondary`&&await X(r.secondaryAction);return}let o=(await yt.ask({variant:`notify`,title:i,message:n,style:r.style,primaryAction:r.primaryAction?{title:r.primaryAction.title,style:r.primaryAction.style}:void 0,secondaryAction:r.secondaryAction?{title:r.secondaryAction.title,style:r.secondaryAction.style}:void 0})).action??`dismiss`;o===`primary`&&await X(r.primaryAction),o===`secondary`&&await X(r.secondaryAction)},a=async(n,r={})=>{let i=t(r.title)??`Azot`,a=!!r.primaryAction||!!r.secondaryAction,o=r.primaryAction??{title:`OK`},s=r.secondaryAction??{title:`Cancel`,style:`cancel`};if(e){if(a){let e=await Z(n,[{kind:`primary`,action:o},{kind:`secondary`,action:s}]);return e===`primary`?(await X(o),!0):(e===`secondary`&&await X(s),!1)}try{let e=await Oe({message:n,default:!0});return e?await X(r.primaryAction):await X(r.secondaryAction),e}catch(e){if(K(e))return!1;throw e}}let c=await yt.ask({variant:`confirm`,title:i,message:n,style:r.style,primaryAction:{title:o.title,style:o.style},secondaryAction:{title:s.title,style:s.style}}),l=c.action===`primary`;return l?await X(o):c.action===`secondary`&&await X(s),l},o=async(r,i)=>{let a=Ct(i.form),o=Object.entries(i.form),s=!!i.primaryAction||!!i.secondaryAction,c=i.primaryAction??{title:`Submit`},l=i.secondaryAction??{title:`Cancel`,style:`cancel`};if(e){let e={};try{for(let[t,n]of o){let r=[n.title||t,n.description].filter(Boolean).join(` - `);if(n.type===`checkbox`){e[t]=await Oe({message:r,default:q(n.defaultValue,!1)});continue}if(n.type===`number`){let i=J(n.defaultValue,NaN);e[t]=await Ae({message:r,default:Number.isFinite(i)?i:void 0,validate:e=>(e===void 0||Number.isNaN(e))&&n.required?`This field is required`:!0});continue}if(n.type===`password`){e[t]=await je({message:r,validate:n.required?e=>String(e??``).trim()?!0:`This field is required`:void 0});continue}e[t]=await ke({message:r,default:n.defaultValue,validate:n.required?e=>String(e??``).trim()?!0:`This field is required`:void 0})}}catch(e){if(K(e))return a;throw e}if(!s)return Y(i.form,e);let t=await Z(r,[{kind:`primary`,action:c},{kind:`secondary`,action:l}]);return t===`primary`?(await X(c),Y(i.form,e)):(t===`secondary`&&await X(l),a)}let u=Object.fromEntries(o.map(([e,t])=>[e,{type:t.type,label:t.title||e,description:t.description,placeholder:t.placeholder,defaultValue:t.defaultValue,value:t.defaultValue,required:t.required,autoFocus:t.autoFocus}])),d=await n({title:t(i.title),description:r,fields:u,actions:s?{primaryAction:{title:c.title,style:c.style},secondaryAction:{title:l.title,style:l.style}}:void 0}),f=d.__action??`primary`,p={...d};return delete p.__action,f===`primary`?(await X(i.primaryAction),Y(i.form,p)):(f===`secondary`&&await X(i.secondaryAction),a)};return{notify:i,confirm:a,askPrompt:async(e,t)=>{if(wt(e)){let t=Et(e);return o(t.message,t.options)}if(!t)throw TypeError(`prompt(message, options) requires a form definition`);return o(e,t)},openWindow:r}},Q=(e,t,n)=>{Object.getOwnPropertyDescriptor(e,t)||Object.defineProperty(e,t,n)},jt=()=>{Q(Uint8Array.prototype,`toBase64`,{value:function(){return Buffer.from(this).toString(`base64`)},writable:!0,configurable:!0}),Q(Uint8Array.prototype,`toHex`,{value:function(){return Buffer.from(this).toString(`hex`)},writable:!0,configurable:!0}),Q(Uint8Array,`fromBase64`,{value:function(e){return new Uint8Array(Buffer.from(e,`base64`))},writable:!0,configurable:!0}),Q(Uint8Array,`fromHex`,{value:function(e){return new Uint8Array(Buffer.from(e,`hex`))},writable:!0,configurable:!0})},Mt=new Map([[24,[`Sequoia`,`15`]],[23,[`Sonoma`,`14`]],[22,[`Ventura`,`13`]],[21,[`Monterey`,`12`]],[20,[`Big Sur`,`11`]],[19,[`Catalina`,`10.15`]],[18,[`Mojave`,`10.14`]],[17,[`High Sierra`,`10.13`]],[16,[`Sierra`,`10.12`]],[15,[`El Capitan`,`10.11`]],[14,[`Yosemite`,`10.10`]],[13,[`Mavericks`,`10.9`]],[12,[`Mountain Lion`,`10.8`]],[11,[`Lion`,`10.7`]],[10,[`Snow Leopard`,`10.6`]],[9,[`Leopard`,`10.5`]],[8,[`Tiger`,`10.4`]],[7,[`Panther`,`10.3`]],[6,[`Jaguar`,`10.2`]],[5,[`Puma`,`10.1`]]]),$=()=>{switch(y.type()){case`Darwin`:return`macOS`;case`Windows_NT`:return`Windows`;default:return`Linux`}},Nt=()=>{let e=Number(y.release().split(`.`)[0]),[t,n]=Mt.get(e)||[`Unknown`,``];return{name:t,version:n}},Pt=()=>{switch($()){case`macOS`:return Nt().version;case`Windows`:return y.release();case`Linux`:return y.release()}},Ft=e=>{let t=process.version.replace(/^v/,``),n=[{brand:`Azot`,version:e.split(`.`).slice(0,2).join(`.`)},{brand:`Node.js`,version:t.split(`.`).slice(0,1).join(`.`)}];return{mobile:!1,platform:$(),brands:n,getHighEntropyValues:async r=>{let i={mobile:!1,platform:$(),brands:n};return r.includes(`architecture`)&&(i.architecture=y.arch()),r.includes(`platform`)&&(i.platform=$()),r.includes(`platformVersion`)&&(i.platformVersion=Pt()),r.includes(`fullVersionList`)&&(i.fullVersionList=[{brand:`Azot`,version:e},{brand:`Node.js`,version:t}]),i}}},It=({name:e=`extension`,dir:t=process.cwd(),title:n}={})=>{jt();let r=O(l(t,e)),i=new F(l(r,`storage.json`)),a=new H({storagePath:l(r,`cookies.json`)}),o=new G({cookieStore:a}),s=(e,t,n)=>e.split(t)[1]?.split(n)[0]?.trim(),c={sanitizeString:I,execUrlPatterns:L,extendEpisodes:R,between:s,getRandomElements:vt},u=n?bt(n):void 0,{notify:d,confirm:f,askPrompt:p,openWindow:m}=At({isCLI:!0,resolveTitle:e=>e||u,requestPrompt:async e=>(e.title||=u,await z.ask(e))});class h extends ve{constructor(e){super({...e,formats:e.formats??pe})}}class g extends xe{constructor(e,t={}){super(e,{fetchFn:o.fetch.bind(o),...t,requestInit:{...t.requestInit,headers:{...o.headers,...t.requestInit?.headers}}})}}let _={defineExtension:e=>e,version:E.version,sleep:C,sanitizeString:I,execUrlPatterns:L,extendEpisodes:R,between:s,getRandomElements:vt,utils:c,notify:d,confirm:f,prompt:p,Input:h,UrlSource:g,ALL_FORMATS:pe,DASH:me,DASH_FORMATS:he,HLS:ge,HLS_FORMATS:_e,MP4:be,MP3:ye,input:ot,ask:p};class ee{get cookie(){return a.toString()}}let v={fetch:o.fetch.bind(o),Response,Request,Headers,AbortController,AbortSignal,URL,URLSearchParams,URLPattern,open:m,Blob,structuredClone,btoa,atob,TextEncoder,TextDecoder,Uint8Array,crypto,console:{log:console.log,info:N.info.bind(N),warn:N.warn.bind(N),error:(...e)=>{let t=String(e[0]??`Unknown error`);et.emit(`error`,{message:t}),N.error(t)},trace:N.trace.bind(N),debug:N.debug.bind(N)},Event,EventTarget,localStorage:i,cookieStore:a,document:new ee,eval:e=>_t(e)?.exports,navigator:{appName:`Azot`,appVersion:E.version,platform:process.platform,userAgent:`Azot/${E.version}`,userAgentData:Ft(E.version)}};return{http:o,question:z,common:c,Streamyx:_,Azot:_,window:v,...v}};export{Ie as A,Xe as C,ze as D,D as E,Be as O,qe as S,Le as T,Ke as _,z as a,M as b,F as c,$e as d,Qe as f,Ge as g,Ue as h,pt as i,E as j,Fe as k,P as l,We as m,gt as n,rt as o,N as p,G as r,at as s,It as t,et as u,He as v,O as w,Ye as x,Je as y};
|
package/dist/context.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./context
|
|
1
|
+
import{t as e}from"./context-Bkk33DH6.mjs";export{e as createContext};
|
package/dist/vitest.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./context
|
|
1
|
+
import{t as e}from"./context-Bkk33DH6.mjs";import"./context.mjs";import{beforeEach as t,vi as n}from"vitest";const r=e();Object.entries(r).forEach(([e,t])=>{n.stubGlobal(e,t)}),n.mock(`azot`,async()=>r.Azot),t(async()=>{r.localStorage.clear();let e=await r.cookieStore.getAll();for(let t of e)await r.cookieStore.delete(t.name);n.clearAllMocks()});export{};
|
package/package.json
CHANGED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
//#region src/extensions-api/main.ts
|
|
2
|
-
const runtimeContext = Azot ?? Streamyx ?? {};
|
|
3
|
-
if (runtimeContext) {
|
|
4
|
-
if (!runtimeContext.defineExtension) runtimeContext.defineExtension = (extension) => extension;
|
|
5
|
-
}
|
|
6
|
-
const defineExtension = runtimeContext.defineExtension;
|
|
7
|
-
runtimeContext.version;
|
|
8
|
-
runtimeContext.sleep;
|
|
9
|
-
runtimeContext.input;
|
|
10
|
-
runtimeContext.prompt;
|
|
11
|
-
runtimeContext.notify;
|
|
12
|
-
runtimeContext.confirm;
|
|
13
|
-
runtimeContext.ask;
|
|
14
|
-
runtimeContext.utils;
|
|
15
|
-
const Input = runtimeContext.Input;
|
|
16
|
-
const UrlSource = runtimeContext.UrlSource;
|
|
17
|
-
runtimeContext.ALL_FORMATS;
|
|
18
|
-
runtimeContext.DASH;
|
|
19
|
-
runtimeContext.DASH_FORMATS;
|
|
20
|
-
runtimeContext.HLS;
|
|
21
|
-
runtimeContext.HLS_FORMATS;
|
|
22
|
-
runtimeContext.MP4;
|
|
23
|
-
runtimeContext.MP3;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/builtins/instagram/instagram.ts
|
|
26
|
-
const INSTAGRAM_HEADERS = { Referer: "https://www.instagram.com/" };
|
|
27
|
-
const INSTAGRAM_API_HEADERS = {
|
|
28
|
-
"X-IG-App-ID": "936619743392459",
|
|
29
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"
|
|
30
|
-
};
|
|
31
|
-
const getPostViaGraphQL = async (shortcode) => {
|
|
32
|
-
const params = new URLSearchParams({
|
|
33
|
-
doc_id: "8845758582119845",
|
|
34
|
-
variables: JSON.stringify({
|
|
35
|
-
shortcode,
|
|
36
|
-
child_comment_count: 3,
|
|
37
|
-
fetch_comment_count: 40,
|
|
38
|
-
parent_comment_count: 24,
|
|
39
|
-
has_threaded_comments: true
|
|
40
|
-
})
|
|
41
|
-
});
|
|
42
|
-
try {
|
|
43
|
-
const response = await fetch(`https://www.instagram.com/graphql/query/?${params.toString()}`, { headers: INSTAGRAM_API_HEADERS });
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
console.error(`GraphQL request failed with status: ${response.status}`);
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
return (await response.json()).data?.xdt_shortcode_media ?? null;
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.error("Error during GraphQL fetch:", error);
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
const getPostViaEmbedPage = async (shortcode) => {
|
|
55
|
-
try {
|
|
56
|
-
const response = await fetch(`https://www.instagram.com/p/${shortcode}/embed/captioned/`, { headers: { "User-Agent": INSTAGRAM_API_HEADERS["User-Agent"] } });
|
|
57
|
-
if (!response.ok) return null;
|
|
58
|
-
const dataMatch = (await response.text()).match(/window\.__additionalDataLoaded\('extra',\s*({.+?})\s*\);/);
|
|
59
|
-
if (!dataMatch?.[1]) return null;
|
|
60
|
-
return JSON.parse(dataMatch[1]).shortcode_media ?? null;
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.error("Error during embed page fetch:", error);
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
const processPostData = (postData) => {
|
|
67
|
-
const title = postData.edge_media_to_caption?.edges?.[0]?.node?.text || "Instagram Post";
|
|
68
|
-
const entries = [];
|
|
69
|
-
const pushEntry = (item) => {
|
|
70
|
-
if (!item) return;
|
|
71
|
-
const mediaUrl = item.is_video && item.video_url ? item.video_url : item.display_url;
|
|
72
|
-
if (!mediaUrl) return;
|
|
73
|
-
entries.push({
|
|
74
|
-
title,
|
|
75
|
-
input: new Input({ source: new UrlSource(mediaUrl, { requestInit: { headers: INSTAGRAM_HEADERS } }) })
|
|
76
|
-
});
|
|
77
|
-
};
|
|
78
|
-
const carouselItems = postData.edge_sidecar_to_children?.edges;
|
|
79
|
-
if (carouselItems?.length) for (const edge of carouselItems) pushEntry(edge.node);
|
|
80
|
-
else pushEntry(postData);
|
|
81
|
-
return entries;
|
|
82
|
-
};
|
|
83
|
-
const isInstagramHostname = (url) => {
|
|
84
|
-
try {
|
|
85
|
-
const hostname = new URL(url).hostname.toLowerCase();
|
|
86
|
-
return hostname === "instagram.com" || hostname.endsWith(".instagram.com");
|
|
87
|
-
} catch {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
var instagram_default = defineExtension({
|
|
92
|
-
canHandle: isInstagramHostname,
|
|
93
|
-
async resolveEntries(url) {
|
|
94
|
-
const shortcode = new URLPattern({
|
|
95
|
-
pathname: "/:type(p|reel|tv|reels|videos)/:shortcode{/*}?",
|
|
96
|
-
baseURL: new URL(url).origin
|
|
97
|
-
}).exec(url)?.pathname.groups.shortcode;
|
|
98
|
-
if (!shortcode) {
|
|
99
|
-
console.error("Could not extract a valid Instagram shortcode from the URL");
|
|
100
|
-
console.debug(url);
|
|
101
|
-
return [];
|
|
102
|
-
}
|
|
103
|
-
try {
|
|
104
|
-
let postData = await getPostViaGraphQL(shortcode);
|
|
105
|
-
if (!postData) {
|
|
106
|
-
console.warn("GraphQL method failed. Falling back to embed page scraping.");
|
|
107
|
-
postData = await getPostViaEmbedPage(shortcode);
|
|
108
|
-
}
|
|
109
|
-
if (!postData) {
|
|
110
|
-
console.error("All extraction methods failed. The post may be private, deleted, or require a login.");
|
|
111
|
-
return [];
|
|
112
|
-
}
|
|
113
|
-
return processPostData(postData);
|
|
114
|
-
} catch (error) {
|
|
115
|
-
console.error("A critical error occurred while fetching Instagram metadata:", error);
|
|
116
|
-
return [];
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
//#endregion
|
|
121
|
-
module.exports = instagram_default;
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
//#region src/extensions-api/main.ts
|
|
2
|
-
const runtimeContext = Azot ?? Streamyx ?? {};
|
|
3
|
-
if (runtimeContext) {
|
|
4
|
-
if (!runtimeContext.defineExtension) runtimeContext.defineExtension = (extension) => extension;
|
|
5
|
-
}
|
|
6
|
-
const defineExtension = runtimeContext.defineExtension;
|
|
7
|
-
runtimeContext.version;
|
|
8
|
-
runtimeContext.sleep;
|
|
9
|
-
runtimeContext.input;
|
|
10
|
-
runtimeContext.prompt;
|
|
11
|
-
runtimeContext.notify;
|
|
12
|
-
runtimeContext.confirm;
|
|
13
|
-
runtimeContext.ask;
|
|
14
|
-
runtimeContext.utils;
|
|
15
|
-
const Input = runtimeContext.Input;
|
|
16
|
-
const UrlSource = runtimeContext.UrlSource;
|
|
17
|
-
runtimeContext.ALL_FORMATS;
|
|
18
|
-
runtimeContext.DASH;
|
|
19
|
-
runtimeContext.DASH_FORMATS;
|
|
20
|
-
runtimeContext.HLS;
|
|
21
|
-
runtimeContext.HLS_FORMATS;
|
|
22
|
-
runtimeContext.MP4;
|
|
23
|
-
runtimeContext.MP3;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/builtins/ntv/ntv.ts
|
|
26
|
-
const between = (text, from, to) => text.split(from)[1]?.split(to)[0];
|
|
27
|
-
const extractXmlTag = (xmlBody, tagName) => {
|
|
28
|
-
const rawContent = between(xmlBody, `<${tagName}>`, `</${tagName}>`)?.trim();
|
|
29
|
-
if (!rawContent) return void 0;
|
|
30
|
-
const cdataMatch = rawContent.match(/<!\[CDATA\[(.*?)\]\]>/s);
|
|
31
|
-
if (cdataMatch?.[1]) return cdataMatch[1].trim();
|
|
32
|
-
return rawContent.split("DATA[")[1]?.split("]")[0]?.trim() || rawContent;
|
|
33
|
-
};
|
|
34
|
-
const fetchText = async (url, kind) => {
|
|
35
|
-
const response = await fetch(url);
|
|
36
|
-
if (!response.ok) {
|
|
37
|
-
console.error(`Failed to fetch ${kind}. Status: ${response.status} ${response.statusText}`);
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
return await response.text();
|
|
41
|
-
};
|
|
42
|
-
const resolveEpisodeEntries = async (url, pageBody, visited) => {
|
|
43
|
-
const pathname = new URL(url).pathname;
|
|
44
|
-
const episodeUrls = /* @__PURE__ */ new Set();
|
|
45
|
-
for (const part of pageBody.split("href=\"/serial")) {
|
|
46
|
-
if (!part.startsWith("/")) continue;
|
|
47
|
-
const route = part.split("\"")[0];
|
|
48
|
-
if (!route || route.length <= 1 || route.includes("/issues/") || route.includes("/about/") || route.split("/").length <= 2) continue;
|
|
49
|
-
episodeUrls.add(url.replace(pathname, `/serial${route}`));
|
|
50
|
-
}
|
|
51
|
-
const results = [];
|
|
52
|
-
for (const episodeUrl of episodeUrls) results.push(...await resolveEntriesInternal(episodeUrl, visited));
|
|
53
|
-
return results;
|
|
54
|
-
};
|
|
55
|
-
const resolveEntriesInternal = async (url, visited = /* @__PURE__ */ new Set()) => {
|
|
56
|
-
if (visited.has(url)) return [];
|
|
57
|
-
visited.add(url);
|
|
58
|
-
const pageBody = await fetchText(url, "NTV page");
|
|
59
|
-
if (!pageBody) return [];
|
|
60
|
-
const videoMetadataFeedLink = between(pageBody, "<meta property=\"ya:ovs:feed_url\" content=\"", "\">") ?? between(pageBody, "<meta property=\"ya:ovs:feed_url\" content=\"", "\" />");
|
|
61
|
-
if (!videoMetadataFeedLink) {
|
|
62
|
-
if (new URL(url).pathname.includes("/serial")) return resolveEpisodeEntries(url, pageBody, visited);
|
|
63
|
-
console.error("Could not find video link in the page.");
|
|
64
|
-
return [];
|
|
65
|
-
}
|
|
66
|
-
const videoId = videoMetadataFeedLink.split("video/")[1]?.split("/")[0];
|
|
67
|
-
if (!videoId) {
|
|
68
|
-
console.error("Could not parse NTV video id.");
|
|
69
|
-
return [];
|
|
70
|
-
}
|
|
71
|
-
const xmlBody = await fetchText(`https://www.ntv.ru/vi${videoId}/`, "NTV XML metadata");
|
|
72
|
-
if (!xmlBody) return [];
|
|
73
|
-
const playbackLink = extractXmlTag(xmlBody, "dash") || extractXmlTag(xmlBody, "hls");
|
|
74
|
-
const fileLink = extractXmlTag(xmlBody, "file") || extractXmlTag(xmlBody, "video");
|
|
75
|
-
const finalLink = extractXmlTag(xmlBody, "hifile") || extractXmlTag(xmlBody, "hd_video") || playbackLink || fileLink;
|
|
76
|
-
if (!finalLink) {
|
|
77
|
-
console.error("Could not resolve NTV media URL.");
|
|
78
|
-
return [];
|
|
79
|
-
}
|
|
80
|
-
const title = between(xmlBody, "<embed_tag>", "</embed_tag>") || "NTV";
|
|
81
|
-
const name = between(pageBody, "\"name\":\"", "\"");
|
|
82
|
-
const episodeNumberString = name?.includes("серия") ? name.split("-")[0] : void 0;
|
|
83
|
-
const episodeNumber = episodeNumberString ? parseInt(episodeNumberString, 10) : void 0;
|
|
84
|
-
const subtitlesRoute = between(xmlBody, "<subtitles>", "</subtitles>");
|
|
85
|
-
const subtitlesUrl = subtitlesRoute ? `https://www.ntv.ru${subtitlesRoute}` : void 0;
|
|
86
|
-
if (subtitlesUrl) console.debug(`Subtitles: ${subtitlesUrl}`);
|
|
87
|
-
const input = new Input({ source: new UrlSource(finalLink) });
|
|
88
|
-
if (subtitlesUrl) input.addSubtitleTrack(new UrlSource(subtitlesUrl), {
|
|
89
|
-
languageCode: "ru",
|
|
90
|
-
name: "Russian"
|
|
91
|
-
});
|
|
92
|
-
return [{
|
|
93
|
-
type: episodeNumber ? "episode" : "video",
|
|
94
|
-
title,
|
|
95
|
-
season: episodeNumber ? 1 : void 0,
|
|
96
|
-
episode: episodeNumber,
|
|
97
|
-
input
|
|
98
|
-
}];
|
|
99
|
-
};
|
|
100
|
-
var ntv_default = defineExtension({ resolveEntries(url) {
|
|
101
|
-
return resolveEntriesInternal(url, /* @__PURE__ */ new Set());
|
|
102
|
-
} });
|
|
103
|
-
//#endregion
|
|
104
|
-
module.exports = ntv_default;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
//#region src/extensions-api/main.ts
|
|
2
|
-
const runtimeContext = Azot ?? Streamyx ?? {};
|
|
3
|
-
if (runtimeContext) {
|
|
4
|
-
if (!runtimeContext.defineExtension) runtimeContext.defineExtension = (extension) => extension;
|
|
5
|
-
}
|
|
6
|
-
const defineExtension = runtimeContext.defineExtension;
|
|
7
|
-
runtimeContext.version;
|
|
8
|
-
runtimeContext.sleep;
|
|
9
|
-
runtimeContext.input;
|
|
10
|
-
runtimeContext.prompt;
|
|
11
|
-
runtimeContext.notify;
|
|
12
|
-
runtimeContext.confirm;
|
|
13
|
-
runtimeContext.ask;
|
|
14
|
-
runtimeContext.utils;
|
|
15
|
-
const Input = runtimeContext.Input;
|
|
16
|
-
const UrlSource = runtimeContext.UrlSource;
|
|
17
|
-
runtimeContext.ALL_FORMATS;
|
|
18
|
-
runtimeContext.DASH;
|
|
19
|
-
runtimeContext.DASH_FORMATS;
|
|
20
|
-
runtimeContext.HLS;
|
|
21
|
-
runtimeContext.HLS_FORMATS;
|
|
22
|
-
runtimeContext.MP4;
|
|
23
|
-
runtimeContext.MP3;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/builtins/rbc/rbc.ts
|
|
26
|
-
var rbc_default = defineExtension({ async resolveEntries(url) {
|
|
27
|
-
const response = await fetch(url);
|
|
28
|
-
if (!response.ok) throw new Error(`Failed to fetch RBC page: ${response.status} ${response.statusText}`);
|
|
29
|
-
const uri = (await response.text()).match(/(?:https?:)?\/\/[^\s"'<>]+\.m3u8(?:\?[^\s"'<>]*)?/i)?.[0];
|
|
30
|
-
if (!uri) throw new Error("Could not find RBC playlist URL.");
|
|
31
|
-
return [{
|
|
32
|
-
type: "video",
|
|
33
|
-
input: new Input({ source: new UrlSource(uri.startsWith("//") ? `https:${uri}` : uri) })
|
|
34
|
-
}];
|
|
35
|
-
} });
|
|
36
|
-
//#endregion
|
|
37
|
-
module.exports = rbc_default;
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
//#region src/extensions-api/main.ts
|
|
2
|
-
const runtimeContext = Azot ?? Streamyx ?? {};
|
|
3
|
-
if (runtimeContext) {
|
|
4
|
-
if (!runtimeContext.defineExtension) runtimeContext.defineExtension = (extension) => extension;
|
|
5
|
-
}
|
|
6
|
-
const defineExtension = runtimeContext.defineExtension;
|
|
7
|
-
runtimeContext.version;
|
|
8
|
-
runtimeContext.sleep;
|
|
9
|
-
runtimeContext.input;
|
|
10
|
-
runtimeContext.prompt;
|
|
11
|
-
runtimeContext.notify;
|
|
12
|
-
runtimeContext.confirm;
|
|
13
|
-
runtimeContext.ask;
|
|
14
|
-
runtimeContext.utils;
|
|
15
|
-
const Input = runtimeContext.Input;
|
|
16
|
-
const UrlSource = runtimeContext.UrlSource;
|
|
17
|
-
runtimeContext.ALL_FORMATS;
|
|
18
|
-
runtimeContext.DASH;
|
|
19
|
-
runtimeContext.DASH_FORMATS;
|
|
20
|
-
runtimeContext.HLS;
|
|
21
|
-
runtimeContext.HLS_FORMATS;
|
|
22
|
-
runtimeContext.MP4;
|
|
23
|
-
runtimeContext.MP3;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/builtins/rutube/rutube.ts
|
|
26
|
-
const patterns = [
|
|
27
|
-
"/video/:id{/}?",
|
|
28
|
-
"/play/embed/:id{/}?",
|
|
29
|
-
"/shorts/:id{/}?",
|
|
30
|
-
"/yappy/:yappyId{/}?",
|
|
31
|
-
"/video/private/:id{/}?"
|
|
32
|
-
];
|
|
33
|
-
const getRutubeParams = (url) => {
|
|
34
|
-
const params = {
|
|
35
|
-
yappyId: "",
|
|
36
|
-
id: "",
|
|
37
|
-
key: ""
|
|
38
|
-
};
|
|
39
|
-
params.key = new URL(url).searchParams.get("p") ?? "";
|
|
40
|
-
for (const path of patterns) {
|
|
41
|
-
const match = new URLPattern(path, "https://rutube.ru").exec(url);
|
|
42
|
-
if (!match) continue;
|
|
43
|
-
Object.assign(params, match.pathname.groups);
|
|
44
|
-
Object.assign(params, match.search.groups);
|
|
45
|
-
}
|
|
46
|
-
return params;
|
|
47
|
-
};
|
|
48
|
-
const resolveYappyEntries = async (yappyId) => {
|
|
49
|
-
const yappyUrl = (await fetch(`https://rutube.ru/pangolin/api/web/yappy/yappypage/?client=wdp&videoId=${yappyId}&page=1&page_size=15`).then((result) => result.json()).catch(() => null))?.results?.find((item) => String(item.id) === yappyId)?.link;
|
|
50
|
-
if (!yappyUrl) {
|
|
51
|
-
console.error("ErrorEmptyDownload");
|
|
52
|
-
return [];
|
|
53
|
-
}
|
|
54
|
-
return [{
|
|
55
|
-
type: "video",
|
|
56
|
-
title: `rutube_yappy_${yappyId}`,
|
|
57
|
-
input: new Input({ source: new UrlSource(yappyUrl) })
|
|
58
|
-
}];
|
|
59
|
-
};
|
|
60
|
-
var rutube_default = defineExtension({ async resolveEntries(url) {
|
|
61
|
-
const params = getRutubeParams(url);
|
|
62
|
-
if (params.yappyId) return resolveYappyEntries(params.yappyId);
|
|
63
|
-
if (!params.id) {
|
|
64
|
-
console.error("Could not extract Rutube video id");
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
const requestUrl = new URL(`https://rutube.ru/api/play/options/${params.id}/?no_404=true&referer&pver=v2`);
|
|
68
|
-
if (params.key) requestUrl.searchParams.set("p", params.key);
|
|
69
|
-
const play = await fetch(requestUrl).then((response) => response.json()).catch((error) => {
|
|
70
|
-
if (error instanceof Error) console.debug(error.message);
|
|
71
|
-
return null;
|
|
72
|
-
});
|
|
73
|
-
if (!play) {
|
|
74
|
-
console.error("Cannot fetch play info");
|
|
75
|
-
return [];
|
|
76
|
-
}
|
|
77
|
-
if (play.detail || !play.video_balancer?.m3u8) {
|
|
78
|
-
console.error("Play info is empty");
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
if (play.live_streams?.hls) {
|
|
82
|
-
console.error("Live videos are not supported");
|
|
83
|
-
return [];
|
|
84
|
-
}
|
|
85
|
-
return [{
|
|
86
|
-
type: "video",
|
|
87
|
-
title: play.title?.trim() || `rutube_${params.id}`,
|
|
88
|
-
input: new Input({ source: new UrlSource(play.video_balancer.m3u8) })
|
|
89
|
-
}];
|
|
90
|
-
} });
|
|
91
|
-
//#endregion
|
|
92
|
-
module.exports = rutube_default;
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
//#region src/extensions-api/main.ts
|
|
2
|
-
const runtimeContext = Azot ?? Streamyx ?? {};
|
|
3
|
-
if (runtimeContext) {
|
|
4
|
-
if (!runtimeContext.defineExtension) runtimeContext.defineExtension = (extension) => extension;
|
|
5
|
-
}
|
|
6
|
-
const defineExtension = runtimeContext.defineExtension;
|
|
7
|
-
runtimeContext.version;
|
|
8
|
-
runtimeContext.sleep;
|
|
9
|
-
runtimeContext.input;
|
|
10
|
-
runtimeContext.prompt;
|
|
11
|
-
runtimeContext.notify;
|
|
12
|
-
runtimeContext.confirm;
|
|
13
|
-
runtimeContext.ask;
|
|
14
|
-
const utils = runtimeContext.utils;
|
|
15
|
-
const Input = runtimeContext.Input;
|
|
16
|
-
const UrlSource = runtimeContext.UrlSource;
|
|
17
|
-
runtimeContext.ALL_FORMATS;
|
|
18
|
-
runtimeContext.DASH;
|
|
19
|
-
runtimeContext.DASH_FORMATS;
|
|
20
|
-
runtimeContext.HLS;
|
|
21
|
-
runtimeContext.HLS_FORMATS;
|
|
22
|
-
runtimeContext.MP4;
|
|
23
|
-
runtimeContext.MP3;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/builtins/soundcloud/soundcloud.ts
|
|
26
|
-
const cachedId = {
|
|
27
|
-
version: "",
|
|
28
|
-
id: ""
|
|
29
|
-
};
|
|
30
|
-
const findClientId = async () => {
|
|
31
|
-
try {
|
|
32
|
-
const homePage = await fetch("https://soundcloud.com/").then((response) => response.text()).catch((error) => {
|
|
33
|
-
const cause = error instanceof Error && error.cause != null ? String(error.cause) : "";
|
|
34
|
-
if (error instanceof Error && cause.includes("ECONNRESET")) console.warn("Soundcloud may be blocked in your region. Use proxy or VPN to bypass restrictions.");
|
|
35
|
-
return "";
|
|
36
|
-
});
|
|
37
|
-
const version = homePage.match(/window\.__sc_version="([0-9]{10})"/)?.[1];
|
|
38
|
-
if (version && cachedId.version === version) return cachedId.id;
|
|
39
|
-
let clientId = "";
|
|
40
|
-
for (const script of homePage.matchAll(/<script.+src="(.+)">/g)) {
|
|
41
|
-
const assetUrl = script[1];
|
|
42
|
-
if (!assetUrl?.startsWith("https://a-v2.sndcdn.com/")) continue;
|
|
43
|
-
const resolvedId = (await fetch(assetUrl).then((response) => response.text()).catch(() => "")).match(/\("client_id=[A-Za-z0-9]{32}"\)/)?.[0].match(/[A-Za-z0-9]{32}/)?.[0];
|
|
44
|
-
if (resolvedId) {
|
|
45
|
-
clientId = resolvedId;
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (version) {
|
|
50
|
-
cachedId.version = version;
|
|
51
|
-
cachedId.id = clientId;
|
|
52
|
-
}
|
|
53
|
-
return clientId;
|
|
54
|
-
} catch {
|
|
55
|
-
return "";
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
const prefersMp3 = (options) => options.audioCodecs?.some((codec) => codec === "aac" || codec === "mp3") ?? false;
|
|
59
|
-
var soundcloud_default = defineExtension({ async resolveEntries(url, options) {
|
|
60
|
-
const { author, song, accessKey, shortLink } = utils.execUrlPatterns(url, [
|
|
61
|
-
":author/:song/s-:accessKey",
|
|
62
|
-
":author/:song",
|
|
63
|
-
":shortLink"
|
|
64
|
-
], ["https://soundcloud.com", "https://on.soundcloud.com"]).pathname;
|
|
65
|
-
const clientId = await findClientId();
|
|
66
|
-
if (!clientId) throw new Error("No client ID");
|
|
67
|
-
let link;
|
|
68
|
-
if (new URL(url).hostname === "on.soundcloud.com" && shortLink) link = await fetch(`https://on.soundcloud.com/${shortLink}/`, { redirect: "manual" }).then((response) => {
|
|
69
|
-
const location = response.headers.get("location");
|
|
70
|
-
if (response.status === 302 && location?.startsWith("https://soundcloud.com/")) return location.split("?", 1)[0];
|
|
71
|
-
}).catch(() => void 0);
|
|
72
|
-
if (!link && author && song) link = `https://soundcloud.com/${author}/${song}${accessKey ? `/s-${accessKey}` : ""}`;
|
|
73
|
-
if (!link) throw new Error("Could not fetch");
|
|
74
|
-
const json = await fetch(`https://api-v2.soundcloud.com/resolve?url=${link}&client_id=${clientId}`).then((response) => response.status === 200 ? response.json() : null).catch(() => null);
|
|
75
|
-
if (!json) throw new Error("Could not fetch");
|
|
76
|
-
const transcodings = json.media?.transcodings;
|
|
77
|
-
if (!transcodings?.length) throw new Error("Empty download");
|
|
78
|
-
let selectedStream = transcodings.find((value) => value.preset === "opus_0_0");
|
|
79
|
-
const mp3Stream = transcodings.find((value) => value.preset === "mp3_0_0");
|
|
80
|
-
if (mp3Stream && (prefersMp3(options) || !selectedStream)) selectedStream = mp3Stream;
|
|
81
|
-
if (!selectedStream) throw new Error("Empty download");
|
|
82
|
-
const streamUrl = `${selectedStream.url}${selectedStream.url.includes("?") ? "&" : "?"}client_id=${clientId}&track_authorization=${json.track_authorization}`;
|
|
83
|
-
if (!streamUrl.startsWith("https://api-v2.soundcloud.com/media/soundcloud:tracks:")) throw new Error("Empty download");
|
|
84
|
-
const fileUrl = await fetch(streamUrl).then(async (response) => (await response.json()).url ?? "").catch(() => "");
|
|
85
|
-
if (!fileUrl) throw new Error("Could not fetch");
|
|
86
|
-
return [{
|
|
87
|
-
type: "audio",
|
|
88
|
-
title: json.title.trim(),
|
|
89
|
-
author: json.user.username.trim(),
|
|
90
|
-
input: new Input({ source: new UrlSource(fileUrl) })
|
|
91
|
-
}];
|
|
92
|
-
} });
|
|
93
|
-
//#endregion
|
|
94
|
-
module.exports = soundcloud_default;
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
//#region src/extensions-api/main.ts
|
|
2
|
-
const runtimeContext = Azot ?? Streamyx ?? {};
|
|
3
|
-
if (runtimeContext) {
|
|
4
|
-
if (!runtimeContext.defineExtension) runtimeContext.defineExtension = (extension) => extension;
|
|
5
|
-
}
|
|
6
|
-
const defineExtension = runtimeContext.defineExtension;
|
|
7
|
-
runtimeContext.version;
|
|
8
|
-
runtimeContext.sleep;
|
|
9
|
-
runtimeContext.input;
|
|
10
|
-
runtimeContext.prompt;
|
|
11
|
-
runtimeContext.notify;
|
|
12
|
-
runtimeContext.confirm;
|
|
13
|
-
runtimeContext.ask;
|
|
14
|
-
runtimeContext.utils;
|
|
15
|
-
const Input = runtimeContext.Input;
|
|
16
|
-
const UrlSource = runtimeContext.UrlSource;
|
|
17
|
-
runtimeContext.ALL_FORMATS;
|
|
18
|
-
runtimeContext.DASH;
|
|
19
|
-
runtimeContext.DASH_FORMATS;
|
|
20
|
-
runtimeContext.HLS;
|
|
21
|
-
runtimeContext.HLS_FORMATS;
|
|
22
|
-
runtimeContext.MP4;
|
|
23
|
-
runtimeContext.MP3;
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region src/builtins/tiktok/tiktok.ts
|
|
26
|
-
var tiktok_default = defineExtension({
|
|
27
|
-
canHandle: (url) => {
|
|
28
|
-
try {
|
|
29
|
-
const hostname = new URL(url).hostname.toLowerCase();
|
|
30
|
-
return hostname === "tiktok.com" || hostname.endsWith(".tiktok.com");
|
|
31
|
-
} catch {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
async resolveEntries(url) {
|
|
36
|
-
const response = await fetch(url);
|
|
37
|
-
if (!response.ok) {
|
|
38
|
-
console.error(`Failed to fetch TikTok page. Status: ${response.status}`);
|
|
39
|
-
return [];
|
|
40
|
-
}
|
|
41
|
-
const jsonString = (await response.text()).split("<script id=\"__UNIVERSAL_DATA_FOR_REHYDRATION__\" type=\"application/json\">")[1]?.split("<\/script>")[0];
|
|
42
|
-
if (!jsonString) {
|
|
43
|
-
console.error("Could not find target script tag. TikTok might have updated their page structure.");
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
let data;
|
|
47
|
-
try {
|
|
48
|
-
data = JSON.parse(jsonString);
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.error("Failed to parse TikTok page JSON", error, { url });
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
const videoDetail = data.__DEFAULT_SCOPE__?.["webapp.video-detail"];
|
|
54
|
-
const videoData = videoDetail?.itemInfo?.itemStruct;
|
|
55
|
-
if (!videoData) {
|
|
56
|
-
console.error("Could not find video data in the JSON payload. The content might be unavailable or the structure has changed.");
|
|
57
|
-
if (videoDetail?.statusMsg) console.error(`Error ${videoDetail.statusCode}: ${videoDetail.statusMsg}`);
|
|
58
|
-
return [];
|
|
59
|
-
}
|
|
60
|
-
const videoUrl = videoData.video?.playAddr;
|
|
61
|
-
if (!videoUrl) {
|
|
62
|
-
console.error("Could not find a video URL (playAddr) in the JSON payload.");
|
|
63
|
-
return [];
|
|
64
|
-
}
|
|
65
|
-
return [{
|
|
66
|
-
type: "video",
|
|
67
|
-
title: videoData.desc || "TikTok Video",
|
|
68
|
-
input: new Input({ source: new UrlSource(videoUrl, { requestInit: { headers: {
|
|
69
|
-
Referer: "https://www.tiktok.com/",
|
|
70
|
-
Cookie: document.cookie
|
|
71
|
-
} } }) })
|
|
72
|
-
}];
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
//#endregion
|
|
76
|
-
module.exports = tiktok_default;
|