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