šŸš€ Big News:Socket Has Acquired Secure Annex.Learn More →
Socket
Book a DemoSign in
Socket

@alessiofrittoli/media-utils

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@alessiofrittoli/media-utils

TypeScript media utility library

latest
Source
npmnpm
Version
1.3.0
Version published
Weekly downloads
72
-20.88%
Maintainers
1
Weekly downloads
Ā 
Created
Source

Media Utils šŸŽ„

TypeScript media utility library

Latest version Test coverage Socket Security score npm downloads Dependencies Dependencies status

minified minizipped Tree shakable

Fund this package

Table of Contents

Getting started

Run the following command to start using media-utils in your projects:

npm i @alessiofrittoli/media-utils

or using pnpm

pnpm i @alessiofrittoli/media-utils

API Reference

MIME types

getMimeType()

Get the MIME type from the given input string.

Parameters
ParameterTypeDescription
inputstringThe input string where MIME type is extracted from.
typeMediaType(Optional) Accepted media type. This may be usefull when subtype matches other media types (eg. audio/mp4 - video/mp4).
Returns

Type: MIMEType

  • The MIME type if found.
  • undefined otherwise.
Examples
import { getMimeType } from "@alessiofrittoli/media-utils";

console.log(getMimeType("/path/to/video-file.mp4")); // Outputs: 'video/mp4'
console.log(getMimeType("/path/to/audio-file.mp4", "audio")); // Outputs: 'audio/mp4'
console.log(getMimeType("/path/to/audio-file.mp3")); // Outputs: 'audio/mpeg'
getAllowedMimeTypes()

Get allowed MIME types.

Parameters
ParameterTypeDescription
acceptstring(Optioanl) A string describing allowed MIME types.
The format is the same accepted by HTMLInputElement.accept attribute.
It could be one of the following examples:
- *
- image (type)
- image/* ({type}/{subtype})
- image/png ({type}/{subtype}) - specific
- .png (extension)
- image,audio (multiple types)
- image/*,audio/* (multiple {type}/{subtype})
- .png, .mp3 (multiple extensions)
- .docx, audio, video/*, text/html (mixed)
Returns

Type: (MIMEType | '*')[]

An array of MIME types based on the accept value. [ '*' ] if a wildcard or no accept is given.

Examples
import { getAllowedMimeTypes } from "@alessiofrittoli/media-utils";

console.log(getAllowedMimeTypes());
console.log(getAllowedMimeTypes("*"));
console.log(getAllowedMimeTypes("image"));
console.log(getAllowedMimeTypes("audio/*"));
console.log(getAllowedMimeTypes("image,video"));
console.log(getAllowedMimeTypes("image/*,video/*"));
console.log(getAllowedMimeTypes(".mp3,mp4"));
console.log(getAllowedMimeTypes(".jpg, .png"));
console.log(getAllowedMimeTypes("image/jpeg,.jpg"));

MediaSession

Types
MediaArtWork

The Media Artwork.

Compatible type with the global MediaImage interface.

Properties
PropertyTypeDescription
srcUrlInputThe Media Artwork image URL.
See UrlInput type for more info.
sizenumberThe Media Artwork image size.
Common values are: 96, 128, 192, 256, 384, 512.
typeMIMETypeThe Media Artwork image MIME type.
Media

Defines the media.

Extends the global MediaMetadata interface.

Properties
PropertyTypeDescription
srcUrlInputThe media URL.
See UrlInput type for more info.
typeMIMETypeThe media MIME type.
titlestringThe title of the media.
artworkMediaArtWork[]The media artwork.
See MediaArtWork type for more info.
artiststringThe artist of the media.
albumstringThe album of the media.
UpdateMediaMetadataAndPositionOptions

Defines the MediaSession update options.

Properties
PropertyTypeDescription
mediaHTMLMediaElementThe HTMLMediaElement.
dataOmit<Media, 'src'>The playing media data.
updatePositionState()

Update MediaSession position state.

Parameters
ParameterTypeDescription
mediaHTMLMediaElementThe HTMLMediaElement.
Examples
import { updatePositionState } from "@alessiofrittoli/media-utils";

navigator.mediaSession.setActionHandler("seekto", (details) => {
  if (typeof details.seekTime === "undefined") return;

  media.currentTime = details.seekTime;

  updatePositionState(media);
});
updateMediaMetadata()

Update MediaSession metadata.

Parameters
ParameterTypeDescription
dataOmit<Media, 'src'>The playing media data.
Examples
import { updateMediaMetadata } from "@alessiofrittoli/media-utils";

media.play().then(() => {
  updateMediaMetadata({
    type: "audio/mpeg",
    title: "Song name",
    album: "Album name",
    artist: "Artist name",
    artwork: [
      {
        src: { pathname: "/path-to-image-96.png" },
        size: 96,
        type: "image/png",
      },
      {
        src: { pathname: "/path-to-image-128.png" },
        size: 128,
        type: "image/png",
      },
      {
        src: { pathname: "/path-to-image-192.png" },
        size: 192,
        type: "image/png",
      },
      {
        src: { pathname: "/path-to-image-256.png" },
        size: 256,
        type: "image/png",
      },
      {
        src: { pathname: "/path-to-image-384.png" },
        size: 384,
        type: "image/png",
      },
      {
        src: { pathname: "/path-to-image-512.png" },
        size: 512,
        type: "image/png",
      },
    ],
  });
});
updateMediaMetadataAndPosition()

Update MediaSession metadata and position state.

Parameters
ParameterTypeDescription
optionsUpdateMediaMetadataAndPositionOptionsAn object defining media HTMLMediaElement and associated data.
See UpdateMediaMetadataAndPositionOptions for more info.
Examples
import { updateMediaMetadataAndPosition } from "@alessiofrittoli/media-utils";

media.play().then(() => {
  updateMediaMetadataAndPosition({
    media,
    data: {
      type: "audio/mpeg",
      title: "Song name",
      album: "Album name",
      artist: "Artist name",
      artwork: [
        {
          src: { pathname: "/path-to-image-96.png" },
          size: 96,
          type: "image/png",
        },
        {
          src: { pathname: "/path-to-image-128.png" },
          size: 128,
          type: "image/png",
        },
        {
          src: { pathname: "/path-to-image-192.png" },
          size: 192,
          type: "image/png",
        },
        {
          src: { pathname: "/path-to-image-256.png" },
          size: 256,
          type: "image/png",
        },
        {
          src: { pathname: "/path-to-image-384.png" },
          size: 384,
          type: "image/png",
        },
        {
          src: { pathname: "/path-to-image-512.png" },
          size: 512,
          type: "image/png",
        },
      ],
    },
  });
});

AudioEngine

Manages volume manipulation for HTML media elements.

Provides methods for fading volume with customizable tweening, and utilities for converting between normalized volume values (0.0-1.0) and linear gain values using decibel-based calculations that better match human perception of audio loudness.

  • Refer to the Audio Engine Manager section to understand how instance caching prevents redundant AudioEngine instantiation.
AudioEngine Types
TickHandler

Callback executed on each interpolation tick.

Parameters
ParameterTypeDescription
valuenumberThe current interpolated value.
FadeVolumeOptions
Properties
PropertyTypeDefaultDescription
tonumber-Defines the final volume to set [0-1].
durationnumber200(Optional) Duration of the tween in milliseconds.
onTickTickHandler-Callback executed on each interpolation tick.
See TickHandler types for more info.
onEndTickHandler-(Optional) Callback executed when the interpolation completes.
See TickHandler types for more info.
easingEasingFnEasing.linear(Optional) Easing function used to transform the linear time progression.
See EasingFn types for more info.
Hznumber120(Optional) Custom tick rate in Hz.
Methods
AudioEngine.fade()

Fade media volume.

Parameters
ParameterTypeDescription
optionsFadeVolumeOptionsAn object defining customization and callbacks.
See FadeVolumeOptions for more info.
Examples
import { AudioEngine } from '@alessiofrittoli/media-utils/audio'

const audio  = new Audio( ... )
const engine = new AudioEngine( audio )

audio.volume = 0
audio.play()
 .then( () => {
   // Fade volume to 0.5 over 2 seconds
   engine.fade( {
     to         : 1,
     duration   : 2000,
   } )
 } )
Static methods
AudioEngine.VolumeToGain()

Converts a volume value (0.0 to 1.0) to a linear gain value.

The returned value will better match the human perceived volume.

Parameters
ParameterTypeDescription
volumenumberThe volume value, where 0 represents silence and 1 represents maximum volume.
Returns

Type: number.

The corresponding linear gain value, or 0 if the gain is effectively inaudible.

Examples
import { AudioEngine } from '@alessiofrittoli/media-utils/audio'

const audio  = new Audio( ... )
const engine = new AudioEngine( audio )

audio.volume = 0
audio.play()
  .then( () => {
    engine.fade( {
      to: AudioEngine.VolumeToGain( 0.5 ),
      onEnd() {
        console.log( audio.volume ) // Outputs: `0.03162277660168379`
      },
    } )
  } )
AudioEngine.GainToVolume()

Converts a linear gain value to a normalized volume value between 0 and 1.

Parameters
ParameterTypeDescription
gainnumberThe linear gain value to convert.
Returns

Type: number.

The normalized volume value in the range [0, 1].

Examples
import { AudioEngine } from '@alessiofrittoli/media-utils/audio'

const audio  = new Audio( ... )
const engine = new AudioEngine( audio )

audio.volume = 0
audio.play()
  .then( () => {
    engine.fade( {
      to: AudioEngine.VolumeToGain( 0.5 ),
      onEnd() {
        console.log( audio.volume ) // Outputs: `0.03162277660168379`
        console.log( AudioEngine.GainToVolume( audio.volume ) ) // Outputs: `0.5`
      },
    } )
  } )
AudioEngine.normalize()

Conditionally normalize volume using AudioEngine.VolumeToGain.

This method acts as a wrapper and has the same API of AudioEngine.VolumeToGain() but it accepts a boolean value as second argument that allows you to quickly opt-in/opt-out based on an incoming variable, thus there is no need to call AudioEngine.VolumeToGain() conditionally.

Examples
import { AudioEngine } from '@alessiofrittoli/media-utils/audio'

// `normalizeAudio` may come from global settings
const audio  = new Audio( ... )
const engine = new AudioEngine( audio )

audio.volume = 0
audio.play()
  .then( () => {
    engine.fade( {
      to: AudioEngine.normalize( 0.5, normalizeAudio ),
      onEnd() {
        console.log( audio.volume ) // Outputs: `0.03162277660168379` if `normalizeAudio` is set to `true`, 0.5 otherwise.
      },
    } )
  } )
AudioEngine.denormalize()

Conditionally denormalize volume using AudioEngine.GainToVolume.

This method acts as a wrapper and has the same API of AudioEngine.GainToVolume() but it accepts a boolean value as second argument that allows you to quickly opt-in/opt-out based on an incoming variable, thus there is no need to call AudioEngine.GainToVolume() conditionally.

Examples
import { AudioEngine } from '@alessiofrittoli/media-utils/audio'

// `normalizeAudio` may come from global settings
const audio  = new Audio( ... )
const engine = new AudioEngine( audio )

audio.volume = 0
audio.play()
  .then( () => {
    engine.fade( {
      to: AudioEngine.normalize( 0.5, normalizeAudio ),
      onEnd() {
        console.log(
          AudioEngine.denormalize( audio.volume, normalizeAudio )
        )
      },
    } )
  } )
Audio Engine Manager

The Audio Engine Manager is responsible for maintaining a one-to-one association between an HTMLMediaElement and its corresponding AudioEngine instance. Its primary goal is to prevent unnecessary re-creation of AudioEngine objects when interacting with the same media element.

When working with audio processing APIs, repeatedly instantiating AudioEngine for the same HTMLMediaElement would:

  • Introduce unnecessary computational overhead.
  • Potentially duplicate internal state.
  • Increase memory usage.
  • Lead to inconsistent behavior.

The manager ensures that each media element has exactly one AudioEngine instance.

getEngine()

Get the AudioEngine associated with the given media. If none exists, it lazily creates a new instance.

Parameters
ParametertypeDecription
mediaHTMLMediaElementThe HTMLMediaElement.
Returns

Type: AudioEngine.

The AudioEngine associated with the given media or a new AudioEngine instance if none exists.

Examples
import { getEngine } from "@alessiofrittoli/media-utils/audio";

const mute = (media: HTMLMediaElement) => {
  getEngine(media).fade({ to: 0 });
};

const unmute = (media: HTMLMediaElement) => {
  getEngine(media).fade({ to: 1 });
};
destroyEngine()

Proactively delete the AudioEngine associated with the given media to free resources.

Parameters
ParametertypeDecription
mediaHTMLMediaElementThe HTMLMediaElement.
Returns

Type: boolean.

  • true if the element was successfully removed.
  • false if no engine was registered.
Examples
import { getEngine, destroyEngine } from "@alessiofrittoli/media-utils/audio";

const stop = (media: HTMLMediaElement) => {
  getEngine(media).fade({
    to: 0,
    onEnd() {
      media.pause();
      destroyEngine(media);
    },
  });
};
Audio Utilities
fadeVolume()

Fade media volume.

This utility function acts as a wrapper handling AudioEngine instances for you using the Audio Engine Manager.

Parameters
ParametertypeDecription
mediaHTMLMediaElementThe HTMLMediaElement.
optionsFadeVolumeOptionsAn object defining customization and callbacks.
See FadeVolumeOptions for more info.
Examples
import { fadeVolume } from "@alessiofrittoli/media-utils/audio";

const play = (media: HTMLMediaElement) => {
  media.volume = 0;
  media.play().then(() => {
    fadeVolume(media, { to: 1 });
  });
};

Media Playback

Media Playback types

PlayMediaOptions

An object defining play options and callbacks.

It extends UpdateMediaMetadataAndPositionOptions and FadeVolumeOptions interfaces and adds/overrides the following properties.

Properties
PropertyTypeDefaultDescription
volumenumber-Defines the final volume to set [0-1].
- overrides FadeVolumeOptions['to']
fadenumber200(Optional) A custom volume fade duration in milliseconds.
- overrides FadeVolumeOptions['duration']
onError( error: MediaError ) => void-(Optional) A custom callback executed when an error occurs when playing a media.
PauseMediaOptions

An object defining pause options and callbacks.

It extends PlayMediaOptions and omits unnecessary properties.

playMedia()

Play the given media.

Parameters
ParameterTypeDescription
optionsPlayMediaOptionsAn object defining play options and callbacks.
See PlayMediaOptions for more info.
Returns

Type: Promise<void>

A new Promise which resolves once media.play() promise is resolved.

Examples
import { playMedia } from "@alessiofrittoli/media-utils";

const media = new Audio( ... )

play.addEventListener("click", () => {

  playMedia( {
    media,
    volume: 1,
    fade: 800,
    data: {
      type: 'audio/mpeg',
      title: 'Media title',
    },
    onError( error ) {
      switch ( error.code ) {
        case MediaError.MEDIA_ERR_ABORTED:
          console.error( 'The fetching of the associated resource was aborted by the user\'s request.' )
          break
        case MediaError.MEDIA_ERR_NETWORK:
          console.error( 'Some kind of network error occurred which prevented the media from being successfully fetched, despite having previously been available.' )
          break
        case MediaError.MEDIA_ERR_DECODE:
          console.error( 'Despite having previously been determined to be usable, an error occurred while trying to decode the media resource, resulting in an error.' )
          break
        case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
          console.error( 'The associated resource or media provider object (such as a MediaStream) has been found to be unsuitable.' )
          break
        default:
          console.error( 'Unknow error.' )
      }
    },
  } )

});

pauseMedia()

Pause the given media.

Parameters
ParameterTypeDescription
optionsPauseMediaOptionsAn object defining pause options and callbacks.
See PauseMediaOptions for more info. for more info.
Examples
import { pauseMedia } from "@alessiofrittoli/media-utils";

const media = new Audio( ... )

pause.addEventListener("click", () => {

  pauseMedia( { media, fade: 800 } )

});

Image Video Stream

Types
CreateImageVideoStreamOptions interface

Options for rendering an image into a video stream.

It optionally accepts a previously created HTMLVideoElement where image will get streamed into.

Properties
PropertyTypeDefaultDescription
mediaBlob|HTMLImageElement-The image source to render. It can be either a Blob or a preloaded HTMLImageElement.
RenderOptions interface

Rendering options.

Properties
PropertyTypeDefaultDescription
mediaBlob|HTMLImageElement-(Optional) The image source to render. It can be either a Blob or a preloaded HTMLImageElement.
videoHTMLVideoElement-(Optional) A previously created HTMLVideoElement where image get streamed into.
aspectRationumber-(Optional) Target aspect ratio (width / height) of the rendering area.
If omitted, the original media aspect ratio is preserved.
fit'contain'|'cover'contain(Optional) Defines how the media should fit inside the rendering area.
- contain (default) behaves like object-fit: contain
- cover behaves like object-fit: cover
Only applies when aspectRatio is specified.
RenderResult interface

The rendering result.

Properties
PropertyTypeDescription
videoHTMLVideoElementThe HTMLVideoElement where image get streamed into.
RenderHandler type

Render a new image to the video stream.

type RenderHandler = (options?: RenderOptions) => Promise<RenderResult>;
DestroyHandler type

Stop stream tracks and release allocated resources.

type DestroyHandler = () => void;
CreateImageVideoStream interface

Defines the returned result of rendering an image into a video.

Properties
PropertyTypeDescription
renderRenderHandlerRender a new image to the video stream.
- See RenderHandler type.
destroyDestroyHandlerStop stream tracks and release allocated resources.
- See DestroyHandler type.
createImageVideoStream

Render an image into a video stream.

If the provided media (HTMLImageElement) fails to load, a 1x1 black frame is rendered instead and the promise does not reject.

Parameters
ParameterTypeDescription
optionsCreateImageVideoStreamOptionsRendering options.
- See CreateImageVideoStreamOptions interface.
Returns

Type: Promise<CreateImageVideoStream>

A new Promise that resolves the allocated rendering resources.

Examples
Fetch and render image Blob
import { fetch } from "@alessiofrittoli/fetcher";
import {
  getFallbackImage,
  createImageVideoStream,
} from "@alessiofrittoli/media-utils";

const createImageStream = async () => {
  const { data: media, error } = await fetch<Blob>("/path-to/image.png", {
    responseType: "blob",
  });

  if (error) {
    return createImageVideoStream({ media: getFallbackImage() });
  }

  return createImageVideoStream({ media });
};
Custom aspect ratio
import { createImageVideoStream } from "@alessiofrittoli/media-utils";

const createImageStream = () => {
  const media = document.createElement("img");
  media.src = "/path-to/image.png";

  return createImageVideoStream({
    media,
    aspectRatio: 16 / 9,
    fit: "cover", // or 'contain'
  });
};
Update streamed content
import { createImageVideoStream } from "@alessiofrittoli/media-utils";

const createImageStream = async () => {
  const media = document.createElement("img");
  media.src = "/path-to/image.png";

  const { video, render } = await createImageVideoStream({
    media,
    aspectRatio: 16 / 9,
    fit: "cover", // or 'contain'
  });

  // update streamed content after 5 seconds
  setTimeout(() => {
    media.src = "/path-to/image-2.png";

    await render({ aspectRatio: 1 });
  }, 5000);

  return video;
};
Using a previously created video
import { createImageVideoStream } from "@alessiofrittoli/media-utils";

const createImageStream = async () => {
  const video = document.createElement("video");
  video.src = "/path-to/video.mp4";

  const media = document.createElement("img");
  media.src = "/path-to/image.png";

  // replace original video content with streamed image
  await createImageVideoStream({
    media,
    video,
    aspectRatio: 16 / 9,
    fit: "cover", // or 'contain'
  });

  return video;
};
Free allocated resources
import { createImageVideoStream } from "@alessiofrittoli/media-utils";

const createImageStream = async () => {
  const media = document.createElement("img");
  media.src = "/path-to/image.png";

  // replace original video content with streamed image
  const { video, destroy } = await createImageVideoStream({
    media,
    aspectRatio: 16 / 9,
    fit: "cover", // or 'contain'
  });

  // free allocated resources after 5 seconds
  setTimeout(() => {
    destroy();
  }, 5000);

  return video;
};

Media Artwork Picture-in-Picture

Types
OpenPictureInPictureCommonOptions interface

Defines common configuration options for opening the media in Picture-in-Picture mode.

Parameters
ParameterTypeDescription
onQuit() => void(Optional) A callback to execute when Picture-in-Picture window is closed.
OpenImagePictureInPictureOptions interface

Defines configuration options for opening the image in Picture-in-Picture mode.

Parameters
ParameterTypeDescription
mediaCreateImageVideoStreamOptions[ 'media' ]|UrlInputThe media to render in a Picture-in-Picture window.
OpenImagePictureInPicture type

Defines the returned result of opening a rendered image into a video Picture-in-Picture window.

OpenVideoArtworkPictureInPictureOptions interface

Defines configuration options for opening the video in Picture-in-Picture window.

Parameters
ParameterTypeDescription
mediaHTMLVideoElement|UrlInputThe media to open in a Picture-in-Picture window.
OpenVideoArtworkPictureInPicture interface

Defines the returned result of opening a video into a Picture-in-Picture window.

Properties
PropertyTypeDescription
videoHTMLVideoElementThe HTMLVideoElement in Picture-in-Picture.
OpenArtworkPictureInPictureOptions interface

Defines configuration options for opening media artwork in Picture-in-Picture window.

Parameters
ParameterTypeDescription
mediaCreateImageVideoStreamOptions['media']| HTMLVideoElement|MediaArtWorkThe media to open in a Picture-in-Picture window.
- See CreateImageVideoStreamOptions interface.
- See MediaArtWork interface.
OpenArtworkPictureInPicture interface

Defines the returned result of opening a media artwork into a Picture-in-Picture window.

It could be OpenImagePictureInPicture or OpenVideoArtworkPictureInPicture.

isPictureInPictureSupported

Checks if the Picture-in-Picture API is supported by the current browser.

requiresPictureInPictureAPI

Validates that the Picture-in-Picture API is supported by the current browser.

  • Throws a new Exception with code ErrorCode.PIP_NOT_SUPPORTED if the Picture-in-Picture API is not supported.
openImagePictureInPicture

Opens an image in Picture-in-Picture window.

Once Picture-in-Picture get closed by the user, allocated resources are automatically freed.

Parameters
ParameterTypeDescription
optionsOpenImagePictureInPictureOptionsConfiguration options for opening the image in PiP window.
- See OpenImagePictureInPictureOptions interface.
Returns

Type: Promise<OpenImagePictureInPicture>

A new Promise that resolves to the Picture-in-Picture result containing the video element and destroy function.

Examples
Simple usage
import {
  ErrorCode,
  openImagePictureInPicture,
} from "@alessiofrittoli/media-utils";

try {
  navigator.mediaSession.setActionHandler("enterpictureinpicture", async () => {
    try {
      await openImagePictureInPicture({
        media: { pathname: "path/to/image.png" },
        aspectRatio: 1,
        fit: "cover",
        onQuit: () => console.log("Picture-in-Picture closed"),
      });
    } catch (_err) {
      const err = _err as Error;

      const error = Exception.isException<string, ErrorCode>(err)
        ? err
        : new Exception(err.message, {
            code: ErrorCode.UNKNOWN,
            name: err.name,
            cause: err,
          });
      switch (error.code) {
        case ErrorCode.PIP_NOT_SUPPORTED:
          alert("Picture-In-Picture is not supported by the current browser.");
          break;
        case ErrorCode.RENDERING_CONTEXT_UNAVAILABLE:
          alert("Couldn't render image in Picture-in-Picture.");
          break;
        default:
          console.error(error);
      }
    }
  });
} catch (error) {
  console.warn(
    'Warning! The "enterpictureinpicture" media session action is not supported.',
    error,
  );
}
Update image Picture-in-Picture content
import {
  openImagePictureInPicture,
  type OpenImagePictureInPicture,
} from "@alessiofrittoli/media-utils";

let resources: OpenImagePictureInPicture;

navigator.mediaSession.setActionHandler("enterpictureinpicture", async () => {
  resources = await openImagePictureInPicture({
    media: { pathname: "/path/to/image.png" },
  });
});

navigator.mediaSession.setActionHandler("nexttrack", async () => {
  resources = await openImagePictureInPicture({
    media: { pathname: "/path/to/image.png" },
    ...resources,
  });
});
openVideoArtworkPictureInPicture

Opens a video artwork element in Picture-in-Picture window.

This function is intended for rendering a short song artwork video. This is not suitable if your're looking for a proper video Picture-in-Picture since it simple as calling video.requestPictureInPicture().

Supports both HTMLVideoElement instances and URL inputs. When a URL is provided, a video element is created and the URL is set as its source.

Parameters
ParameterTypeDescription
optionsOpenVideoArtworkPictureInPictureOptionsConfiguration options for opening the video in Picture-in-Picture.
- See OpenVideoArtworkPictureInPictureOptions interface.
Returns

Type: Promise<OpenVideoArtworkPictureInPicture>

A new Promise that resolves with an object containing the video element displayed in Picture-in-Picture mode.

Examples
import { openVideoArtworkPictureInPicture } from "@alessiofrittoli/media-utils";

// With a URL
const { video } = await openVideoArtworkPictureInPicture({
  media: "/song-artwork-video.mp4",
  onQuit: () => console.log("Picture-in-Picture closed"),
});

// With an HTMLVideoElement
const media = document.querySelector("video");
media.src = "/song-artwork-video.mp4";

const { video } = await openVideoArtworkPictureInPicture({ media });
openArtworkPictureInPicture

Opens the given media in Picture-in-Picture window.

It easly handles images and videos rendering using openImagePictureInPicture or openVideoArtworkPictureInPicture.

Once Picture-in-Picture get closed by the user, allocated resources are automatically freed.

Parameters
ParameterTypeDescription
optionsOpenArtworkPictureInPictureOptionsConfiguration options for opening the media in Picture-in-Picture window.
- See OpenArtworkPictureInPictureOptions interface.
Returns

Type: Promise<OpenArtworkPictureInPicture>

A new Promise that resolves to the Picture-in-Picture result.

Examples
Simple usage
import { openArtworkPictureInPicture } from "@alessiofrittoli/media-utils";

const result = await openArtworkPictureInPicture({
  media: {
    type: "image/png",
    src: "/path/to/image.png",
  },
  aspectRatio: 1,
  fit: "cover",
});

// update
await openArtworkPictureInPicture({
  media: {
    type: "video/mp4",
    src: "/path/to/video.mp4",
  },
  ...result,
});
Using media session image
import {
  openArtworkPictureInPicture,
  updateMediaMetadata,
  type MediaSessionMetadata,
} from "@alessiofrittoli/media-utils";

const data: MediaSessionMetadata = {
  title: "Test Song",
  artist: "Test Artist",
  album: "Test Album",
  artwork: [
    { src: "/path/to/song-artwork.png", sizes: 128, type: "image/png" },
  ],
};

updateMediaMetadata(data);

await openArtworkPictureInPicture();
Handling errors
import {
  ErrorCode,
  openArtworkPictureInPicture,
} from "@alessiofrittoli/media-utils";

try {
  await openArtworkPictureInPicture({ ... });
} catch (_err) {
  const err = _err as Error;

  const error = Exception.isException<string, ErrorCode>(err)
    ? err
    : new Exception(err.message, {
        code: ErrorCode.UNKNOWN,
        name: err.name,
        cause: err,
      });
  switch (error.code) {
    case ErrorCode.PIP_NOT_SUPPORTED:
      alert("Picture-In-Picture is not supported by the current browser.");
      break;
    case ErrorCode.RENDERING_CONTEXT_UNAVAILABLE:
      alert("Couldn't render image in Picture-in-Picture.");
      break;
    default:
      console.error(error);
  }
}

Utilities

formatMediaTiming()

Formats a time value in seconds into a human-readable media timing string (M:SS or H:MM:SS).

Parameters
ParameterTypeDefaultDescription
timenumber-The time value in seconds to format.
showHoursbooleanfalse(Optional) Whether to include hours in the formatted output.
Returns

Type: string

A formatted time string in the format "M:SS" or "H:MM:SS" if showHours is true. If the time is 0 or invalid, returns "0:00".

Examples
import { formatMediaTiming } from "@alessiofrittoli/media-utils";

console.log(formatMediaTiming(45)); // Outputs: "0:45"
console.log(formatMediaTiming(90)); // Outputs: "1:30"
console.log(formatMediaTiming(125)); // Outputs: "2:05"

console.log(formatMediaTiming(3661, true)); // Outputs: "1:01:01"

console.log(formatMediaTiming(0)); // Outputs: "0:00"
console.log(formatMediaTiming(-NaN)); // Outputs: "0:00"
console.log(formatMediaTiming(NaN)); // Outputs: "0:00"
console.log(formatMediaTiming(-Infinity)); // Outputs: "0:00"
console.log(formatMediaTiming(Infinity)); // Outputs: "0:00"

console.log(formatMediaTiming(0, true)); // Outputs: "0:00:00"
console.log(formatMediaTiming(-NaN, true)); // Outputs: "0:00:00"
console.log(formatMediaTiming(NaN, true)); // Outputs: "0:00:00"
console.log(formatMediaTiming(-Infinity, true)); // Outputs: "0:00:00"
console.log(formatMediaTiming(Infinity, true)); // Outputs: "0:00:00"
getPreloadStrategy

Determines the optimal preload strategy for media elements based on network conditions.

It returns a value that corresponds to the preload attribute used in HTML media elements like <video> and <audio>.

Returns

Type: HTMLMediaElement[ 'preload' ]

The recommended preload attribute value ('none', 'metadata', or 'auto').

  • Returns 'auto' if network connection information is unavailable
  • Returns 'none' if data saver mode is enabled
  • Returns 'metadata' for slow-2g or 2g connections
  • Returns 'auto' for faster connections (3g, 4g, etc.)

Development

Install depenendencies

npm install

or using pnpm

pnpm i

Build the source code

Run the following command to test and build code for distribution.

pnpm build

ESLint

warnings / errors check.

pnpm lint

Jest

Run all the defined test suites by running the following:

# Run tests and watch file changes.
pnpm test:watch

# Run tests in a CI environment.
pnpm test:ci

Run tests with coverage.

An HTTP server is then started to serve coverage files from ./coverage folder.

āš ļø You may see a blank page the first time you run this command. Simply refresh the browser to see the updates.

test:coverage:serve

Contributing

Contributions are truly welcome!

Please refer to the Contributing Doc for more information on how to start contributing to this project.

Help keep this project up to date with GitHub Sponsor.

GitHub Sponsor

Security

If you believe you have found a security vulnerability, we encourage you to responsibly disclose this and NOT open a public issue. We will investigate all legitimate reports. Email security@alessiofrittoli.it to disclose any security vulnerabilities.

Made with ā˜•

avatar
Alessio Frittoli
https://alessiofrittoli.it | info@alessiofrittoli.it

Keywords

nodejs

FAQs

Package last updated on 04 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts