I have a list of hosted audio files for which I would like to get the duration of, without having to download the files themselves.
I can do this by creating a html DOM element <audio>
and extracting the duration with the duration
attribute. This works nicely in the following shinyapp: When clicking on the button "Click me", the duration is returned in an alert.
shinyApp(
ui = fluidPage(
useShinyjs(),
actionButton("btn", "Click me"),
tags$audio(id = "myaudio",
src = "https://download.samplelib.com/mp3/sample-3s.mp3",
type = "audio/mp3", autoplay = NA, controls = NA)
),
server = function(input, output) {
observeEvent(input$btn, {
runjs("alert(myaudio.duration);")
})
}
)
This is the point where I am stuck: How can I leverage this method to extract the duration of multiple (> 1'000) mp3s?
src=
and iterate of a list of mp3s?R
?This answer only works for one audio file
To get the duration of the audio and print it, we need to use js
, an environment in shinyjs
as follows:
Define get_duration
as our JS and specify what happens when the input changes via Shiny.onInputChange
. Here I have also used reactiveValues
to store durations on change.
library(shinyjs)
library(shiny)
get_duration <- 'shinyjs.aud_duration = function(params) {
var duration = myaudio.duration;
Shiny.onInputChange("aud_duration", duration);
}'
ui <- fluidPage(
useShinyjs(),
extendShinyjs(text = get_duration, functions = "aud_duration"),
actionButton("btn", "Click me"),
tags$audio(id = "myaudio",
src = "https://download.samplelib.com/mp3/sample-3s.mp3",
type = "audio/mp3", autoplay = NA, controls = NA),
verbatimTextOutput("aud_duration")
)
server <- function(input, output) {
js$aud_duration()
durations <- reactiveValues(duration = NA)
observeEvent(input$btn,
durations$duration <- input$aud_duration
)
output$aud_duration <- renderText(durations$duration)
}
shinyApp(ui, server)
Thanks to @NelsonGon's answer, which solved part of the problem, I was able to develop a solution to my problem which scales and thus works on multiple urls. It solves the following problems:
get_duration <- function(src){
library(shinyjs)
library(shiny)
get_duration <- 'shinyjs.aud_duration = function(params) {
var duration = myaudio.duration;
Shiny.onInputChange("aud_duration", duration);
}'
ui <- fluidPage(
useShinyjs(),
extendShinyjs(text = get_duration, functions = "aud_duration"),
tags$audio(id = "myaudio",
src = src),
)
server <- function(input, output) {
js$aud_duration()
durations <- reactiveValues(duration = NA)
observe({
invalidateLater(1000)
if(!is.null(isolate(input$aud_duration))){
stopApp(input$aud_duration)
}
})
}
shiny::runGadget(ui, server)
}
it an be run as follows:
get_duration("https://download.samplelib.com/mp3/sample-3s.mp3")
[1] 3.239184