import * as fs from 'fs'; import * as path from 'path'; import { SongsterrToAlphaTabConverter } from './songsterr/songsterr-to-alphatab.converter.ts'; import type { SongsterrStateMetaCurrent, SongsterrRevisionTrackPayload } from './songsterr/types.ts'; // Polite standard User-Agent header to prevent aggressive scraper blocks const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; /** * Fetches the HTML content of a URL using the global fetch API. * * @param url Target endpoint to fetch. * @returns HTML string content. */ async function fetchHTML(url: string): Promise { const res = await fetch(url, { headers: { 'User-Agent': userAgent } }); if (!res.ok) { throw new Error(`Failed to fetch ${url} (HTTP ${res.status})`); } return res.text(); } /** * Fetches and parses JSON from a URL using the global fetch API. * * @param url Target JSON API endpoint. * @returns Parsed JSON object. */ async function fetchJSON(url: string): Promise { const res = await fetch(url, { headers: { 'User-Agent': userAgent } }); if (!res.ok) { throw new Error(`Failed to fetch JSON ${url} (HTTP ${res.status})`); } return res.json(); } /** * Sanitizes a filename string by replacing illegal OS characters with underscores. * * @param name File name to clean. * @returns Cleaned file name. */ function sanitizeFilename(name: string): string { return name.replace(/[\\/:*?"<>|]/g, '_'); } /** * Main execution entry point for the Songsterr download and conversion helper. */ async function main() { const args = process.argv.slice(2); let songUrl = ''; let outputDir = '.'; // Parse custom command-line arguments: --url and --output for (let i = 0; i < args.length; i++) { if (args[i] === '--url' && i + 1 < args.length) { songUrl = args[i + 1]; i++; } else if (args[i] === '--output' && i + 1 < args.length) { outputDir = args[i + 1]; i++; } } if (!songUrl) { console.error('Error: Missing --url parameter'); process.exit(1); } try { console.log(`[*] Fetching Songsterr page: ${songUrl}`); const html = await fetchHTML(songUrl); // Locate the embedded React hydration state JSON script tag const stateMatch = html.match(/