updated script

This commit is contained in:
2025-10-23 02:17:40 -05:00
parent de58099ac0
commit fa199ea1bb
3 changed files with 102 additions and 20 deletions

91
main.ts
View File

@@ -1,8 +1,7 @@
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 { parseArgs } from "jsr:@std/cli/parse-args"
import { exists } from "jsr:@std/fs/exists";
import * as cheerio from 'https://esm.sh/cheerio?target=esnext'
const REGEX_PLAYLISTURL =
@@ -12,23 +11,65 @@ const REGEX_SONGURL =
const REGEX_ALBUMTITLE = /^(.*?) MP3 - Download/i
const REGEX_UNSAFEFORFILE = /[^a-z0-9\-_=+,.()\[\]{} ]/gi
async function main() {
// deno main.ts <playlistURL> [<downloadPath>] [sync]
const playlistURL = argv[2]
const downloadPath = argv[3] || '.'
const runSync = argv[4]?.toLowerCase() == 'sync'
// parse args
const flags = parseArgs(Deno.args, {
alias: {
"url": ["u"],
"output": ["o"],
"sync": ["s"],
"help": ["h"],
},
string: ["url", "output"],
boolean: ["sync", "help"],
default: {
"url": "",
"output": ".",
"sync": false
}
})
if (!flags.url && flags._.length > 0) {
flags.url = flags._[0].toString()
}
function printHelp() {
console.log(`deno
--allow-net --allow-write --allow-read main.ts
[--url] <url>
[--output <downloadPath>]
[--sync]
[--help]
parameters:
--url -u (default)
url to download
--output -o
default: "."
output path
--sync -s
download files one at a time
--help -h
print help message
`)
}
async function main() {
// load all song details
const playlist = await fetchPlaylist(playlistURL)
const playlist = await fetchPlaylist(flags.url)
// if sync, download one at a time
if (runSync) {
if (flags.sync) {
console.log('downloading one at a time\n')
for (const song of playlist) {
await downloadSong(song, downloadPath || '.')
await downloadSong(song, flags.output || '.')
}
} else {
console.log('downloading all at once\n')
await Promise.all(
playlist.map((song) => downloadSong(song, downloadPath || '.'))
playlist.map((song) => downloadSong(song, flags.output || '.'))
)
}
}
@@ -38,6 +79,8 @@ async function fetchPlaylist(url: string): Promise<PlaylistSongData[]> {
throw `unaccepted url ${url}`
}
console.log(`downloading: ${url}`)
// load the playlist page's dom
const req = await fetch(url)
const text = await req.text()
@@ -53,12 +96,12 @@ async function fetchPlaylist(url: string): Promise<PlaylistSongData[]> {
throw `unable to grab album name from ${title}`
}
const albumName = titleMatch[1]
console.log(` title: ${albumName}`)
// parse all rows in playlist
const columns = getPlaylistTableHeaders($)
const rows = getPlaylistRows($, columns, albumName)
console.log(`downloading ${rows.length} songs`)
console.log(` songs: ${rows.length}\n`)
return rows
}
@@ -203,12 +246,12 @@ async function downloadSong(song: PlaylistSongData, location: string) {
const { pathname, fullpathname } = pathFor(location, song)
// ensure folder exists
if (!existsSync(pathname)) {
await mkdir(pathname)
if (!await exists(pathname)) {
await Deno.mkdir(pathname)
}
// skip file if it exists
if (existsSync(fullpathname)) {
if (await exists(fullpathname)) {
console.log(`skipping file already exists ${fullpathname}`)
}
@@ -218,7 +261,7 @@ async function downloadSong(song: PlaylistSongData, location: string) {
// download the file
const songresp = await fetch(flacUrl)
const songblob = await songresp.arrayBuffer()
return writeFile(fullpathname, toBuffer(songblob))
return Deno.writeFile(fullpathname, toBuffer(songblob))
}
interface SongPath {
@@ -279,4 +322,12 @@ function toBuffer(arrayBuffer: ArrayBuffer): Buffer<ArrayBuffer> {
return buffer
}
main().catch((e) => console.error(e))
if (!flags.url) {
console.log('Missing URL\n\n')
printHelp()
} else if (flags.help) {
printHelp()
} else {
main().catch((e) => console.error(e))
}