564 lines
28 KiB
JavaScript
564 lines
28 KiB
JavaScript
"use strict";
|
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
function step(op) {
|
|
if (f) throw new TypeError("Generator is already executing.");
|
|
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
switch (op[0]) {
|
|
case 0: case 1: t = op; break;
|
|
case 4: _.label++; return { value: op[1], done: false };
|
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
default:
|
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
if (t[2]) _.ops.pop();
|
|
_.trys.pop(); continue;
|
|
}
|
|
op = body.call(thisArg, _);
|
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
}
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.Util = void 0;
|
|
var fs = require("fs");
|
|
var path = require("path");
|
|
var index_1 = require("./index");
|
|
var stream_1 = require("stream");
|
|
var child_process_1 = require("child_process");
|
|
var temp = 0;
|
|
var FFMPEG = { checked: false, path: "" };
|
|
var SOURCES = [
|
|
function () {
|
|
var _a;
|
|
var ffmpeg = require("ffmpeg-static");
|
|
return (_a = ffmpeg === null || ffmpeg === void 0 ? void 0 : ffmpeg.path) !== null && _a !== void 0 ? _a : ffmpeg;
|
|
},
|
|
function () { return "ffmpeg"; },
|
|
function () { return "./ffmpeg"; },
|
|
];
|
|
var Util = /** @class */ (function () {
|
|
function Util(api) {
|
|
var _this = this;
|
|
this.api = api;
|
|
this.tracks = new index_1.Tracks(this.api);
|
|
this.users = new index_1.Users(this.api);
|
|
this.playlists = new index_1.Playlists(this.api);
|
|
this.resolveTrack = function (trackResolvable) { return __awaiter(_this, void 0, void 0, function () {
|
|
var _a;
|
|
return __generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0:
|
|
if (!(typeof trackResolvable === "string")) return [3 /*break*/, 2];
|
|
return [4 /*yield*/, this.tracks.get(trackResolvable)];
|
|
case 1:
|
|
_a = _b.sent();
|
|
return [3 /*break*/, 3];
|
|
case 2:
|
|
_a = trackResolvable;
|
|
_b.label = 3;
|
|
case 3: return [2 /*return*/, _a];
|
|
}
|
|
});
|
|
}); };
|
|
this.sortTranscodings = function (trackResolvable, protocol) { return __awaiter(_this, void 0, void 0, function () {
|
|
var track, transcodings;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, this.resolveTrack(trackResolvable)];
|
|
case 1:
|
|
track = _a.sent();
|
|
transcodings = track.media.transcodings.sort(function (t) { return (t.quality === "hq" ? -1 : 1); });
|
|
if (!protocol)
|
|
return [2 /*return*/, transcodings];
|
|
return [2 /*return*/, transcodings.filter(function (t) { return t.format.protocol === protocol; })];
|
|
}
|
|
});
|
|
}); };
|
|
this.getStreamLink = function (transcoding) { return __awaiter(_this, void 0, void 0, function () {
|
|
var url, client_id, headers, connect, _a;
|
|
return __generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0:
|
|
if (!(transcoding === null || transcoding === void 0 ? void 0 : transcoding.url))
|
|
return [2 /*return*/, null];
|
|
url = transcoding.url;
|
|
return [4 /*yield*/, this.api.getClientId()];
|
|
case 1:
|
|
client_id = _b.sent();
|
|
headers = this.api.headers;
|
|
connect = url.includes("?") ? "&client_id=".concat(client_id) : "?client_id=".concat(client_id);
|
|
_b.label = 2;
|
|
case 2:
|
|
_b.trys.push([2, 3, , 5]);
|
|
return [2 /*return*/, fetch(url + connect, { headers: headers }).then(function (r) { return r.json(); }).then(function (r) { return r.url; })];
|
|
case 3:
|
|
_a = _b.sent();
|
|
return [4 /*yield*/, this.api.getClientId(true)];
|
|
case 4:
|
|
client_id = _b.sent();
|
|
connect = url.includes("?") ? "&client_id=".concat(client_id) : "?client_id=".concat(client_id);
|
|
try {
|
|
return [2 /*return*/, fetch(url + connect, { headers: headers }).then(function (r) { return r.json(); }).then(function (r) { return r.url; })];
|
|
}
|
|
catch (_c) {
|
|
return [2 /*return*/, null];
|
|
}
|
|
return [3 /*break*/, 5];
|
|
case 5: return [2 /*return*/];
|
|
}
|
|
});
|
|
}); };
|
|
/**
|
|
* Gets the direct streaming link of a track.
|
|
*/
|
|
this.streamLink = function (trackResolvable, protocol) { return __awaiter(_this, void 0, void 0, function () {
|
|
var track, transcodings;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, this.resolveTrack(trackResolvable)];
|
|
case 1:
|
|
track = _a.sent();
|
|
return [4 /*yield*/, this.sortTranscodings(track, protocol)];
|
|
case 2:
|
|
transcodings = _a.sent();
|
|
if (!transcodings.length)
|
|
return [2 /*return*/, null];
|
|
return [2 /*return*/, this.getStreamLink(transcodings[0])];
|
|
}
|
|
});
|
|
}); };
|
|
this.mergeFiles = function (files, outputFile) { return __awaiter(_this, void 0, void 0, function () {
|
|
var outStream, ret, _loop_1, _i, files_1, file;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0:
|
|
outStream = fs.createWriteStream(outputFile);
|
|
ret = new Promise(function (resolve, reject) {
|
|
outStream.on("finish", resolve);
|
|
outStream.on("error", reject);
|
|
});
|
|
_loop_1 = function (file) {
|
|
return __generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0: return [4 /*yield*/, new Promise(function (resolve, reject) {
|
|
fs.createReadStream(file).on("error", reject).on("end", resolve).pipe(outStream, { end: false });
|
|
})];
|
|
case 1:
|
|
_b.sent();
|
|
return [2 /*return*/];
|
|
}
|
|
});
|
|
};
|
|
_i = 0, files_1 = files;
|
|
_a.label = 1;
|
|
case 1:
|
|
if (!(_i < files_1.length)) return [3 /*break*/, 4];
|
|
file = files_1[_i];
|
|
return [5 /*yield**/, _loop_1(file)];
|
|
case 2:
|
|
_a.sent();
|
|
_a.label = 3;
|
|
case 3:
|
|
_i++;
|
|
return [3 /*break*/, 1];
|
|
case 4:
|
|
outStream.end();
|
|
return [2 /*return*/, ret];
|
|
}
|
|
});
|
|
}); };
|
|
this.checkFFmpeg = function () {
|
|
var _a;
|
|
if (FFMPEG.checked)
|
|
return true;
|
|
for (var _i = 0, SOURCES_1 = SOURCES; _i < SOURCES_1.length; _i++) {
|
|
var fn = SOURCES_1[_i];
|
|
try {
|
|
var command = fn();
|
|
var result = (0, child_process_1.spawnSync)(command, ["-h"], { windowsHide: true, shell: true, encoding: "utf-8" });
|
|
if (result.error)
|
|
throw result.error;
|
|
if (result.stderr && !result.stdout)
|
|
throw new Error(result.stderr);
|
|
var output = result.output.filter(Boolean).join("\n");
|
|
var version = (_a = /version (.+) Copyright/im.exec(output)) === null || _a === void 0 ? void 0 : _a[1];
|
|
if (!version)
|
|
throw new Error("Malformed FFmpeg command using ".concat(command));
|
|
FFMPEG.path = command;
|
|
}
|
|
catch (_b) { }
|
|
}
|
|
FFMPEG.checked = true;
|
|
if (!FFMPEG.path) {
|
|
console.warn("FFmpeg not found, please install ffmpeg-static or add ffmpeg to your PATH.");
|
|
console.warn("Download m4a (hq) is disabled, use mp3 (sq) instead.");
|
|
}
|
|
return true;
|
|
};
|
|
this.spawnFFmpeg = function (argss) {
|
|
try {
|
|
(0, child_process_1.spawnSync)(FFMPEG.path, argss, { windowsHide: true, shell: false });
|
|
}
|
|
catch (e) {
|
|
console.error(e);
|
|
throw "FFmpeg error";
|
|
}
|
|
};
|
|
/**
|
|
* Readable stream of m3u playlists.
|
|
*/
|
|
this.m3uReadableStream = function (trackResolvable) { return __awaiter(_this, void 0, void 0, function () {
|
|
var track, transcodings, transcoding, _i, transcodings_1, t, headers, client_id, connect, m3uLink, destDir, output, m3u, urls, chunks, i, arrayBuffer, chunkPath, stream;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, this.resolveTrack(trackResolvable)];
|
|
case 1:
|
|
track = _a.sent();
|
|
return [4 /*yield*/, this.sortTranscodings(track, "hls")];
|
|
case 2:
|
|
transcodings = _a.sent();
|
|
if (!transcodings.length)
|
|
throw "No transcodings found";
|
|
for (_i = 0, transcodings_1 = transcodings; _i < transcodings_1.length; _i++) {
|
|
t = transcodings_1[_i];
|
|
if (t.format.mime_type.startsWith('audio/mp4; codecs="mp4a') && this.checkFFmpeg()) {
|
|
transcoding = { url: t.url, type: "m4a" };
|
|
break;
|
|
}
|
|
if (t.format.mime_type.startsWith("audio/mpeg")) {
|
|
transcoding = { url: t.url, type: "mp3" };
|
|
break;
|
|
}
|
|
}
|
|
if (!transcoding) {
|
|
console.log("Support for this track is not yet implemented, please open an issue on GitHub.\n\n URL: ".concat(track.permalink_url, ".\n\n Type: ").concat(track.media.transcodings.map(function (t) { return t.format.mime_type; }).join(" | ")));
|
|
throw "No supported transcodings found";
|
|
}
|
|
headers = this.api.headers;
|
|
return [4 /*yield*/, this.api.getClientId()];
|
|
case 3:
|
|
client_id = _a.sent();
|
|
connect = transcoding.url.includes("?") ? "&client_id=".concat(client_id) : "?client_id=".concat(client_id);
|
|
return [4 /*yield*/, fetch(transcoding.url + connect, { headers: this.api.headers }).then(function (r) { return r.json(); }).then(function (r) { return r.url; })];
|
|
case 4:
|
|
m3uLink = _a.sent();
|
|
destDir = path.join(__dirname, "tmp_".concat(temp++));
|
|
if (!fs.existsSync(destDir))
|
|
fs.mkdirSync(destDir, { recursive: true });
|
|
output = path.join(destDir, "out.".concat(transcoding.type));
|
|
if (!(transcoding.type === "m4a")) return [3 /*break*/, 5];
|
|
try {
|
|
this.spawnFFmpeg(["-y", "-loglevel", "warning", "-i", m3uLink, "-bsf:a", "aac_adtstoasc", "-vcodec", "copy", "-c", "copy", "-crf", "50", output]);
|
|
}
|
|
catch (_b) {
|
|
console.warn("Failed to transmux to m4a (hq), download as mp3 (hq) instead.");
|
|
FFMPEG.path = null;
|
|
return [2 /*return*/, this.m3uReadableStream(trackResolvable)];
|
|
}
|
|
return [3 /*break*/, 12];
|
|
case 5: return [4 /*yield*/, fetch(m3uLink, { headers: headers }).then(function (r) { return r.text(); })];
|
|
case 6:
|
|
m3u = _a.sent();
|
|
urls = m3u.match(/(http).*?(?=\s)/gm);
|
|
chunks = [];
|
|
i = 0;
|
|
_a.label = 7;
|
|
case 7:
|
|
if (!(i < urls.length)) return [3 /*break*/, 10];
|
|
return [4 /*yield*/, fetch(urls[i], { headers: headers }).then(function (r) { return r.arrayBuffer(); })];
|
|
case 8:
|
|
arrayBuffer = _a.sent();
|
|
chunkPath = path.join(destDir, "".concat(i, ".").concat(transcoding.type));
|
|
fs.writeFileSync(chunkPath, Buffer.from(arrayBuffer));
|
|
chunks.push(chunkPath);
|
|
_a.label = 9;
|
|
case 9:
|
|
i++;
|
|
return [3 /*break*/, 7];
|
|
case 10: return [4 /*yield*/, this.mergeFiles(chunks, output)];
|
|
case 11:
|
|
_a.sent();
|
|
_a.label = 12;
|
|
case 12:
|
|
stream = stream_1.Readable.from(fs.readFileSync(output));
|
|
Util.removeDirectory(destDir);
|
|
return [2 /*return*/, { stream: stream, type: transcoding.type }];
|
|
}
|
|
});
|
|
}); };
|
|
this.webToNodeStream = function (webStream) {
|
|
var reader = webStream.getReader();
|
|
return new stream_1.Readable({
|
|
read: function () {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
var _a, done, value;
|
|
return __generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0: return [4 /*yield*/, reader.read()];
|
|
case 1:
|
|
_a = _b.sent(), done = _a.done, value = _a.value;
|
|
if (done) {
|
|
this.push(null);
|
|
}
|
|
else {
|
|
this.push(value);
|
|
}
|
|
return [2 /*return*/];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
};
|
|
/**
|
|
* Downloads the mp3 stream of a track.
|
|
*/
|
|
this.downloadTrackStream = function (trackResolvable, title, dest) { return __awaiter(_this, void 0, void 0, function () {
|
|
var result, track, transcodings, transcoding, url, headers, stream_2, type, stream, fileName, writeStream;
|
|
var _this = this;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, this.resolveTrack(trackResolvable)];
|
|
case 1:
|
|
track = _a.sent();
|
|
return [4 /*yield*/, this.sortTranscodings(track, "progressive")];
|
|
case 2:
|
|
transcodings = _a.sent();
|
|
if (!!transcodings.length) return [3 /*break*/, 4];
|
|
return [4 /*yield*/, this.m3uReadableStream(trackResolvable)];
|
|
case 3:
|
|
result = _a.sent();
|
|
return [3 /*break*/, 7];
|
|
case 4:
|
|
transcoding = transcodings[0];
|
|
return [4 /*yield*/, this.getStreamLink(transcoding)];
|
|
case 5:
|
|
url = _a.sent();
|
|
headers = this.api.headers;
|
|
return [4 /*yield*/, fetch(url, { headers: headers }).then(function (r) { return _this.webToNodeStream(r.body); })];
|
|
case 6:
|
|
stream_2 = _a.sent();
|
|
type = transcoding.format.mime_type.startsWith('audio/mp4; codecs="mp4a') ? "m4a" : "mp3";
|
|
result = { stream: stream_2, type: type };
|
|
_a.label = 7;
|
|
case 7:
|
|
stream = result.stream;
|
|
fileName = path.extname(dest) ? dest : path.join(dest, "".concat(title, ".").concat(result.type));
|
|
writeStream = fs.createWriteStream(fileName);
|
|
stream.pipe(writeStream);
|
|
return [4 /*yield*/, new Promise(function (resolve) { return stream.on("end", function () { return resolve(); }); })];
|
|
case 8:
|
|
_a.sent();
|
|
return [2 /*return*/, fileName];
|
|
}
|
|
});
|
|
}); };
|
|
/**
|
|
* Downloads a track on Soundcloud.
|
|
*/
|
|
this.downloadTrack = function (trackResolvable, dest) { return __awaiter(_this, void 0, void 0, function () {
|
|
var folder, track, downloadObj, result, arrayBuffer, _a;
|
|
return __generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0:
|
|
if (!dest)
|
|
dest = "./";
|
|
folder = path.extname(dest) ? path.dirname(dest) : dest;
|
|
if (!fs.existsSync(folder))
|
|
fs.mkdirSync(folder, { recursive: true });
|
|
return [4 /*yield*/, this.resolveTrack(trackResolvable)];
|
|
case 1:
|
|
track = _b.sent();
|
|
if (!(track.downloadable === true)) return [3 /*break*/, 8];
|
|
_b.label = 2;
|
|
case 2:
|
|
_b.trys.push([2, 6, , 7]);
|
|
return [4 /*yield*/, this.api.getV2("/tracks/".concat(track.id, "/download"))];
|
|
case 3:
|
|
downloadObj = _b.sent();
|
|
return [4 /*yield*/, fetch(downloadObj.redirectUri)];
|
|
case 4:
|
|
result = _b.sent();
|
|
dest = path.extname(dest) ? dest : path.join(dest, "".concat(track.title.replace(/[\\/:*?\"<>|]/g, ""), ".").concat(result.headers["x-amz-meta-file-type"]));
|
|
return [4 /*yield*/, result.arrayBuffer()];
|
|
case 5:
|
|
arrayBuffer = _b.sent();
|
|
fs.writeFileSync(dest, Buffer.from(arrayBuffer, "binary"));
|
|
return [2 /*return*/, dest];
|
|
case 6:
|
|
_a = _b.sent();
|
|
return [2 /*return*/, this.downloadTrackStream(track, track.title.replace(/[\\/:*?\"<>|]/g, ""), dest)];
|
|
case 7: return [3 /*break*/, 9];
|
|
case 8: return [2 /*return*/, this.downloadTrackStream(track, track.title.replace(/[\\/:*?\"<>|]/g, ""), dest)];
|
|
case 9: return [2 /*return*/];
|
|
}
|
|
});
|
|
}); };
|
|
/**
|
|
* Downloads an array of tracks.
|
|
*/
|
|
this.downloadTracks = function (tracks, dest, limit) { return __awaiter(_this, void 0, void 0, function () {
|
|
var resultArray, i, result, _a;
|
|
return __generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0:
|
|
if (!limit)
|
|
limit = tracks.length;
|
|
resultArray = [];
|
|
i = 0;
|
|
_b.label = 1;
|
|
case 1:
|
|
if (!(i < limit)) return [3 /*break*/, 6];
|
|
_b.label = 2;
|
|
case 2:
|
|
_b.trys.push([2, 4, , 5]);
|
|
return [4 /*yield*/, this.downloadTrack(tracks[i], dest)];
|
|
case 3:
|
|
result = _b.sent();
|
|
resultArray.push(result);
|
|
return [3 /*break*/, 5];
|
|
case 4:
|
|
_a = _b.sent();
|
|
return [3 /*break*/, 5];
|
|
case 5:
|
|
i++;
|
|
return [3 /*break*/, 1];
|
|
case 6: return [2 /*return*/, resultArray];
|
|
}
|
|
});
|
|
}); };
|
|
/**
|
|
* Downloads all the tracks from the search query.
|
|
*/
|
|
this.downloadSearch = function (query, dest, limit) { return __awaiter(_this, void 0, void 0, function () {
|
|
var tracks;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, this.tracks.search({ q: query })];
|
|
case 1:
|
|
tracks = _a.sent();
|
|
return [2 /*return*/, this.downloadTracks(tracks.collection, dest, limit)];
|
|
}
|
|
});
|
|
}); };
|
|
/**
|
|
* Download all liked tracks by a user.
|
|
*/
|
|
this.downloadLikes = function (userResolvable, dest, limit) { return __awaiter(_this, void 0, void 0, function () {
|
|
var tracks;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, this.users.likes(userResolvable, limit)];
|
|
case 1:
|
|
tracks = _a.sent();
|
|
return [2 /*return*/, this.downloadTracks(tracks, dest, limit)];
|
|
}
|
|
});
|
|
}); };
|
|
/**
|
|
* Downloads all the tracks in a playlist.
|
|
*/
|
|
this.downloadPlaylist = function (playlistResolvable, dest, limit) { return __awaiter(_this, void 0, void 0, function () {
|
|
var playlist;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, this.playlists.get(playlistResolvable)];
|
|
case 1:
|
|
playlist = _a.sent();
|
|
return [2 /*return*/, this.downloadTracks(playlist.tracks, dest, limit)];
|
|
}
|
|
});
|
|
}); };
|
|
/**
|
|
* Returns a readable stream to the track.
|
|
*/
|
|
this.streamTrack = function (trackResolvable) { return __awaiter(_this, void 0, void 0, function () {
|
|
var url, readable;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, this.streamLink(trackResolvable, "progressive")];
|
|
case 1:
|
|
url = _a.sent();
|
|
if (!url)
|
|
return [2 /*return*/, this.m3uReadableStream(trackResolvable).then(function (r) { return r.stream; })];
|
|
return [4 /*yield*/, fetch(url, { headers: this.api.headers }).then(function (r) { return r.body; })];
|
|
case 2:
|
|
readable = _a.sent();
|
|
return [2 /*return*/, this.webToNodeStream(readable)];
|
|
}
|
|
});
|
|
}); };
|
|
/**
|
|
* Downloads a track's song cover.
|
|
*/
|
|
this.downloadSongCover = function (trackResolvable, dest, noDL) { return __awaiter(_this, void 0, void 0, function () {
|
|
var folder, track, artwork, title, client_id, url, arrayBuffer;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0:
|
|
if (!dest)
|
|
dest = "./";
|
|
folder = dest;
|
|
if (!fs.existsSync(folder))
|
|
fs.mkdirSync(folder, { recursive: true });
|
|
return [4 /*yield*/, this.resolveTrack(trackResolvable)];
|
|
case 1:
|
|
track = _a.sent();
|
|
artwork = (track.artwork_url ? track.artwork_url : track.user.avatar_url).replace(".jpg", ".png").replace("-large", "-t500x500");
|
|
title = track.title.replace(/[\\/:*?\"<>|]/g, "");
|
|
dest = path.extname(dest) ? dest : path.join(folder, "".concat(title, ".png"));
|
|
return [4 /*yield*/, this.api.getClientId()];
|
|
case 2:
|
|
client_id = _a.sent();
|
|
url = "".concat(artwork, "?client_id=").concat(client_id);
|
|
if (noDL)
|
|
return [2 /*return*/, url];
|
|
return [4 /*yield*/, fetch(url).then(function (r) { return r.arrayBuffer(); })];
|
|
case 3:
|
|
arrayBuffer = _a.sent();
|
|
fs.writeFileSync(dest, Buffer.from(arrayBuffer));
|
|
return [2 /*return*/, dest];
|
|
}
|
|
});
|
|
}); };
|
|
}
|
|
Util.removeDirectory = function (dir) {
|
|
if (!fs.existsSync(dir))
|
|
return;
|
|
fs.readdirSync(dir).forEach(function (file) {
|
|
var current = path.join(dir, file);
|
|
if (fs.lstatSync(current).isDirectory()) {
|
|
Util.removeDirectory(current);
|
|
}
|
|
else {
|
|
fs.unlinkSync(current);
|
|
}
|
|
});
|
|
try {
|
|
fs.rmdirSync(dir);
|
|
}
|
|
catch (error) {
|
|
console.error(error);
|
|
}
|
|
};
|
|
return Util;
|
|
}());
|
|
exports.Util = Util;
|