Migrating from v1
V1VideoCompatPlugin (id 'v1-video-compat') attaches the old v1 method names (seek(), speed(), playlist(), enterFullscreen(), and the rest of the v1 surface) onto a v2 player instance. Every shim delegates to the real v2 method underneath and logs one deprecation line per call, nothing here is new behavior, it’s a compatibility surface over the API this whole collection documents. It is entirely opt-in, a v2 app that never adds this plugin never carries the shim code or the deprecation logging at all.
Options
None. V1VideoCompatPlugin takes no configuration, add it and every shim installs:
import nmplayer from '@nomercy-entertainment/nomercy-video-player';
import { V1VideoCompatPlugin } from '@nomercy-entertainment/nomercy-video-player';
const player = nmplayer('player');
player.addPlugin(V1VideoCompatPlugin); // before setup()
player.setup({
baseUrl: 'https://raw.githubusercontent.com/NoMercy-Entertainment/nomercy-media/master/Films',
baseImageUrl: 'https://image.tmdb.org/t/p',
muted: true,
autoPlay: true,
playlist: [
{
id: 'sintel',
title: 'Sintel',
url: '/Sintel.(2010)/Sintel.(2010).NoMercy.m3u8',
image: '/w780/q2bVM5z90tCGbmXYtq2J38T5hSX.jpg',
},
],
});
What it shims
Grouped by concern, every entry maps directly to a v2 method already covered elsewhere in this collection:
| v1 method | v2 equivalent |
|---|---|
seek(seconds), currentTime() / currentTime(seconds), currentSrc() | time(seconds), videoElement.currentSrc / videoElement.src |
speed() / speed(rate), speeds(), hasSpeeds() | playbackRate(), playbackRates() |
muted() / muted(state), gain(), isPlaying, state() | volumeState(), mute()/unmute(), videoElement.volume, playState() |
enterFullscreen(), exitFullscreen(), hasPIP(), setFloatingPlayer(active) | fullscreen(state), platform().pip, pip(active) |
aspect() / aspect(value), setAspect(value) | aspectRatio() / aspectRatio(value) |
resize(), width(), height(), element() | no-op (v2’s ResizeObserver tracks size automatically), container.clientWidth, container.clientHeight, container |
subtitleIndex(), subtitleIndexBy(lang), hasSubtitles() | subtitle()?.index, a subtitles() search, subtitles().length > 0 |
audioTrackIndex(), audioTrackIndexByLanguage(lang), hasAudioTracks() | the audio-track equivalents of the row above |
hasQualities() | qualityLevels().length > 0 |
chapterText(idx?) | chapter()?.title / chapters()[idx]?.title |
playlist() / playlist(items), playlistItem(), playlistIndex(), setPlaylist(items), loadSource(url) | queue() / queue(items), item(), index(), load({ id, url }) |
load(items[]) | queue(items), the array-overload only, a single-item load(item, opts) call still delegates straight through to the real v2 load(). |
playVideo(target) | item(target, { autoplay: true }) |
setEpisode(season, episode) | find the index in queue() by season/episode, then item(index) |
isFirstPlaylistItem(), isLastPlaylistItem(), hasPlaylists() | derived from index() and queueLength() |
seasons() | grouped from queue() by the item’s season field |
localize(key, vars), addTranslation(key, value) | t(key, vars), translation(language(), key, value) |
registerPlugin(...), usePlugin(...), plugin(id) | addPlugin(...), getPluginById(id) |
displayMessage(text, ms) | emit 'display-message' / 'remove-message' directly |
setup() itself is shimmed too: v1 allowed a second setup({ playlist, autoPlay }) call to swap sources on a live player; v2’s real setup() throws on re-entry. With this plugin loaded, a repeat call after the first queues the incoming playlist and autoplays it instead of throwing, matching the old behavior.
What has no v2 equivalent
A handful of v1 methods throw NotImplementedError rather than silently no-opping, because there’s no v2 data model to translate them into:
subtitleFile(url),chapterFile(url),skipFile(url),skip(): dynamic sidecar/skip-segment ingestion. Add the URL to the playlist item’stracks/chaptersfield instead, or calltime(seconds)at the boundary directly for skip segments.skippers(): always returns an empty array, there is no v2 skip-segment data model yet.
A second group keeps working exactly as it did in v1 (nothing throws), but has no v2 method to migrate onto, either because v2 solved the underlying problem structurally or because the behavior is a pure utility outside the player’s typed surface. Delete these call sites when you remove the plugin, replicating them yourself if your app still needs them:
allowFullscreen/setAllowFullscreen(allowed): gatesenterFullscreen()only,fullscreen()itself is never gated in v2.stretchOptions: the v1 array['uniform', 'fill', 'exactfit', 'none']. No v2 accessor reads this list back,cycleAspectRatio()cycles the same four values internally, but there’s nothing public to iterate yourself against. Hardcode the array in your own app code if you still need to render an aspect-ratio menu from it.doubleTap(el, callback, thresholdMs): a pure DOM double-tap detector, unrelated to player state.appendScriptFilesToDocument(urls): a pure DOM utility, appends<script>tags todocument.headin sequence, awaiting eachonloadbefore starting the next. Unrelated to player state, replicate it in your own app code if you still need it.snakeToCamel(value),spaceToCamel(value): pure string utilities, no player state involved either.setTitle(title): writesdocument.titledirectly.tracks(kind): reads the item’s raw v1tracksfield, v2’s typedsubtitles()/audioTracks()replace it for the formats they cover, there’s no v2 generic-track equivalent.addTranslations(entries)(the list-form,{ key, value }[], overload): loops callingtranslation(language(), entry.key, entry.value)for you. The bundle-form overload,addTranslations(bundle), is real v2 API and passes straight through to it, the plugin still logs the deprecation warning first even though that call needed no translation.
Rules & restrictions
- Every shim logs
@deprecated player.<method>() is a v1 compatibility shim — migrate to the v2 API before it is removed.through the player’s logger on every call, so grepping logs during a migration surfaces exactly which call sites still need updating. - Two events bridge automatically while this plugin is loaded:
'playbackRate'also emits as'speed', and'queue'also emits as'playlist', matching the v1 event names a legacy listener might still be attached to. - Must be added before
setup(), like any plugin, adding it afterready()misses the plugin’s ownuse()call during the setup pipeline.
How to remove it
Delete the player.addPlugin(V1VideoCompatPlugin) call, then work through the deprecation log output (every remaining call site logs its own replacement method), migrating call sites to the v2 methods in the table above. Once the log is empty, remove the import too, there is nothing else in the codebase that depends on this plugin being present.
Next steps
- Reference: Player Methods: the full v2 surface every shim in this plugin delegates to.