Seanime provides APIs for controlling media playback and interacting with the underlying Playback Manager and MPV. These APIs give plugins access to the same functionality Seanime uses internally for media tracking and player control.
Gets the next episode to play for the current media.
Returns: Promise<Anime_LocalFile | undefined>
Example:
// Check if there's a next episode
try {
const nextEpisode = await ctx.playback.getNextEpisode()
if (nextEpisode) {
console.log(`Next episode: ${nextEpisode.name}`)
} else {
console.log("No next episode available")
}
} catch (error) {
console.error("Error getting next episode:", error)
}
playNextEpisode()
Plays the next episode for the current media.
Returns: Promise<void>
Example:
// Play next episode when current is almost done
ctx.playback.registerEventListener((event) => {
if (event.status && event.status.completionPercentage > 95) {
try {
ctx.playback.playNextEpisode()
} catch(e) {}
}
})
MPV
openAndPlay(filePath)
Opens and plays a file directly with MPV (without tracking).
Parameters:
filePath: String - Path to a video file
Returns: Promise<void>
Example:
// Play a file directly with MPV without tracking
try {
await ctx.mpv.openAndPlay("/path/to/video.mkv")
console.log("MPV playback started")
} catch (error) {
console.error("MPV playback error:", error)
}
onEvent(callback)
Registers a listener for MPV player events (fires frequently).
Parameters:
callback: Function(event, closed) - Callback function for events
Returns: Function - Call this function to unregister the listener
The playback API is designed for tracked media files that are part of the Seanime library:
// Good practice: Play scanned files for proper tracking
const localFile = getScannedFile() // Get a file that's in the library
ctx.playback.playUsingMediaPlayer(localFile.path)
// Bad practice: Playing unscanned files won't track properly
ctx.playback.playUsingMediaPlayer("/random/video.mp4") // Will cause tracking errors
MPV Connection Management
Handle MPV connections carefully:
// Good practice: Check connection before using
function skipIntro() {
const conn = ctx.mpv.getConnection()
if (conn && !conn.isClosed()) {
const currentTime = conn.get("time-pos") || 0
conn.set("time-pos", currentTime + 90) // Skip 90 seconds
}
}
// Bad practice: Not checking connection state
function badSkipFunction() {
const conn = ctx.mpv.getConnection()
conn.set("time-pos", 90) // Might fail if connection doesn't exist
}