diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000..c45ec2f --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,56 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + paths: ['r-package/**'] + pull_request: + branches: [main, master] + paths: ['r-package/**'] + +name: R-CMD-check.yaml + +permissions: read-all + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + working-directory: r-package + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + working-directory: r-package + upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/r-package/DESCRIPTION b/r-package/DESCRIPTION index 092daee..a6cbc32 100644 --- a/r-package/DESCRIPTION +++ b/r-package/DESCRIPTION @@ -1,14 +1,21 @@ Package: shinymedia -Title: Multimedia Input/Output Controls for Shiny +Title: Multimedia Input/Output Controls for 'Shiny' Version: 0.0.0.9000 -Authors@R: - person("Joe", "Cheng", , "joe@posit.co", role = c("aut", "cre")) -Description: What the package does (one paragraph). +Authors@R: c( + person("Joe", "Cheng", , "joe@posit.co", role = c("aut", "cre")), + person("Posit Software, PBC", role = c("cph", "fnd")) + ) +Description: Extends the 'Shiny' web framework with controls for + multimedia input/output. Includes a video input control and an audio + output. License: MIT + file LICENSE -Encoding: UTF-8 -Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +URL: https://github.com/posit-dev/shinymedia +BugReports: https://github.com/posit-dev/shinymedia/issues Imports: + base64enc, htmltools, rlang, shiny +Encoding: UTF-8 +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.3.2 diff --git a/r-package/NAMESPACE b/r-package/NAMESPACE index eba3eaf..75d022e 100644 --- a/r-package/NAMESPACE +++ b/r-package/NAMESPACE @@ -2,11 +2,6 @@ export(audio_spinner) export(input_video_clip) -import(base64enc) import(htmltools) -importFrom(htmltools,div) -importFrom(htmltools,htmlDependency) -importFrom(htmltools,tag) -importFrom(htmltools,tagList) -importFrom(htmltools,tags) +importFrom(base64enc,base64encode) importFrom(shiny,icon) diff --git a/r-package/R/audio_spinner.R b/r-package/R/audio_spinner.R index c948184..d6313f1 100644 --- a/r-package/R/audio_spinner.R +++ b/r-package/R/audio_spinner.R @@ -1,46 +1,66 @@ #' Create an audio spinner #' -#' @param src The source URL or URI for the audio file. This should be used for remote resources -#' or data URIs. If provided, this takes precedence over `con`. -#' @param con An optional connection object or file path for local audio files. This is ignored -#' if `src` is provided. Use this for reading local files securely. -#' @param rpm The speed of the spinner, in clockwise revolutions per minute. Default is 10 RPM. -#' Use 0 to disable rotation, or a negative value to rotate counter-clockwise. -#' @param gap The gap between the blades of the spinner, in radians. Default is pi/5, or 36°. -#' @param stroke The stroke thickness of the individual arcs that make up each blade of the spinner, -#' in pixels. Default is 2.5. -#' @param min_radius The radius of the spinner when there is only silence, in pixels. Default is 30. -#' @param radius_compression The raw `[-1, 1]` amplitude of the audio is compressed using -#' `x^radius_compression` to make the spinner more responsive to quiet sounds. Default is 0.8. -#' Set to 1.0 to disable compression. (Note that this only affects the visualization, not the audio playback.) -#' @param radius_overscan Use this parameter to set the maximum possible radius of the spinner, -#' relative to the width/height of the container. Default is 1.1, meaning the spinner radius -#' will be scaled such that at maximum amplitude, it will be 10% larger than the container -#' (the spinner blades will be clipped). Use larger values if you're expecting generally quiet audio. -#' @param steps The number of concentric arcs that make up each blade of the spinner, not including -#' the central circle. Default is 2. -#' @param blades The number of blades in the spinner. Default is 3. Set to 0 to use concentric circles -#' instead of blades. +#' @param src The source URL or URI for the audio file. This should be used for +#' remote resources or data URIs. If provided, this takes precedence over +#' `con`. +#' @param con An optional connection object or file path for local audio files. +#' This is ignored if `src` is provided. Use this for reading local files +#' securely. +#' @param rpm The speed of the spinner, in clockwise revolutions per minute. +#' Default is 10 RPM. Use 0 to disable rotation, or a negative value to rotate +#' counter-clockwise. +#' @param gap The gap between the blades of the spinner, in radians. Default is +#' pi/5, or 36°. +#' @param stroke The stroke thickness of the individual arcs that make up each +#' blade of the spinner, in pixels. Default is 2.5. +#' @param min_radius The radius of the spinner when there is only silence, in +#' pixels. Default is 30. +#' @param radius_compression The raw `[-1, 1]` amplitude of the audio is +#' compressed using `x^radius_compression` to make the spinner more responsive +#' to quiet sounds. Default is 0.8. Set to 1.0 to disable compression. (Note +#' that this only affects the visualization, not the audio playback.) +#' @param radius_overscan Use this parameter to set the maximum possible radius +#' of the spinner, relative to the width/height of the container. Default is +#' 1.1, meaning the spinner radius will be scaled such that at maximum +#' amplitude, it will be 10% larger than the container (the spinner blades +#' will be clipped). Use larger values if you're expecting generally quiet +#' audio. +#' @param steps The number of concentric arcs that make up each blade of the +#' spinner, not including the central circle. Default is 2. +#' @param blades The number of blades in the spinner. Default is 3. Set to 0 to +#' use concentric circles instead of blades. #' @param width The width of the spinner in CSS units. Default is "125px". #' @param height The height of the spinner in CSS units. Default is "125px". -#' @param autoplay Whether to autoplay the audio. Default is TRUE. Note that many browsers will not -#' allow autoplaying audio without user interaction; if autoplay fails, the spinner will show a -#' tooltip instructing the user to tap or click to start the audio. -#' @param autodismiss Whether to remove the spinner after the audio finishes playing. Default is FALSE. -#' @param class The class of the spinner. Default is "mx-auto" which horizontally centers the element -#' inside its container (assuming Bootstrap is loaded). -#' @param ... Additional attributes for the spinner, to be added directly to the `` element. +#' @param autoplay Whether to autoplay the audio. Default is TRUE. Note that +#' many browsers will not allow autoplaying audio without user interaction; if +#' autoplay fails, the spinner will show a tooltip instructing the user to tap +#' or click to start the audio. +#' @param autodismiss Whether to remove the spinner after the audio finishes +#' playing. Default is FALSE. +#' @param class The class of the spinner. Default is "mx-auto" which +#' horizontally centers the element inside its container (assuming Bootstrap +#' is loaded). +#' @param ... Additional attributes for the spinner, to be added directly to the +#' `` element. #' -#' @return An HTML tag object representing the audio spinner. -#' @import htmltools -#' @import base64enc +#' @return An HTML `` tag object representing the audio spinner. #' -#' @examples +#' @examplesIf rlang::is_interactive() #' # Using a URL -#' audio_spinner(src = "https://example.com/audio.mp3", rpm = 15, width = "200px", height = "200px") +#' audio_spinner( +#' src = "https://example.com/audio.mp3", +#' rpm = 15, +#' width = "200px", +#' height = "200px" +#' ) #' #' # Using a local file -#' audio_spinner(con = "path/to/local/audio.mp3", rpm = 20, width = "150px", height = "150px") +#' audio_spinner( +#' con = "path/to/local/audio.mp3", +#' rpm = 20, +#' width = "150px", +#' height = "150px" +#' ) #' #' @export audio_spinner <- function( diff --git a/r-package/R/html_deps.R b/r-package/R/html_deps.R index 57b59ca..2383a51 100644 --- a/r-package/R/html_deps.R +++ b/r-package/R/html_deps.R @@ -1,6 +1,4 @@ -#' Create HTML dependency for multimodal component -#' -#' @importFrom htmltools htmlDependency +# HTML dependency for multimodal component multimodal_dep <- function() { htmlDependency( name = "multimodal", diff --git a/r-package/R/input_video_clip.R b/r-package/R/input_video_clip.R index 8342346..bd76d2b 100644 --- a/r-package/R/input_video_clip.R +++ b/r-package/R/input_video_clip.R @@ -1,28 +1,33 @@ #' A video clip input control that records short videos from webcam #' #' @param inputId The input slot that will be used to access the value. -#' @param reset_on_record Whether to reset the video clip input value when recording starts. If -#' TRUE, the video clip input value will become NULL at the moment the -#' Record button is pressed; if FALSE, the value will not change until -#' the user stops recording. Default is TRUE. -#' @param mime_type The MIME type of the video clip to record. By default, this is NULL, -#' which means the browser will choose a suitable MIME type for video +#' @param reset_on_record Whether to reset the video clip input value when +#' recording starts. If TRUE, the video clip input value will become NULL at +#' the moment the Record button is pressed; if FALSE, the value will not +#' change until the user stops recording. Default is TRUE. +#' @param mime_type The MIME type of the video clip to record. By default, this +#' is NULL, which means the browser will choose a suitable MIME type for video #' recording. Common MIME types include 'video/webm' and 'video/x-matroska'. -#' @param video_bits_per_second The target video bitrate in bits per second. By default, this is NULL, -#' which means the browser will choose a suitable bitrate for video -#' recording (according to the spec, 2,500,000). This is only a -#' suggestion; the browser may choose a different bitrate. -#' @param audio_bits_per_second The target audio bitrate in bits per second. By default, this is NULL, -#' which means the browser will choose a suitable bitrate for audio -#' recording. This is only a suggestion; the browser may choose a different -#' bitrate. +#' @param video_bits_per_second The target video bitrate in bits per second. By +#' default, this is NULL, which means the browser will choose a suitable +#' bitrate for video recording (according to the spec, 2,500,000). This is +#' only a suggestion; the browser may choose a different bitrate. +#' @param audio_bits_per_second The target audio bitrate in bits per second. By +#' default, this is NULL, which means the browser will choose a suitable +#' bitrate for audio recording. This is only a suggestion; the browser may +#' choose a different bitrate. #' @param ... Additional parameters to pass to the underlying HTML tag. +#' +#' @examplesIf rlang::is_interactive() +#' input_video_clip( +#' "clip1", +#' video_bits_per_second = 256000, +#' audio_bits_per_second = 64000, +#' style = "width: 400px; max-width: 100%;", +#' ) #' #' @return A video clip input control that can be added to a UI definition. #' @export -#' -#' @importFrom htmltools tag tags tagList div -#' @importFrom shiny icon input_video_clip <- function( inputId, reset_on_record = TRUE, diff --git a/r-package/R/shinymedia-package.R b/r-package/R/shinymedia-package.R new file mode 100644 index 0000000..84b1900 --- /dev/null +++ b/r-package/R/shinymedia-package.R @@ -0,0 +1,9 @@ +#' @keywords internal +"_PACKAGE" + +## usethis namespace: start +#' @import htmltools +#' @importFrom base64enc base64encode +#' @importFrom shiny icon +## usethis namespace: end +NULL diff --git a/r-package/man/audio_spinner.Rd b/r-package/man/audio_spinner.Rd index 2cf3094..a9b830a 100644 --- a/r-package/man/audio_spinner.Rd +++ b/r-package/man/audio_spinner.Rd @@ -24,63 +24,86 @@ audio_spinner( ) } \arguments{ -\item{...}{Additional attributes for the spinner, to be added directly to the \verb{} element.} +\item{...}{Additional attributes for the spinner, to be added directly to the +\verb{} element.} -\item{src}{The source URL or URI for the audio file. This should be used for remote resources -or data URIs. If provided, this takes precedence over \code{con}.} +\item{src}{The source URL or URI for the audio file. This should be used for +remote resources or data URIs. If provided, this takes precedence over +\code{con}.} -\item{con}{An optional connection object or file path for local audio files. This is ignored -if \code{src} is provided. Use this for reading local files securely.} +\item{con}{An optional connection object or file path for local audio files. +This is ignored if \code{src} is provided. Use this for reading local files +securely.} -\item{rpm}{The speed of the spinner, in clockwise revolutions per minute. Default is 10 RPM. -Use 0 to disable rotation, or a negative value to rotate counter-clockwise.} +\item{rpm}{The speed of the spinner, in clockwise revolutions per minute. +Default is 10 RPM. Use 0 to disable rotation, or a negative value to rotate +counter-clockwise.} -\item{gap}{The gap between the blades of the spinner, in radians. Default is pi/5, or 36°.} +\item{gap}{The gap between the blades of the spinner, in radians. Default is +pi/5, or 36°.} -\item{stroke}{The stroke thickness of the individual arcs that make up each blade of the spinner, -in pixels. Default is 2.5.} +\item{stroke}{The stroke thickness of the individual arcs that make up each +blade of the spinner, in pixels. Default is 2.5.} -\item{min_radius}{The radius of the spinner when there is only silence, in pixels. Default is 30.} +\item{min_radius}{The radius of the spinner when there is only silence, in +pixels. Default is 30.} -\item{radius_compression}{The raw \verb{[-1, 1]} amplitude of the audio is compressed using -\code{x^radius_compression} to make the spinner more responsive to quiet sounds. Default is 0.8. -Set to 1.0 to disable compression. (Note that this only affects the visualization, not the audio playback.)} +\item{radius_compression}{The raw \verb{[-1, 1]} amplitude of the audio is +compressed using \code{x^radius_compression} to make the spinner more responsive +to quiet sounds. Default is 0.8. Set to 1.0 to disable compression. (Note +that this only affects the visualization, not the audio playback.)} -\item{radius_overscan}{Use this parameter to set the maximum possible radius of the spinner, -relative to the width/height of the container. Default is 1.1, meaning the spinner radius -will be scaled such that at maximum amplitude, it will be 10\% larger than the container -(the spinner blades will be clipped). Use larger values if you're expecting generally quiet audio.} +\item{radius_overscan}{Use this parameter to set the maximum possible radius +of the spinner, relative to the width/height of the container. Default is +1.1, meaning the spinner radius will be scaled such that at maximum +amplitude, it will be 10\% larger than the container (the spinner blades +will be clipped). Use larger values if you're expecting generally quiet +audio.} -\item{steps}{The number of concentric arcs that make up each blade of the spinner, not including -the central circle. Default is 2.} +\item{steps}{The number of concentric arcs that make up each blade of the +spinner, not including the central circle. Default is 2.} -\item{blades}{The number of blades in the spinner. Default is 3. Set to 0 to use concentric circles -instead of blades.} +\item{blades}{The number of blades in the spinner. Default is 3. Set to 0 to +use concentric circles instead of blades.} \item{width}{The width of the spinner in CSS units. Default is "125px".} \item{height}{The height of the spinner in CSS units. Default is "125px".} -\item{autoplay}{Whether to autoplay the audio. Default is TRUE. Note that many browsers will not -allow autoplaying audio without user interaction; if autoplay fails, the spinner will show a -tooltip instructing the user to tap or click to start the audio.} +\item{autoplay}{Whether to autoplay the audio. Default is TRUE. Note that +many browsers will not allow autoplaying audio without user interaction; if +autoplay fails, the spinner will show a tooltip instructing the user to tap +or click to start the audio.} -\item{autodismiss}{Whether to remove the spinner after the audio finishes playing. Default is FALSE.} +\item{autodismiss}{Whether to remove the spinner after the audio finishes +playing. Default is FALSE.} -\item{class}{The class of the spinner. Default is "mx-auto" which horizontally centers the element -inside its container (assuming Bootstrap is loaded).} +\item{class}{The class of the spinner. Default is "mx-auto" which +horizontally centers the element inside its container (assuming Bootstrap +is loaded).} } \value{ -An HTML tag object representing the audio spinner. +An HTML \verb{} tag object representing the audio spinner. } \description{ Create an audio spinner } \examples{ +\dontshow{if (rlang::is_interactive()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} # Using a URL -audio_spinner(src = "https://example.com/audio.mp3", rpm = 15, width = "200px", height = "200px") +audio_spinner( + src = "https://example.com/audio.mp3", + rpm = 15, + width = "200px", + height = "200px" +) # Using a local file -audio_spinner(con = "path/to/local/audio.mp3", rpm = 20, width = "150px", height = "150px") - +audio_spinner( + con = "path/to/local/audio.mp3", + rpm = 20, + width = "150px", + height = "150px" +) +\dontshow{\}) # examplesIf} } diff --git a/r-package/man/input_video_clip.Rd b/r-package/man/input_video_clip.Rd index 7e45661..d067c29 100644 --- a/r-package/man/input_video_clip.Rd +++ b/r-package/man/input_video_clip.Rd @@ -16,24 +16,24 @@ input_video_clip( \arguments{ \item{inputId}{The input slot that will be used to access the value.} -\item{reset_on_record}{Whether to reset the video clip input value when recording starts. If -TRUE, the video clip input value will become NULL at the moment the -Record button is pressed; if FALSE, the value will not change until -the user stops recording. Default is TRUE.} +\item{reset_on_record}{Whether to reset the video clip input value when +recording starts. If TRUE, the video clip input value will become NULL at +the moment the Record button is pressed; if FALSE, the value will not +change until the user stops recording. Default is TRUE.} -\item{mime_type}{The MIME type of the video clip to record. By default, this is NULL, -which means the browser will choose a suitable MIME type for video +\item{mime_type}{The MIME type of the video clip to record. By default, this +is NULL, which means the browser will choose a suitable MIME type for video recording. Common MIME types include 'video/webm' and 'video/x-matroska'.} -\item{video_bits_per_second}{The target video bitrate in bits per second. By default, this is NULL, -which means the browser will choose a suitable bitrate for video -recording (according to the spec, 2,500,000). This is only a -suggestion; the browser may choose a different bitrate.} +\item{video_bits_per_second}{The target video bitrate in bits per second. By +default, this is NULL, which means the browser will choose a suitable +bitrate for video recording (according to the spec, 2,500,000). This is +only a suggestion; the browser may choose a different bitrate.} -\item{audio_bits_per_second}{The target audio bitrate in bits per second. By default, this is NULL, -which means the browser will choose a suitable bitrate for audio -recording. This is only a suggestion; the browser may choose a different -bitrate.} +\item{audio_bits_per_second}{The target audio bitrate in bits per second. By +default, this is NULL, which means the browser will choose a suitable +bitrate for audio recording. This is only a suggestion; the browser may +choose a different bitrate.} \item{...}{Additional parameters to pass to the underlying HTML tag.} } @@ -43,3 +43,13 @@ A video clip input control that can be added to a UI definition. \description{ A video clip input control that records short videos from webcam } +\examples{ +\dontshow{if (rlang::is_interactive()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +input_video_clip( + "clip1", + video_bits_per_second = 256000, + audio_bits_per_second = 64000, + style = "width: 400px; max-width: 100\%;", +) +\dontshow{\}) # examplesIf} +} diff --git a/r-package/man/multimodal_dep.Rd b/r-package/man/multimodal_dep.Rd deleted file mode 100644 index b536854..0000000 --- a/r-package/man/multimodal_dep.Rd +++ /dev/null @@ -1,11 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/html_deps.R -\name{multimodal_dep} -\alias{multimodal_dep} -\title{Create HTML dependency for multimodal component} -\usage{ -multimodal_dep() -} -\description{ -Create HTML dependency for multimodal component -} diff --git a/r-package/man/shinymedia-package.Rd b/r-package/man/shinymedia-package.Rd new file mode 100644 index 0000000..8b00882 --- /dev/null +++ b/r-package/man/shinymedia-package.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/shinymedia-package.R +\docType{package} +\name{shinymedia-package} +\alias{shinymedia} +\alias{shinymedia-package} +\title{shinymedia: Multimedia Input/Output Controls for 'Shiny'} +\description{ +Extends the 'Shiny' web framework with controls for multimedia input/output. Includes a video input control and an audio output. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/posit-dev/shinymedia} + \item Report bugs at \url{https://github.com/posit-dev/shinymedia/issues} +} + +} +\author{ +\strong{Maintainer}: Joe Cheng \email{joe@posit.co} + +Other contributors: +\itemize{ + \item Posit Software, PBC [copyright holder, funder] +} + +} +\keyword{internal}