110 lines
3.2 KiB
JavaScript
110 lines
3.2 KiB
JavaScript
const got = require("got");
|
|
const cheerio = require("cheerio");
|
|
const time = require("s-ago");
|
|
const u = require("url");
|
|
|
|
/*
|
|
example of what an object is supposed to look like
|
|
|
|
{
|
|
"cover": "<url to the album cover>",
|
|
"track": {
|
|
"name": "<track title>",
|
|
"url": "<url to track on scrobbler/service>"
|
|
"stream": "<url to stream, if available>"
|
|
},
|
|
"artist": {
|
|
"url": "<url to artist on scrobbler/service>"
|
|
"name": "<artist's name>"
|
|
},
|
|
"album": {
|
|
"url": "<url to album on scrobbler/service>",
|
|
"name": "<name of album>"
|
|
},
|
|
"est-timestamp": "<'live' or est. of how long ago>"
|
|
"timestamp": "<actual timestamp, if provided>"
|
|
}
|
|
*/
|
|
|
|
exports.extract = function(user, cb) {
|
|
got(`https://listenbrainz.org/user/${user}/`).then(function(resp) {
|
|
var $ = cheerio.load(resp.body);
|
|
var j = JSON.parse($("#page-react-props")[0].children[0].data).listens[0];
|
|
|
|
if (!j.listened_at) {
|
|
var ta = "live";
|
|
var t = (new Date() * 1);
|
|
} else {
|
|
var ta = time(new Date(j.listened_at * 1000));
|
|
var t = j.listened_at * 1000;
|
|
}
|
|
|
|
if (typeof j.track_metadata.mbid_mapping == "string") {
|
|
var mbid = j.track_metadata.mbid_mapping.release_mbid;
|
|
} else {
|
|
var mbid = null;
|
|
}
|
|
|
|
if (j.track_metadata.release_name !== "None" && typeof j.track_metadata.mbid_mapping == "string") {
|
|
var al = {
|
|
name: (j.track_metadata.release_name || null),
|
|
url: (`https://musicbrainz.org/release/${mbid}` || null)
|
|
};
|
|
} else {
|
|
var al = null;
|
|
}
|
|
|
|
if (toThumb(j.track_metadata.additional_info.origin_url)) {
|
|
var c = toThumb(j.track_metadata.additional_info.origin_url);
|
|
} else if (mbid !== null) {
|
|
var c = `https://coverartarchive.org/release/${mbid}`;
|
|
} else {
|
|
var c = null;
|
|
}
|
|
|
|
cb(null,{
|
|
scrobbler: {
|
|
name: "ListenBrainz",
|
|
user_url: `https://listenbrainz.org/user/${user}/`
|
|
},
|
|
cover: c,
|
|
track: {
|
|
name: (j.track_metadata.track_name || null),
|
|
stream: (j.track_metadata.additional_info.origin_url || null),
|
|
url: (`https://musicbrainz.org/recording/${j.track_metadata.mbid_mapping.recording_mbid}` || null)
|
|
},
|
|
artist: {
|
|
name: (j.track_metadata.artist_name || null),
|
|
url: (`https://musicbrainz.org/artist/${j.track_metadata.mbid_mapping.artist_mbids[0]}` || null)
|
|
},
|
|
album: al,
|
|
"est-timestamp": ta,
|
|
timestamp: t
|
|
});
|
|
}).catch(function(err) {
|
|
if (err.response) {
|
|
if (err.response.statusCode == 404) {
|
|
cb("Profile doesn't exist.", null);
|
|
}
|
|
} else {
|
|
if (err.message && err.message == "Cannot read properties of undefined (reading 'listened_at')") {
|
|
cb("User appears to have no listens.", null)
|
|
} else {
|
|
cb(err, null);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function toThumb(url) {
|
|
if (typeof url !== "string") {return null;}
|
|
switch(u.parse(url, true).host) {
|
|
case "www.youtube.com":
|
|
case "youtube.com":
|
|
case "youtu.be":
|
|
if (u.parse(url, true).host == "youtu.be") {var i = url.split("//")[1].split("/")[1].split("?")[0];} else {var i = url.split("v=")[1].split("&")[0];}
|
|
return `https://i.ytimg.com/vi/${i}/hqdefault.jpg`;
|
|
default:
|
|
return null;
|
|
}
|
|
} |