diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..281ed98 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "tabWidth": 2, + "useTabs": false, + "semi": false, + "singleQuote": true, + "objectWrap": "collapse" +} diff --git a/main.ts b/main.ts index 2fab175..ca6148d 100644 --- a/main.ts +++ b/main.ts @@ -2,11 +2,13 @@ import { existsSync } from 'node:fs' import { mkdir, writeFile } from 'node:fs/promises' import path from 'node:path' import { argv } from 'node:process' -import { Buffer } from "node:buffer" -import * as cheerio from "https://esm.sh/cheerio?target=esnext" +import { Buffer } from 'node:buffer' +import * as cheerio from 'https://esm.sh/cheerio?target=esnext' -const REGEX_PLAYLISTURL = /^https:\/\/downloads\.khinsider\.com\/game-soundtracks\/album\/[^\/]+\/?$/i -const REGEX_SONGURL = /^https:\/\/downloads\.khinsider\.com\/game-soundtracks\/album\/[^\/]+\/[^\/]+\/?$/i +const REGEX_PLAYLISTURL = + /^https:\/\/downloads\.khinsider\.com\/game-soundtracks\/album\/[^\/]+\/?$/i +const REGEX_SONGURL = + /^https:\/\/downloads\.khinsider\.com\/game-soundtracks\/album\/[^\/]+\/[^\/]+\/?$/i const REGEX_ALBUMTITLE = /^(.*?) MP3 - Download/i const REGEX_UNSAFEFORFILE = /[^a-z0-9\-_=+,.()\[\]{} ]/gi @@ -22,7 +24,9 @@ async function main() { await downloadSong(song, downloadPath || '.') } } else { - await Promise.all(playlist.map(song => downloadSong(song, downloadPath || '.'))) + await Promise.all( + playlist.map((song) => downloadSong(song, downloadPath || '.')) + ) } } @@ -36,9 +40,10 @@ async function fetchPlaylist(url: string): Promise { const $ = cheerio.load(text) - const title = $.extract({ - title: 'title' - }).title ?? '' + const title = + $.extract({ + title: 'title', + }).title ?? '' const titleMatch = REGEX_ALBUMTITLE.exec(title) if (titleMatch === null) { throw `unable to grab album name from ${title}` @@ -49,7 +54,7 @@ async function fetchPlaylist(url: string): Promise { const rows = getPlaylistRows($, columns, albumName) console.log(`downloading ${rows.length} songs`) - + return rows } @@ -58,6 +63,7 @@ interface PlaylistTableColumns { track: number cd: number } + interface PlaylistSongData { url: string album: string @@ -69,26 +75,29 @@ interface PlaylistSongData { function getPlaylistTableHeaders($: cheerio.CheerioAPI): PlaylistTableColumns { const header = $('#songlist tr#songlist_header') const headerCells = header.extract({ - cells: ['th'] + cells: ['th'], }) - const indexes = headerCells.cells.reduce((p, c, i) => { - switch (c.toLocaleLowerCase()) { - case 'cd': - p.cd = i - break - case '#': - p.track = i - break - case 'song name': - p.name = i + const indexes = headerCells.cells.reduce( + (p, c, i) => { + switch (c.toLocaleLowerCase()) { + case 'cd': + p.cd = i + break + case '#': + p.track = i + break + case 'song name': + p.name = i + } + return p + }, + { + name: -1, + track: -1, + cd: -1, } - return p - }, { - name: -1, - track: -1, - cd: -1, - }) + ) if (indexes.name == -1) { throw 'unable to find song title column' @@ -97,10 +106,14 @@ function getPlaylistTableHeaders($: cheerio.CheerioAPI): PlaylistTableColumns { return indexes } -function getPlaylistRows($: cheerio.CheerioAPI, columns: PlaylistTableColumns, albumName: string): PlaylistSongData[] { +function getPlaylistRows( + $: cheerio.CheerioAPI, + columns: PlaylistTableColumns, + albumName: string +): PlaylistSongData[] { const rows = $('#songlist tr:not(#songlist_header):not(#songlist_footer)') const rowsData: PlaylistSongData[] = [] - + rows.each((_, rowEl) => { const row = cheerio.load(rowEl) const rowData: PlaylistSongData = { @@ -110,16 +123,17 @@ function getPlaylistRows($: cheerio.CheerioAPI, columns: PlaylistTableColumns, a track: -1, cd: -1, } - - rowData.url = row.extract({ - url: { - selector: 'td.playlistDownloadSong a', - value: 'href' - } - }).url ?? '' + + rowData.url = + row.extract({ + url: { + selector: 'td.playlistDownloadSong a', + value: 'href', + }, + }).url ?? '' const rowCells = row.extract({ - cells: ['td'] + cells: ['td'], }).cells rowData.name = rowCells[columns.name] @@ -163,8 +177,8 @@ async function downloadSong(song: PlaylistSongData, location: string) { const flacUrl = $.extract({ url: { selector: '#pageContent a[href*="flac"]', - value: 'href' - } + value: 'href', + }, }).url if (!flacUrl) { @@ -172,7 +186,7 @@ async function downloadSong(song: PlaylistSongData, location: string) { } const { pathname, fullpathname } = pathFor(location, song) - + if (!existsSync(pathname)) { await mkdir(pathname) } @@ -198,24 +212,27 @@ function pathFor(location: string, song: PlaylistSongData): SongPath { const albumname = song.album.replace(REGEX_UNSAFEFORFILE, '') const songname = song.name.replace(REGEX_UNSAFEFORFILE, '') - const filename = `${song.cd >= 0 ? song.cd+'.' : ''}${song.track >= 0 ? song.track+'.' : ''}${song.cd >= 0 || song.track >= 0 ? ' ' : ''}${songname}.flac` + const cd = song.cd >= 0 ? song.cd + '.' : '' + const track = song.track >= 0 ? song.track + '.' : '' + const separator = song.cd >= 0 || song.track >= 0 ? ' ' : '' + const filename = `${cd}${track}${separator}${songname}.flac` const pathname = path.resolve(location, albumname) const fullpathname = path.resolve(pathname, filename) return { pathname, - fullpathname + fullpathname, } } function toBuffer(arrayBuffer: ArrayBuffer) { - const buffer = Buffer.alloc(arrayBuffer.byteLength); - const view = new Uint8Array(arrayBuffer); + const buffer = Buffer.alloc(arrayBuffer.byteLength) + const view = new Uint8Array(arrayBuffer) for (let i = 0; i < buffer.length; ++i) { - buffer[i] = view[i]; + buffer[i] = view[i] } - return buffer; + return buffer } -main().catch(e => console.error(e)) +main().catch((e) => console.error(e))