import { existsSync } from 'node:fs' import { mkdir, writeFile } from 'node:fs/promises' import path from 'node:path' import {argv} from 'node:process' const REGEX_PLAYLISTURL = /^https:\/\/downloads\.khinsider\.com\/game-soundtracks\/album\/[^\/]+\/?$/i const REGEX_SONGURL = /^https:\/\/downloads\.khinsider\.com\/game-soundtracks\/album\/[^\/]+\/[^\/]+\/?$/i const REGEX_FILEPATHPARSE = /^\/soundtracks\/([^\/]+)\/[^\/]+\/([^\/]+)$/i const REGEX_PLAYLIST_SONGHREF = //gi const REGEX_SONG_FILEHREF = / downloadSong(song, downloadPath || '.'))) } } async function fetchPlaylist(url: string): Promise { if (!REGEX_PLAYLISTURL.test(url)) { throw `unaccepted url ${url}` } const resp = await fetch(url) const text = await resp.text() const matches = text.matchAll(REGEX_PLAYLIST_SONGHREF) const matchesArr = [...matches].map(match => match[1]) console.log(`downloading ${matchesArr.length} songs`) return matchesArr } async function downloadSong(url: string, location: string) { if (!/^http/i.test(url)) { url = 'https://downloads.khinsider.com' + url } if (!REGEX_SONGURL.test(url)) { throw `unaccepted url ${url}` } let resp = await fetch(url) let text = await resp.text() let match = text.match(REGEX_SONG_FILEHREF) if (!match) { throw `can't find download link for ${url}` } const songurl = new URL(match[1]) const songurlmatch = REGEX_FILEPATHPARSE.exec(songurl.pathname) if (!songurlmatch) { throw `can't find folder and filename for ${songurl}` } const foldername = decodeURIComponent(songurlmatch[1]) const filename = decodeURIComponent(songurlmatch[2]) const pathname = path.resolve(location, foldername) const fullpathname = path.resolve(pathname, filename) if (!existsSync(pathname)) { await mkdir(pathname) } if (existsSync(fullpathname)) { console.log(`skipping file already exists ${fullpathname}`) } console.log(`downloading ${fullpathname}`) const songresp = await fetch(songurl) const songblob = await songresp.arrayBuffer() return writeFile(fullpathname, toBuffer(songblob)) } function toBuffer(arrayBuffer: ArrayBuffer) { const buffer = Buffer.alloc(arrayBuffer.byteLength); const view = new Uint8Array(arrayBuffer); for (let i = 0; i < buffer.length; ++i) { buffer[i] = view[i]; } return buffer; } main().catch(e => console.error(e))