damonjs
Version:
A modified Shoukaku wrapper with enhanced queue support.
194 lines (193 loc) • 8.31 kB
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DamonJsTrack = void 0;
const Interfaces_1 = require("../../Modules/Interfaces");
class DamonJsTrack {
constructor(raw, requester) {
this.raw = raw;
this.resolvedBySource = false;
this.damonjs = undefined;
this.data = new Map();
this.encoded = raw.encoded;
this.sourceName = raw.info.sourceName;
this.title = raw.info.title;
this.uri = raw.info.uri;
this.identifier = raw.info.identifier;
this.isSeekable = raw.info.isSeekable;
this.isStream = raw.info.isStream;
this.author = raw.info.author;
this.length = raw.info.length;
this.position = raw.info.position;
this.artworkUrl = raw.info.artworkUrl;
this.isrc = raw.info.isrc;
this.realUri = Interfaces_1.SupportedSources.includes(this.sourceName) && this.uri ? this.uri : null;
this.pluginInfo = raw.pluginInfo;
this.requester = requester;
}
/**
* Get json of this track
* @returns {RawTrack}
*/
getRaw() {
return {
encoded: this.encoded,
info: {
identifier: this.identifier,
isSeekable: this.isSeekable,
author: this.author,
length: this.length,
isStream: this.isStream,
position: this.position,
title: this.title,
uri: this.uri,
isrc: this.isrc,
artworkUrl: this.artworkUrl,
sourceName: this.sourceName,
},
pluginInfo: this.pluginInfo,
_raw: this.raw,
};
}
/**
* Set damonjs instance
* @param damonjs DamonJs instance
* @returns DamonJsTrack
*/
setDamonJs(damonjs) {
var _a;
this.damonjs = damonjs;
if (this.sourceName === 'youtube' && this.identifier)
this.artworkUrl = `https://img.youtube.com/vi/${this.identifier}/${(_a = damonjs.DamonJsOptions.defaultYoutubeThumbnail) !== null && _a !== void 0 ? _a : 'hqdefault'}.jpg`;
return this;
}
/**
* Whether the track is ready to play or need to be solved
*/
get readyToPlay() {
return (this.damonjs !== undefined &&
!!this.encoded &&
!!this.sourceName &&
!!this.identifier &&
!!this.author &&
!!this.length &&
!!this.title &&
!!this.uri &&
!!this.realUri);
}
/**
* Resolve the track
* @param options Resolve options
* @returns Promise<DamonJsTrack>
*/
resolve(options) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
if (!this.damonjs)
throw new Interfaces_1.DamonJsError(1, 'DamonJs is not set');
if (this.damonjs.DamonJsOptions.trackResolver &&
typeof this.damonjs.DamonJsOptions.trackResolver === 'function' &&
(yield this.damonjs.DamonJsOptions.trackResolver.bind(this)(options)))
return this;
const resolveSource = (_b = (_a = this.damonjs.DamonJsOptions) === null || _a === void 0 ? void 0 : _a.sourceForceResolve) === null || _b === void 0 ? void 0 : _b.includes(this.sourceName);
const { forceResolve, overwrite } = options ? options : { forceResolve: false, overwrite: false };
if (!forceResolve && this.readyToPlay)
return this;
if (resolveSource && this.resolvedBySource)
return this;
if (resolveSource) {
this.resolvedBySource = true;
return this;
}
this.damonjs.emit(Interfaces_1.Events.Debug, options.player, `Resolving ${this.sourceName} track ${this.title}; Source: ${this.sourceName}`);
const result = (yield this.getTrack(options.player, Interfaces_1.SourceIDs[this.damonjs.DamonJsOptions.defaultSearchEngine || 'youtube'] || 'yt').catch(() => null)) || (yield this.getTrack(options.player, 'youtube').catch(() => null));
if (!result)
throw new Interfaces_1.DamonJsError(2, 'No results found');
this.encoded = result.encoded;
this.realUri = result.info.uri || null;
this.length = result.info.length;
if (overwrite || resolveSource) {
this.title = result.info.title;
this.identifier = result.info.identifier;
this.isSeekable = result.info.isSeekable;
this.author = result.info.author;
this.length = result.info.length;
this.isStream = result.info.isStream;
this.uri = result.info.uri;
}
return this;
});
}
getTrackScore(track) {
let score = 0;
const title = track.info.title.toLowerCase();
const author = track.info.author.toLowerCase();
if (track.info.sourceName === 'youtube') {
// Prefer "Topic" channels
if (author.includes('- topic'))
score += 3;
// Lower score for music videos
if (title.includes('official video') ||
title.includes('music video') ||
title.includes('official mv') ||
title.includes('(video)') ||
title.includes('[video]')) {
score -= 2;
}
// Prefer "audio" tracks
if (title.includes('audio') || title.includes('lyric'))
score += 1;
}
else if (track.info.sourceName === 'soundcloud') {
// Prefer "audio" tracks
if (author.includes('official'))
score += 2;
if (title.includes('original mix'))
score += 3;
if (title.includes('remix'))
score -= 1;
if (title.includes('repost'))
score -= 2;
if (title.includes('cover'))
score -= 1;
}
return score;
}
filterPlayableTrack(track) {
if (track.info.sourceName === 'soundcloud' && track.info.identifier.includes('/preview/')) {
return false;
}
return true;
}
getTrack(player, source) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.damonjs)
throw new Interfaces_1.DamonJsError(1, 'DamonJs is not set');
const query = [this.author, this.title].filter((x) => !!x).join(' - ');
const result = yield player.search(`${query}`, { requester: this.requester, engine: source });
if (!result || !result.tracks.length)
throw new Interfaces_1.DamonJsError(2, 'No results found');
const rawTracks = result.tracks.map((x) => x.getRaw()._raw);
// Filter out preview tracks
const filteredTracks = rawTracks.filter((track) => this.filterPlayableTrack(track));
if (!filteredTracks.length)
throw new Interfaces_1.DamonJsError(2, 'No non-preview tracks found');
const sortedTracks = filteredTracks.sort((a, b) => {
// Prioritize "Topic" channels and tracks without "Official Video" in title
const aScore = this.getTrackScore(a);
const bScore = this.getTrackScore(b);
return bScore - aScore;
});
return sortedTracks[0];
});
}
}
exports.DamonJsTrack = DamonJsTrack;