Get media (mp3) duration

System Information
  • Strapi Version: 3.3.2
  • Operating System: Heruko (with AWS s3upload)
  • Database: MongoDB
  • Node Version: v12.18.4
  • NPM Version: 6.14.6
  • Yarn Version:

Hi Guys,
I’m kinda new to Strapi.
I have an iOS app the gets mp3 files from my Strapi server. I need to get a duration (in seconds/milliseconds) of the media file (mp3) to the JSON response.
I went over the documentations and couldn’t understand how to do it. Any help?

Thank you!

Hello,

You can achieve this by using extensions.


First of all, create the Duration field for Files.

Copy the file ./node_modules/strapi-plugin-upload/models/File.settings.json to ./extensions/upload/models/File.settings.json and add the duration field to attributes:

{
  "info": {
    "name": "file",
    "description": ""
  },
  "options": {
    "timestamps": true
  },
  "attributes": {
    //... in that case it will hold total ms or total seconds.
    "duration":{
      "type": "integer",
      "configurable": false
    }
    //...
  }
}

Second, copy the ./node_modules/strapi-plugin-upload/services/Upload.js file to ./extensions/upload/services/Upload.js , and modify it like this:

Replace code:
const { bytesToKbytes } = require('../utils/file');
With:
const { bytesToKbytes } = require('../../../node_modules/strapi-plugin-upload/utils/file');


Third, find the enhanceFile function, and add this code before its return statement:

Now, make your custom function that will handle the buffer variable and will return the duration. Set the duration to formattedFile.duration.


Result:

2 Likes

Thank you Sunnyson for this help!
I took a different approach but with the same logic, with the help of Raoul Kramer.
I post the code here if anyone will need it in the future.

  1. Creating a duration field in the model

  2. Installing the "got package (npm install got --save)

  3. Using this code in the mian/api/song/model/song.js
    Change the name of the model to whatever you need, in my example it’s model.media

    ‘use strict’;

    const mm = require(‘music-metadata’);
    const got = require(‘got’);

    async function getMp3Metadata(pathOrUrl, parseOption = { duration: true, skipCovers: true }) {
    if (pathOrUrl.startsWith(‘http’)) {
    const body = await got(pathOrUrl).buffer();
    if (body) {
    return await mm.parseBuffer(body, ‘audio/mpeg’, { duration: true, skipCovers: true });
    }
    }
    // This is for AWS absolute URL
    return await mm.parseFile($pathOrUrl, parseOption); //on local file uploads use: return await mm.parseFile(./public/${pathOrUrl}, parseOption); and figure out where the upload directory is stored and replace ./public/
    }

    /**
    // Read the documentation (Strapi’s documentation | Strapi Documentation)
    //to customize this model
    */

    module.exports = {
    lifecycles: {
    async beforeCreate(model) {
    if (model.media) {
    const file = await strapi.plugins[‘upload’].services.upload.fetch({ id: model.media });
    const mp3Meta = await getMp3Metadata(file.url);
    model.duration = mp3Meta.format.duration;
    model.title = mp3Meta.common.title;
    }
    },
    async beforeUpdate(params, model) {
    if (model.media) {
    const file = await strapi.plugins[‘upload’].services.upload.fetch({ id: model.media });
    const mp3Meta = await getMp3Metadata(file.url);
    model.duration = mp3Meta.format.duration;
    model.title = mp3Meta.common.title;
    }
    }
    }
    };

This will parse the mp3 file and get its duration on every update or creation of a new record.

Good luck!

Solution with mp3-duration - npm

File.settings.json
    "duration": {
      "type": "decimal",
      "configurable": false
    },
services/Upload.js

const mp3Duration = require("mp3-duration");



    if (formattedFile.mime.startsWith("audio")) {
      await mp3Duration(readBuffer, (err, duration) => {
        if (!err) {
          formattedFile.duration = duration;
          return _.assign(formattedFile, info, {
            buffer,
          });
        }
      });
    }
    return _.assign(formattedFile, info, {
      buffer,
    });