-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnodeinsider.js
More file actions
104 lines (94 loc) · 4.12 KB
/
nodeinsider.js
File metadata and controls
104 lines (94 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
const { program } = require('commander');
const fs = require('fs');
const { Readable } = require('stream');
const { finished } = require('stream/promises');
const sanitize = require("sanitize-filename");
const path = require('path');
const cheerio = require('cheerio');
const prefix = "https://downloads.khinsider.com/game-soundtracks/album";
const songPagePrefix = "https://downloads.khinsider.com";
const artworkRegex = /(?<=\/)[^\/\?#]+(?=[^\/]*$)/;
const extRegex = /\.\w{3,4}($|\?)/;
(async () => {
program
.requiredOption('-i, --id <ost id>', 'ID of the soundtrack (that part after game-soundtracks/album)')
.option('-o, --output <folder>', 'Where to download')
.option('--disableart', 'Disable art download')
.option('--dump <file>', 'Dump all download links to the specified file, and skip downloading.')
program.parse(process.argv);
const options = program.opts();
console.log(`Fetching songlist...`);
const initialSonglist = await fetch(`${prefix}/${options.id}`);
const initialSonglistBody = await initialSonglist.text();
const initSonglistDOM = cheerio.load(initialSonglistBody);
const songlist = [];
const artworks = [];
initSonglistDOM(`.playlistDownloadSong > a`).each((i, el) => {
songlist.push(initSonglistDOM(el).attr("href"));
});
initSonglistDOM('.albumImage > a').each((i, el) => {
artworks.push(initSonglistDOM(el).attr("href"));
})
if (!songlist) {
console.error('Album not found. Make sure you pasted the right id!');
process.exit(1);
}
let outputBase;
if(!options.output) {
outputBase = './'
} else {
outputBase = options.output;
}
const album = initSonglistDOM('h2').prop('innerText');
const sanitizedAlbumName = sanitize(album);
if (album !== sanitizedAlbumName) {
console.log('WARN : Album name had to be sanitized. Please double check the output.')
}
console.log(`Album name : ${album}`)
console.log(`Found ${songlist.length} songs.`);
if (!options.dump && !fs.existsSync(path.join(outputBase, sanitizedAlbumName))) {
fs.mkdirSync(path.join(outputBase, sanitizedAlbumName), { recursive: true });
}
if (!options.disableart) {
console.log(`Processing artworks...`);
for (const art of artworks) {
const filename = path.join(outputBase, sanitizedAlbumName, artworkRegex.exec(art)[0]);
if (!fs.existsSync(filename) && !options.dump) await downloadFile(art, filename);
if (options.dump) fs.appendFileSync(options.dump, `${art}\n`)
}
}
let progress = 0;
console.log('Processing songs...');
for (const song of songlist) {
progress += 1;
const resp = await fetch(`${songPagePrefix}${song}`);
const body = await resp.text();
const $ = cheerio.load(body);
let url = $('#pageContent > p:nth-child(10) > a:nth-child(1)').prop('href');
if(!url) {
console.log('WARN : FLAC is unavailable, falling back to lossy.')
url = $('#pageContent > p:nth-child(9) > a:nth-child(1)').prop('href');
}
if(!url) {
console.error("Couldn't find this song's URL; skipping.")
} else if (options.dump) {
fs.appendFileSync(options.dump, `${url}\n`)
} else {
const songName = $('#pageContent > p:nth-child(6) > b:nth-child(3)').prop('innerText');
const filename = path.join(outputBase, sanitizedAlbumName, `${`${progress}`.padStart(2, '0')}. ${songName}${extRegex.exec(url)[0]}`);
if (fs.existsSync(filename)) {
console.log(`(${progress}/${songlist.length}) "${songName}" has already been downloaded, skipping`);
} else {
console.log(`(${progress}/${songlist.length}) Downloading "${songName}"`);
await downloadFile(url, filename);
}
}
}
console.log('Done.');
})();
async function downloadFile(url, filename) {
const response = await fetch(url);
const body = Readable.fromWeb(response.body);
const ws = fs.createWriteStream(filename);
await finished(body.pipe(ws));
}