Implement song tagging
This commit is contained in:
parent
e70ce4a9ca
commit
eb9263972e
2 changed files with 78 additions and 30 deletions
107
index.js
107
index.js
|
@ -1,5 +1,5 @@
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
const { Readable } = require("stream");
|
const { Readable, PassThrough } = require("stream");
|
||||||
const { finished } = require("stream/promises");
|
const { finished } = require("stream/promises");
|
||||||
const { searchMusics } = require('fix-esm').require("node-youtube-music");
|
const { searchMusics } = require('fix-esm').require("node-youtube-music");
|
||||||
const { GetListByKeyword } = require("youtube-search-api");
|
const { GetListByKeyword } = require("youtube-search-api");
|
||||||
|
@ -9,9 +9,10 @@ const path = require("path");
|
||||||
const { readFileSync, writeFileSync } = require("fs");
|
const { readFileSync, writeFileSync } = require("fs");
|
||||||
const io = require('socket.io-client');
|
const io = require('socket.io-client');
|
||||||
const { program } = require('commander');
|
const { program } = require('commander');
|
||||||
|
const NodeID3 = require('node-id3');
|
||||||
|
|
||||||
function pathGenerator({ url, name, channelName }) {
|
function pathGenerator({ url, name, channelName }) {
|
||||||
return path.join(process.env.NEXTCLOUD_FOLDER, `${url}-${skewered(`${name} - ${channelName}`)}.mp3`)
|
return `${url}-${skewered(`${name} - ${channelName}`)}.mp3`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkLastSong({ name, channelName }) {
|
function checkLastSong({ name, channelName }) {
|
||||||
|
@ -28,6 +29,7 @@ function writeLastSong({ name, channelName }) {
|
||||||
|
|
||||||
async function getVideo({ msName, msArtist }) {
|
async function getVideo({ msName, msArtist }) {
|
||||||
let trackData;
|
let trackData;
|
||||||
|
let tags;
|
||||||
|
|
||||||
if (msName != null && msArtist != null) {
|
if (msName != null && msArtist != null) {
|
||||||
trackData = {
|
trackData = {
|
||||||
|
@ -40,6 +42,17 @@ async function getVideo({ msName, msArtist }) {
|
||||||
trackData = await fetch(
|
trackData = await fetch(
|
||||||
`https://${process.env.LASTFM_INSTANCE}/2.0/?method=user.getrecenttracks&user=${process.env.LASTFM_USERNAME}&api_key=${process.env.LASTFM_API_KEY}&format=json&limit=1&extended=1`
|
`https://${process.env.LASTFM_INSTANCE}/2.0/?method=user.getrecenttracks&user=${process.env.LASTFM_USERNAME}&api_key=${process.env.LASTFM_API_KEY}&format=json&limit=1&extended=1`
|
||||||
).then(x => x.json()).then(data => data.recenttracks.track[0]);
|
).then(x => x.json()).then(data => data.recenttracks.track[0]);
|
||||||
|
|
||||||
|
tags = {
|
||||||
|
title: trackData.name,
|
||||||
|
artist: trackData.artist.name,
|
||||||
|
album: trackData.album["#text"],
|
||||||
|
APIC: "./cover.png",
|
||||||
|
userDefinedUrl: [{
|
||||||
|
description: "Last.FM page",
|
||||||
|
url: trackData.url
|
||||||
|
}]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkLastSong({
|
if (checkLastSong({
|
||||||
|
@ -68,8 +81,6 @@ async function getVideo({ msName, msArtist }) {
|
||||||
return skewered(song.title).includes(skewered(trackData.name));
|
return skewered(song.title).includes(skewered(trackData.name));
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(youtubeMusicVideo);
|
|
||||||
|
|
||||||
if (youtubeMusicVideo == null) {
|
if (youtubeMusicVideo == null) {
|
||||||
const videoList = await GetListByKeyword(`${trackData.artist.name} - ${trackData.name}`, false, 1, [
|
const videoList = await GetListByKeyword(`${trackData.artist.name} - ${trackData.name}`, false, 1, [
|
||||||
{type: "video"}
|
{type: "video"}
|
||||||
|
@ -91,7 +102,11 @@ async function getVideo({ msName, msArtist }) {
|
||||||
|
|
||||||
selectedVideo.channelName = selectedVideo.channelName.replace(/\s-\sTopic/ig, "");
|
selectedVideo.channelName = selectedVideo.channelName.replace(/\s-\sTopic/ig, "");
|
||||||
|
|
||||||
return selectedVideo;
|
return {
|
||||||
|
tags,
|
||||||
|
...selectedVideo,
|
||||||
|
albumCover: trackData.image.at(-1)["#text"]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkNextcloud({ url, name, channelName }, nextcloudClient) {
|
async function checkNextcloud({ url, name, channelName }, nextcloudClient) {
|
||||||
|
@ -100,13 +115,12 @@ async function checkNextcloud({ url, name, channelName }, nextcloudClient) {
|
||||||
return await nextcloudClient.exists(fileName);
|
return await nextcloudClient.exists(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadFromCobalt({ url, name, channelName }) {
|
async function downloadFromCobalt({ url }) {
|
||||||
const processor = await fetch(`https://${process.env.COBALT_INSTANCE}/api/json`, {
|
const processor = await fetch(`https://${process.env.COBALT_INSTANCE}/api/json`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
url: `https://youtu.be/${url}`,
|
url: `https://youtu.be/${url}`,
|
||||||
vCodec: "h264",
|
vCodec: "h264",
|
||||||
vQuality: "144",
|
|
||||||
aFormat: "mp3",
|
aFormat: "mp3",
|
||||||
filenamePattern: "basic",
|
filenamePattern: "basic",
|
||||||
isAudioOnly: true,
|
isAudioOnly: true,
|
||||||
|
@ -142,23 +156,37 @@ async function downloadFromCobalt({ url, name, channelName }) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { body } = await fetch(processorURL);
|
const body = Buffer.from(await fetch(processorURL).then(x => x.arrayBuffer()));
|
||||||
|
|
||||||
return {
|
return body;
|
||||||
fileStream: Readable.fromWeb(body),
|
|
||||||
url,
|
|
||||||
name,
|
|
||||||
channelName
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadToNextcloud({ fileStream, url, name, channelName }, nextcloudClient) {
|
async function downloadAlbumCover({ albumCover }) {
|
||||||
await nextcloudClient.createDirectory(process.env.NEXTCLOUD_FOLDER, {
|
const body = Buffer.from(await fetch(albumCover).then(x => x.arrayBuffer()));
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyTags({ fileStream, tags }) {
|
||||||
|
const body = NodeID3.update(tags, fileStream);
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadToNextcloud({ fileStream, url, name, channelName, tags, albumCover }, nextcloudClient) {
|
||||||
|
await nextcloudClient.createDirectory(path.join(process.env.NEXTCLOUD_FOLDER, tags.album), {
|
||||||
recursive: true,
|
recursive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const fileBufferStream = new PassThrough().end(fileStream);
|
||||||
|
|
||||||
|
const albumBufferStream = new PassThrough().end(albumCover);
|
||||||
|
|
||||||
const fileName = pathGenerator({ url, name, channelName });
|
const fileName = pathGenerator({ url, name, channelName });
|
||||||
await finished(fileStream.pipe(nextcloudClient.createWriteStream(fileName)));
|
|
||||||
|
await finished(fileBufferStream.pipe(nextcloudClient.createWriteStream(path.join(process.env.NEXTCLOUD_FOLDER, fileName))));
|
||||||
|
|
||||||
|
await finished(albumBufferStream.pipe(nextcloudClient.createWriteStream(path.join(process.env.NEXTCLOUD_FOLDER, "cover.png"))));
|
||||||
|
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
@ -182,7 +210,6 @@ async function main() {
|
||||||
msName: options.song,
|
msName: options.song,
|
||||||
msArtist: options.artist
|
msArtist: options.artist
|
||||||
});
|
});
|
||||||
console.log(video);
|
|
||||||
|
|
||||||
if (video == null) return dismantle(socket);
|
if (video == null) return dismantle(socket);
|
||||||
|
|
||||||
|
@ -201,23 +228,43 @@ async function main() {
|
||||||
password: process.env.NOTIFICATION_SERVER_PASSWORD
|
password: process.env.NOTIFICATION_SERVER_PASSWORD
|
||||||
})
|
})
|
||||||
|
|
||||||
const cobalt = await downloadFromCobalt(video);
|
const albumCover = await downloadAlbumCover(video);
|
||||||
console.log(cobalt);
|
|
||||||
|
|
||||||
socket.emit('nodeMessage', {
|
socket.emit('nodeMessage', {
|
||||||
message: `Nextcloud upload running - ${cobalt.name} from ${cobalt.channelName}`,
|
message: `Cobalt download starting - ${video.name} from ${video.channelName}`,
|
||||||
password: process.env.NOTIFICATION_SERVER_PASSWORD
|
|
||||||
});
|
|
||||||
|
|
||||||
const nextcloud = await uploadToNextcloud(cobalt, nextcloudClient);
|
|
||||||
console.log(nextcloud);
|
|
||||||
|
|
||||||
socket.emit('nodeMessage', {
|
|
||||||
message: `Nextcloud upload finished - ${cobalt.name} from ${cobalt.channelName}`,
|
|
||||||
password: process.env.NOTIFICATION_SERVER_PASSWORD
|
password: process.env.NOTIFICATION_SERVER_PASSWORD
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const cobalt = await downloadFromCobalt(video);
|
||||||
|
|
||||||
|
socket.emit('nodeMessage', {
|
||||||
|
message: `Cobalt download finished - ${video.name} from ${video.channelName}`,
|
||||||
|
password: process.env.NOTIFICATION_SERVER_PASSWORD
|
||||||
|
});
|
||||||
|
|
||||||
|
const taggedMusic = applyTags({
|
||||||
|
fileStream: cobalt,
|
||||||
|
tags: video.tags
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit('nodeMessage', {
|
||||||
|
message: `Nextcloud upload running - ${video.name} from ${video.channelName}`,
|
||||||
|
password: process.env.NOTIFICATION_SERVER_PASSWORD
|
||||||
|
});
|
||||||
|
|
||||||
|
const nextcloud = await uploadToNextcloud(
|
||||||
|
{
|
||||||
|
...video,
|
||||||
|
fileStream: taggedMusic,
|
||||||
|
albumCover: albumCover
|
||||||
|
},
|
||||||
|
nextcloudClient
|
||||||
|
);
|
||||||
|
|
||||||
|
socket.emit('nodeMessage', {
|
||||||
|
message: `Nextcloud upload finished - ${tags.name} from ${tags.channelName}`,
|
||||||
|
password: process.env.NOTIFICATION_SERVER_PASSWORD
|
||||||
|
})
|
||||||
|
|
||||||
return dismantle(socket);
|
return dismantle(socket);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"dotenv": "^16.4.4",
|
"dotenv": "^16.4.4",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"fix-esm": "^1.0.1",
|
"fix-esm": "^1.0.1",
|
||||||
|
"node-id3": "^0.2.6",
|
||||||
"node-notifier": "^10.0.1",
|
"node-notifier": "^10.0.1",
|
||||||
"node-youtube-music": "^0.10.3",
|
"node-youtube-music": "^0.10.3",
|
||||||
"skewered": "^1.0.0",
|
"skewered": "^1.0.0",
|
||||||
|
|
Loading…
Reference in a new issue