UNPKG

ashi-smule

Version:

AshiTEAM Smule Song Downloader

235 lines 12.4 kB
"use strict"; /// <reference path="SmuleUserData.ts"/> var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 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) : new P(function (resolve) { resolve(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 (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, 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 }); var SmuleUserData_1 = require("./SmuleUserData"); var SmuleRecording_1 = require("./SmuleRecording"); var SmuleSongChunk = (function () { function SmuleSongChunk() { } return SmuleSongChunk; }()); exports.SmuleSongChunk = SmuleSongChunk; var SmuleUser = (function () { function SmuleUser(screenName, outputFolder) { this.SmuleURL = "https://www.smule.com/"; var os = require('os'); this.m_ScreenName = screenName; this.m_OutputFolder = outputFolder; if (this.m_OutputFolder === undefined || this.m_OutputFolder === null || this.m_OutputFolder == '') { this.m_OutputFolder = os.homedir() + "/AshiSmule/"; } var fse = require('fs-extra'); fse.ensureDir(this.m_OutputFolder, function (err) { if (err) { console.log("Error: " + err); process.exit(1); } }); } SmuleUser.prototype.LoadChunk = function (offset) { var pThis = this; return new Promise(function (resolve, reject) { var https = require('follow-redirects').https; var userDataURL = "https://www.smule.com/" + pThis.m_ScreenName + "/performances/json"; if (offset > 0) userDataURL += "?offset=" + offset.toString(); https.get(userDataURL, function (res, cb) { var sJson = ''; res.on('data', function (chunk) { sJson += chunk; }); res.on('end', function () { try { var userData = SmuleUserData_1.SmuleUserDataProxy.Parse(sJson); var songChunk = new SmuleSongChunk(); songChunk.Songs = userData.list; songChunk.Next_Offset = userData.next_offset; resolve(songChunk); } catch (err) { reject("Invalid screen name: " + pThis.m_ScreenName); } }); }).on("error", function (err) { reject(err); }); }); }; SmuleUser.prototype.GetHTMLPage = function (sUrl) { var pThis = this; return new Promise(function (resolve, reject) { var https = require('follow-redirects').https; https.get(sUrl, function (res, cb) { var sHTML = ''; res.on('data', function (chunk) { sHTML += chunk; }); res.on('end', function () { resolve(sHTML); }); }).on("error", function (err) { reject(err); }); }); }; SmuleUser.prototype.GetSmuleRecording = function (song) { var pRec = new SmuleRecording_1.SmuleRecording(); pRec.Init1(song, this.m_OutputFolder); return pRec; }; SmuleUser.prototype.DownloadAllSongsInParts = function () { return __awaiter(this, void 0, void 0, function () { var i, chalk, ora, spinner, logUpdate, jsdom, JSDOM, userData, userDataURL, userDataURLToUse, done, i_1, j, k, totalSoFar, totalDownloaded, songChunk, recordings, sCollabHTML, dom, aElements, pCollabs, songName, songURL, imageURL, singers, collabElement, test, temp, parentElement, pH4, artists, pRec, err_1, errMsg; return __generator(this, function (_a) { switch (_a.label) { case 0: chalk = require('chalk'); ora = require('ora'); spinner = ora(); logUpdate = require('log-update'); jsdom = require("jsdom"); JSDOM = jsdom.JSDOM; _a.label = 1; case 1: _a.trys.push([1, 14, , 15]); userData = void 0; userDataURL = "https://www.smule.com/" + this.m_ScreenName + "/performances/json"; userDataURLToUse = userDataURL; done = false; j = void 0; k = void 0; totalSoFar = 0; totalDownloaded = 0; spinner.text = "" + chalk.dim('Fetching all songs for ' + this.m_ScreenName + '...'); spinner.start(); songChunk = new SmuleSongChunk(); songChunk.Next_Offset = 0; _a.label = 2; case 2: return [4 /*yield*/, this.LoadChunk(songChunk.Next_Offset)]; case 3: songChunk = _a.sent(); if (totalSoFar > 0) spinner.start(); spinner.text = chalk.dim('So far found ' + totalSoFar.toString() + ' songs'); recordings = []; i_1 = 0; _a.label = 4; case 4: if (!(i_1 < songChunk.Songs.length)) return [3 /*break*/, 8]; if (!(songChunk.Songs[i_1].child_count > 0)) return [3 /*break*/, 6]; spinner.text = chalk.dim('Getting collabs of ' + songChunk.Songs[i_1].title); return [4 /*yield*/, this.GetHTMLPage(this.SmuleURL + songChunk.Songs[i_1].web_url)]; case 5: sCollabHTML = _a.sent(); dom = new JSDOM(sCollabHTML); aElements = dom.window.document.querySelectorAll('a'); pCollabs = new Array(0); for (j = 0; j < aElements.length; ++j) { if ((" " + aElements[j].className + " ").indexOf(" " + "album-art playable" + " ") > -1) { pCollabs.push(aElements[j]); } } songName = songChunk.Songs[i_1].title; spinner.text = chalk.dim('Found ' + pCollabs.length + ' collaborations for song ' + songName); totalSoFar += pCollabs.length; for (j = 0; j < pCollabs.length; ++j) { songURL = null; imageURL = null; singers = []; collabElement = pCollabs[j]; test = collabElement.outerHTML; if (collabElement.href !== undefined) { songURL = this.SmuleURL + collabElement.href; } if (collabElement.style !== undefined) { temp = collabElement.style.cssText; temp = temp.replace("background-image: url(", "").trim(); if (temp.endsWith(");")) temp = temp.substring(0, temp.length - 2); imageURL = temp; } parentElement = collabElement.parentElement; pH4 = parentElement.querySelectorAll("h4"); if (pH4.length == 1) { artists = pH4[0].textContent.trim(); singers = artists.split('+'); } pRec = new SmuleRecording_1.SmuleRecording(); pRec.Init2(songChunk.Songs[i_1].title, songURL, imageURL, singers, songChunk.Songs[i_1].type, this.m_OutputFolder); recordings.push(pRec); } return [3 /*break*/, 7]; case 6: totalSoFar++; recordings.push(this.GetSmuleRecording(songChunk.Songs[i_1])); _a.label = 7; case 7: ++i_1; return [3 /*break*/, 4]; case 8: spinner.succeed(chalk.green("So far found " + totalSoFar + " songs for " + this.m_ScreenName)); k = 0; _a.label = 9; case 9: if (!(k < recordings.length)) return [3 /*break*/, 12]; return [4 /*yield*/, recordings[k].Download()]; case 10: if (_a.sent()) totalDownloaded++; _a.label = 11; case 11: ++k; return [3 /*break*/, 9]; case 12: if (songChunk.Next_Offset > 0) return [3 /*break*/, 2]; _a.label = 13; case 13: return [2 /*return*/, { "totalDownloaded": totalDownloaded, "totalFound": totalSoFar }]; case 14: err_1 = _a.sent(); errMsg = "Failed to load all songs for " + this.m_ScreenName + ": " + err_1; spinner.fail("" + chalk.red.bgWhite(errMsg)); throw errMsg; case 15: return [2 /*return*/]; } }); }); }; return SmuleUser; }()); exports.SmuleUser = SmuleUser; //# sourceMappingURL=SmuleUser.js.map