From f14fcbc07af0ed487edd9a4607dfd786a40d7383 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 30 Aug 2024 16:33:43 -0400 Subject: [PATCH] fix: at least ensure that metadata tags are added to downloaded songs --- src/jobs/generate-album.ts | 33 ++++++++++++------- src/queues/album-queue.ts | 6 ++-- src/routers/v1/trackGroups/{id}/download.ts | 6 +--- .../v1/trackGroups/{id}/generateDownload.ts | 2 +- src/utils/trackGroup.ts | 2 ++ src/utils/tracks.ts | 23 ++++++++++++- 6 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/jobs/generate-album.ts b/src/jobs/generate-album.ts index 113e66afc..9232d430e 100644 --- a/src/jobs/generate-album.ts +++ b/src/jobs/generate-album.ts @@ -12,8 +12,14 @@ import { import { convertAudioToFormat } from "../utils/tracks"; import archiver from "archiver"; import { PassThrough } from "stream"; -import { Track, TrackGroup } from "@mirlo/prisma/client"; +import { + Track, + TrackArtist, + TrackAudio, + TrackGroup, +} from "@mirlo/prisma/client"; import filenamify from "filenamify"; +import prisma from "@mirlo/prisma"; const { MINIO_HOST = "", @@ -41,13 +47,10 @@ const parseFormat = (format: string) => { }; export default async (job: Job) => { - const { - trackGroup, - tracks, - format: formatString, - } = job.data as { - trackGroup: TrackGroup; - tracks: (Track & { audio: { id: string; fileExtension: string } })[]; + const { trackGroup, format: formatString } = job.data as { + trackGroup: TrackGroup & { + tracks: (Track & { audio: TrackAudio; trackArtists: TrackArtist[] })[]; + }; format: string; }; const format = parseFormat(formatString); @@ -72,7 +75,7 @@ export default async (job: Job) => { const profiler = logger.startTimer(); let i = 0; - for await (const track of tracks) { + for await (const track of trackGroup.tracks) { const minioTrackLocation = `${track.audio.id}/original.${track.audio.fileExtension}`; logger.info(`audioId ${track.audio.id}: Fetching ${minioTrackLocation}`); const originalTrackPath = `${tempFolder}/original.${track.audio.fileExtension}`; @@ -82,10 +85,18 @@ export default async (job: Job) => { minioTrackLocation, originalTrackPath ); - progress += (i * 70) / tracks.length; + progress += (i * 70) / trackGroup.tracks.length; i += 1; await job.updateProgress(progress); + const artist = await prisma.artist.findFirst({ + where: { id: trackGroup.artistId }, + }); + + if (!artist) { + throw "Couldn't find artist, weird"; + } + await new Promise((resolve, reject) => { logger.info( `audioId ${track.audio.id}: Processing stream for ${format.format}${ @@ -94,7 +105,7 @@ export default async (job: Job) => { ); convertAudioToFormat( - track.audio.id, + { track, artist, trackGroup }, createReadStream(originalTrackPath), format, `${tempFolder}/${track.order ?? i}-${filenamify(track.title ?? "")}`, diff --git a/src/queues/album-queue.ts b/src/queues/album-queue.ts index 55cf20fd1..0bb15df53 100644 --- a/src/queues/album-queue.ts +++ b/src/queues/album-queue.ts @@ -72,14 +72,12 @@ generateAlbumQueueEvents.on("error", async (error) => { }); export const startGeneratingAlbum = async ( - trackGroup: TrackGroup, - format: string, - tracks: Track[] + trackGroup: TrackGroup & { tracks: Track[] }, + format: string ) => { const job = await generateAlbumQueue.add("generate-album", { trackGroup, format, - tracks, }); return job.id; diff --git a/src/routers/v1/trackGroups/{id}/download.ts b/src/routers/v1/trackGroups/{id}/download.ts index db56f2b82..2fe61398c 100644 --- a/src/routers/v1/trackGroups/{id}/download.ts +++ b/src/routers/v1/trackGroups/{id}/download.ts @@ -91,11 +91,7 @@ export default function () { await minioClient.statObject(trackGroupFormatBucket, zipName); } catch (e) { logger.info("trackGroup doesn't exist yet, start generating it"); - const jobId = await startGeneratingAlbum( - trackGroup, - format, - trackGroup.tracks - ); + const jobId = await startGeneratingAlbum(trackGroup, format); return res.json({ message: "We've started generating the album", result: { jobId }, diff --git a/src/routers/v1/trackGroups/{id}/generateDownload.ts b/src/routers/v1/trackGroups/{id}/generateDownload.ts index 7313612c7..ce66125d1 100644 --- a/src/routers/v1/trackGroups/{id}/generateDownload.ts +++ b/src/routers/v1/trackGroups/{id}/generateDownload.ts @@ -79,7 +79,7 @@ export default function () { return next(); } - await startGeneratingAlbum(trackGroup, format, trackGroup.tracks); + await startGeneratingAlbum(trackGroup, format); return res.json({ message: "Success", diff --git a/src/utils/trackGroup.ts b/src/utils/trackGroup.ts index 30935c644..77143ca04 100644 --- a/src/utils/trackGroup.ts +++ b/src/utils/trackGroup.ts @@ -24,6 +24,7 @@ import { Response } from "express"; import { DefaultArgs } from "@prisma/client/runtime/library"; import { doesTrackGroupBelongToUser } from "./ownership"; import { AppError } from "./error"; +import trackArtists from "../routers/v1/manage/tracks/{trackId}/trackArtists"; export const whereForPublishedTrackGroups = (): Prisma.TrackGroupWhereInput => { return { @@ -341,6 +342,7 @@ export const basicTrackGroupInclude = { tracks: { include: { audio: true, + trackArtists: true, }, where: { deletedAt: null, diff --git a/src/utils/tracks.ts b/src/utils/tracks.ts index 20a979341..8be5766af 100644 --- a/src/utils/tracks.ts +++ b/src/utils/tracks.ts @@ -3,6 +3,13 @@ import { finalAudioBucket, removeObjectsFromBucket } from "../utils/minio"; import ffmpeg from "fluent-ffmpeg"; import logger from "../logger"; import { Readable } from "stream"; +import { + Artist, + Track, + TrackArtist, + TrackAudio, + TrackGroup, +} from "@mirlo/prisma/client"; export const deleteTrack = async (trackId: number) => { await prisma.track.delete({ @@ -47,7 +54,11 @@ const generateDestination = ( }; export const convertAudioToFormat = ( - audioId: string, + content: { + track: Track & { audio: TrackAudio; trackArtists: TrackArtist[] }; + artist: Artist; + trackGroup: TrackGroup; + }, stream: Readable, formatDetails: { format: "wav" | "flac" | "opus" | "mp3"; @@ -58,15 +69,25 @@ export const convertAudioToFormat = ( onError?: (err: unknown) => void, onSuccess?: (dunno: null) => void ) => { + const audioId = content.track.audio.id; const { format, audioBitrate, audioCodec } = formatDetails; logger.info( `audioId ${audioId}: converting ${format} going to ${goingTo} @${audioBitrate}` ); + console.log(content.track.metadata); + let destination = generateDestination(format, goingTo, audioBitrate); const processor = ffmpeg(stream) .noVideo() .toFormat(format) + // FIXME why don't these work? + // .outputOptions("-map_metadata:s:a", "0:s:a") + // .outputOption("-map_metadata:s:a 0:s:a") + // .outputOptions("-map_metadata 0:s") + .outputOptions("-metadata", `title=${content.track.title}`) + .outputOptions("-metadata", `album=${content.trackGroup.title}`) + .outputOptions("-metadata", `artist=${content.artist.name}`) .on("stderr", function (stderrLine) { // logger.info("Stderr output: " +resolve stderrLine); })