-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CON-537 "poor-mans UUID" Ensure each track file gets a unique CID to avoid re-upload collisions #4631
CON-537 "poor-mans UUID" Ensure each track file gets a unique CID to avoid re-upload collisions #4631
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import ffmpegPath from 'ffmpeg-static' | |
// The typing for the ffmpeg-static model is incorrect | ||
// so this line is here to fix that | ||
const ffmpeg = (ffmpegPath as unknown as { path: string }).path | ||
const uuid = require('uuid/v4') | ||
|
||
/** | ||
* Segments file into equal size chunks without re-encoding. | ||
|
@@ -98,47 +99,74 @@ export function segmentFile( | |
}) | ||
} | ||
|
||
/** | ||
* Call `ffmpeg -i <filepath>` to get audio file information with ffmpeg | ||
* NOTE - ffmpeg requires an output file always, but for our purposes we don't need one | ||
* For now function always resolves using stderr, which is where the current command pipes output | ||
* This function can be made more robust by either adding an output file to the ffmpeg command, or using ffprobe-static instead | ||
*/ | ||
export async function getFileInformation(filePath: string) { | ||
return new Promise((resolve) => { | ||
const proc = spawn(ffmpeg, ['-i', filePath]) | ||
|
||
// capture output | ||
let stderr = '' | ||
proc.stderr.on('data', (data) => (stderr += data.toString())) | ||
|
||
proc.on('close', () => { | ||
resolve(stderr) | ||
}) | ||
}) | ||
} | ||
|
||
/** | ||
* Transcode file into 320kbps mp3 and store in same directory. | ||
* @date 01-27-2022 | ||
* @param {Object} params | ||
* @param {string} params.fileDir the directory of the uploaded track artifact | ||
* @param {string} params.fileName the uploaded track artifact filename | ||
* @param {LogContext} params.logContext the log context used to instantiate a logger | ||
* @returns {Promise<string>} the path to the transcode | ||
* @param fileDir the directory of the uploaded track artifact | ||
* @param fileName the uploaded track artifact filename | ||
* @param logContext the log context used to instantiate a logger | ||
* @returns the path to the newly created transcoded file | ||
*/ | ||
export async function transcodeFileTo320( | ||
fileDir: string, | ||
fileName: string, | ||
{ logContext }: { logContext: LogContext } | ||
) { | ||
): Promise<string> { | ||
const logger = genericLogger.child(logContext) | ||
|
||
const sourcePath = path.resolve(fileDir, fileName) | ||
const targetPath = path.resolve(fileDir, fileName.split('.')[0] + '-dl.mp3') | ||
logger.info(`Transcoding file ${sourcePath}...`) | ||
const destinationPath = path.resolve( | ||
fileDir, | ||
fileName.split('.')[0] + '-dl.mp3' | ||
) | ||
logger.info( | ||
`Transcoding file at ${sourcePath} and saving to ${destinationPath}...` | ||
) | ||
|
||
// Exit if dl-copy file already exists at target path. | ||
if (await fs.pathExists(targetPath)) { | ||
logger.info(`Downloadable copy already exists at ${targetPath}.`) | ||
return targetPath | ||
// Exit if dl-copy file already exists at target path | ||
if (await fs.pathExists(destinationPath)) { | ||
logger.info(`Downloadable copy already exists at ${destinationPath}.`) | ||
return destinationPath | ||
} | ||
|
||
return new Promise((resolve, reject) => { | ||
// https://ffmpeg.org/ffmpeg-formats.html#hls-2 | ||
const args = [ | ||
'-i', | ||
sourcePath, | ||
'-metadata', | ||
`fileName="${fileName}"`, | ||
'-metadata', | ||
`uuid="${uuid()}"`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these 4 lines are the only SUBSTANTIVE changes in this PR |
||
'-ar', | ||
'48000', // TODO - move to configs | ||
'-b:a', | ||
'320k', | ||
// "-vn" flag required to allow track uploading with album art | ||
// https://stackoverflow.com/questions/20193065/how-to-remove-id3-audio-tag-image-or-metadata-from-mp3-with-ffmpeg | ||
'-vn', // skip inclusion of video, process only the audio file without "video" | ||
targetPath | ||
destinationPath | ||
] | ||
logger.debug(`Spawning: ffmpeg ${args}`) | ||
const proc = spawn(ffmpeg, args) | ||
|
||
// capture output | ||
|
@@ -150,18 +178,24 @@ export async function transcodeFileTo320( | |
proc.on('close', (code) => { | ||
async function asyncFn() { | ||
if (code === 0) { | ||
if (await fs.pathExists(targetPath)) { | ||
logger.info(`Transcoded file ${targetPath}`) | ||
resolve(targetPath) | ||
if (await fs.pathExists(destinationPath)) { | ||
logger.info(`Transcoded file ${destinationPath}`) | ||
resolve(destinationPath) | ||
} else { | ||
logger.error('Error when processing file with ffmpeg') | ||
logger.error('Command stdout:', stdout, '\nCommand stderr:', stderr) | ||
reject(new Error('FFMPEG Error')) | ||
const logMsg = | ||
'Error when processing file with ffmpeg' + | ||
`\nCommand stdout: ${stdout}` + | ||
`\nCommand stderr: ${stderr}` | ||
logger.error(logMsg) | ||
reject(new Error(`FFMPEG Error: ${logMsg}`)) | ||
} | ||
} else { | ||
logger.error('Error when processing file with ffmpeg') | ||
logger.error('Command stdout:', stdout, '\nCommand stderr:', stderr) | ||
reject(new Error('FFMPEG Error')) | ||
const logMsg = | ||
'Error when processing file with ffmpeg' + | ||
`\nCommand stdout: ${stdout}` + | ||
`\nCommand stderr: ${stderr}` | ||
logger.error(logMsg) | ||
reject(new Error(`FFMPEG Error: ${logMsg}`)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here and above - only changes are to return error msg out of promise in addition to just logging it |
||
} | ||
} | ||
asyncFn() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only used in tests - was gonna put in test file but wasn't working for some reason so just left here