rx3-to-mastodon/libs.js
2020-05-01 11:29:58 +02:00

286 lines
7.6 KiB
JavaScript

const fs = require('fs')
const request = require('request')
const Discogs = require('disconnect').Client
const Masto = require('mastodon')
const mongo = require('./mongo')
const config = require('./config')
// Instanciation de Mastodon
const M = new Masto({
access_token: config.mastodonToken,
api_url: config.mastondonApi
})
// Instanciation de Disgocs
const dis = new Discogs({ userToken: config.discogsToken }).database()
/**
* Fonction permettant de sauvegarder en historique le morceau en cours de diffusion
* @param {Object} values
* @param {Function} callback
*/
const saveSong = (values, callback) => {
mongo.Histories
.find({})
.sort({
createdAt: 'desc'
})
.limit(1)
.exec(function (err, last) {
if (err ||
last.length === 0 ||
(last[0] !== undefined && last[0].stringId !== values.stringId)
) {
console.log(config.colors.FgBlue, '[INFO][saveSong] song not found:', values.title, values.artist, config.colors.Reset)
const history = new mongo.Histories(values)
history.save(callback)
}
})
}
/**
* Fonction permettant de retrouver le dernier morceau sauvegardé en base
* @param {Function} callback
*/
const getLastSong = (callback) => {
mongo.Histories
.find({})
.sort({
createdAt: 'desc'
})
.limit(1)
.exec(function (err, last) {
if (err) {
callback(err)
return false
}
callback(null, last)
})
}
/**
* Fonction permettant de retrouver la cover d'un titre Rx3
* @param {Object} song
* @param {Function} callback
*/
const getRx3Cover = (song, callback) => {
let cover = null
// Cas des GSU
if (song.title.indexOf('GSU') === 0) {
const year = song.title.split(' ')[1]
if (!isNaN(parseInt(year))) {
cover = `${config.rx3CoverBaseUrl}gsu${year}.jpg`
}
}
callback(null, cover)
}
/**
* Fonction permettant de chercher sur Discogs la pochette d'un album
* @param {Object} song
* @param {Function} callback
*/
const getRemoteCover = (song, callback) => {
if (config.rx3List.indexOf(song.artist) !== -1) {
getRx3Cover(song, callback)
return true
}
// Si c'est KOЯN on remplace par KORN (merci discogs)
if (song.artist === 'KOЯN') {
song.artist = 'KORN'
}
dis.search({ q: song.album, artist: song.artist, page: 1, per_page: 1 }, (err, res) => {
if (err) {
console.log(config.colors.FgRed, 'ERR:', err, config.colors.Reset)
callback(err)
return false
}
// Une pochette est trouvée
if (res.results && res.results.length === 1) {
callback(null, res.results[0].cover_image)
} else {
console.log(config.colors.FgBlue, '[INFO] No cover found for:', song.album, song.artist, config.colors.Reset)
callback(null, null)
}
})
}
/**
* Fonction permettant de retourner l'url de la pochette d'un album
* @param {Object} song
* @param {Function} callback
*/
const findCover = (song, callback) => {
mongo.Metadata.findOne({
stringId: song.stringId
})
.exec((err, metadata) => {
if (err) {
callback(err)
return false
}
// Ce morceau est déjà en base
if (metadata) {
// On a déjà une pochette pour ce morceau
if (metadata.cover) {
console.log(config.colors.FgBlue, '[INFO][findCover] cover exists:', metadata._id, metadata.cover, config.colors.Reset)
callback(null, metadata.cover)
return true
}
// Aucune pochette trouvée, on interroge Discogs (peut être que cette fois ils auront une cover...)
getRemoteCover(song, (err, coverUrl) => {
if (err) {
callback(err)
return false
}
console.log(config.colors.FgBlue, '[INFO][findCover] cover does not exists but found on discogs:', coverUrl, config.colors.Reset)
metadata.updateOne({ cover: coverUrl })
callback(null, coverUrl)
})
} else { // Première fois que ce morceau est jouée, on rempli sa fiche
getRemoteCover(song, (err, coverUrl) => {
if (err) {
callback(err)
return false
}
console.log(config.colors.FgBlue, '[INFO][findCover] cover does not exists but found on discogs (2):', coverUrl, config.colors.Reset)
song.cover = coverUrl
const metadata = new mongo.Metadata(song)
metadata.save()
callback(null, coverUrl)
})
}
})
}
/**
* Fonction permettant de récupérer le titre diffusé
* @param {Funtion} callback
*/
const getStream = (callback) => {
request.get(config.streamUrl,
(error, response, body) => {
if (!error && response.statusCode === 200) {
let res = null
try {
const _body = JSON.parse(body)
res = {
artist: _body.data[0].track.artist,
title: _body.data[0].track.title,
album: _body.data[0].track.album,
royaltytrackid: _body.data[0].track.royaltytrackid,
id: _body.data[0].track.id,
stringId: _body.data[0].track.id || `FAKEID_${_body.data[0].track.artist}_${_body.data[0].track.title}_${_body.data[0].track.album}`,
playlistId: _body.data[0].track.playlist ? _body.data[0].track.playlist.id : null,
thumbCover: _body.data[0].track.imageurl
}
if (res !== null && res.artist !== undefined && res.title !== undefined) {
callback(null, res)
} else {
error = true
}
} catch (e) {
error = e
console.error('getStream error:', error)
}
}
if (error) {
callback(error)
}
})
}
/**
* Fonction permettant de télécharger la pochette d'un album selon une URL donnée
* @param {String} coverUrl
* @param {Function} callback
*/
const getMedia = (coverUrl, callback) => {
const dest = '/tmp/attachment.jpg'
const file = fs.createWriteStream(dest)
try {
request({
uri: coverUrl,
headers: {
'Cache-Control': 'max-age=0',
Connection: 'keep-alive',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
})
.on('error', (error) => {
console.log(config.colors.FgRed, 'ERR:', error, config.colors.Reset)
callback(error)
})
.pipe(file)
.on('finish', () => {
callback(null, dest)
})
} catch (error) {
callback(error)
}
}
/**
* Fonction formattant le texte à publier
* @param {Object} values
*/
const formatMessage = (values) => {
return `#rx3 #nowplaying ${values.artist} - ${values.title}`
}
/**
* Fonction publiant un message (et média si attaché) sur Mastdon
* @param {Object} song
* @param {String} cover
*/
const publishMessage = (song, cover) => {
const status = formatMessage(song)
const callback = (err, res) => {
if ( err ) {
console.log(config.colors.FgRed, 'ERR on publishMessage:', err, config.colors.Reset)
}
}
if (cover) {
getMedia(cover, (err, dest) => {
if (err) {
M.post('statuses', { status }, callback)
} else {
M.post('media', { file: fs.createReadStream(dest) }).then(resp => {
const id = resp.data.id
M.post('statuses', { status, media_ids: [id] }, callback)
})
.catch( () => {
M.post('statuses', { status }, callback)
})
}
})
} else {
M.post('statuses', { status }, callback)
}
}
module.exports = {
saveSong: saveSong,
getLastSong: getLastSong,
findCover: findCover,
getStream: getStream,
getMedia: getMedia,
formatMessage: formatMessage,
publishMessage: publishMessage
}