🧩
Seanime Extensions
🧩
Seanime Extensions
  • Seanime
    • Getting started
    • Core APIs
    • Changelog
  • Content Providers
    • Write, test, share
    • Anime torrent provider
    • Manga provider
    • Online streaming provider
  • Plugins
    • Introduction
    • Write, test, share
    • APIs
      • Helpers
      • Store
      • Storage
      • Database
      • AniList
      • System
        • Permissions
        • OS
        • Filepath
        • Commands
        • Buffers, I/O
        • MIME
    • UI
      • Basics
      • User Interface
        • Tray
        • Toast
        • Screen
        • Command Palette
        • Action
        • DOM
      • Anime/Library
        • Anime
        • Playback
        • Continuity
        • Auto Downloader
        • Auto Scanner
        • Filler Manager
        • External Player Link
      • Downloading
        • Downloader
        • Torrent Client
      • Other
        • Manga
        • Discord
        • MPV
    • Hooks
    • Example
  • Frequently asked
    • Feature requests
Powered by GitBook
On this page
  • Permissions
  • Core methods
  • playUsingMediaPlayer
  • streamUsingMediaPlayer
  • registerEventListener
  • pause
  • resume
  • seek
  • cancel
  • getNextEpisode
  • playNextEpisode
  • Best Practices
  1. Plugins
  2. UI
  3. Anime/Library

Playback

Interact with the playback and auto-tracking system in Seanime.

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.

Permissions

playback permission is required

{
  //...
  "plugin": {
    "permissions": {
      "scopes": ["playback"]
    }
  }
}

Core methods

playUsingMediaPlayer

playUsingMediaPlayer(filePath)

Plays a local file using the configured media player, with automatic tracking.

Parameters:

  • filePath: String - Path to a scanned local video file

Note: This only works with files properly scanned by Seanime. Using it with unscanned files will result in tracking errors.

Example:

// Play a local file with tracking
try {
  await ctx.playback.playUsingMediaPlayer("/anime/One Piece/One Piece - 1015.mkv")
  console.log("Playback started successfully")
} catch (error) {
  console.error("Playback error:", error)
}

streamUsingMediaPlayer

streamUsingMediaPlayer(windowTitle, streamUrl, anime, aniDbEpisode)

Streams a video from a URL using the configured media player, with automatic tracking.

Parameters:

  • windowTitle: String - Title for the player window

  • streamUrl: String - URL of the video stream

  • anime: AL_BaseAnime - AniList anime object

  • aniDbEpisode: String - AniDB episode number

Example:

// Stream an episode with proper tracking
const anime = $anilist.getAnime(21) // One Piece
try {
  await ctx.playback.streamUsingMediaPlayer(
    "One Piece - Episode 1015", 
    "https://example.com/streams/one-piece-1015.mkv",
    anime,
    "1015"
  )
  console.log("Stream started successfully")
} catch (error) {
  console.error("Stream error:", error)
}

registerEventListener

registerEventListener(id, callback)

Registers a listener for playback events.

Parameters:

  • id: String - Unique identifier for the listener

  • callback: Function(event: PlaybackEvent) - Function called when an event occurs

Example:

// Listen for playback events
// Callback triggered every 1-3 seconds
const unsubscribe = ctx.playback.registerEventListener((event) => {
   //
   // Local file playback
   //
   if (event.isVideoStarted || event.isVideoCompleted || event.isIsVideoStopped) {
     // Video started
     if (event.isVideoStated) {
        console.log(event.startedEvent?.filename)
        return
     }
     
     // Video completed
     if (event.isVideoCompleted) {
        console.log(event.completedEvent?.filename)
        return
     }
     
     // Video stopped
     if (event.isIsVideoStopped) {
        console.log(event.stoppedEvent?.reason)
        return
     }
     
     // The playback state
     if (event.state) {
       console.log("Media title", event.state.mediaTitle)
       console.log("Episode number", event.state.episodeNumber) 
       console.log("Completion percentage", event.state.completionPercentage)
     }
     if(event.status) {
       console.log("Is Playing", event.status.playing)
       console.log("Current time", event.status.currentTimeInSeconds)
       console.log("Duration", event.status.durationInSeconds)
     }
   }
  
   //
   // Stream playback
   //
   if (event.isStreamStarted || event.isStreamCompleted || event.isStreamStopped) {
     // Stream started
     if (event.isStreamStarted) {
        console.log(event.startedEvent?.filename)
        return
     }
     
      // Stream completed
      if (event.isStreamCompleted) {
        console.log(event.completedEvent?.filename)
        return
      }
     
      // Stream stopped
      if (event.isStreamStopped) {
        console.log(event.stoppedEvent?.reason)
        return
      }
     
     // The stream playback state
     if (event.state) {
        console.log("Media title", event.state.mediaTitle)
        console.log("Episode number", event.state.episodeNumber) 
        console.log("Completion percentage", event.state.completionPercentage)
     }
     if(event.status) {
        console.log("Is Playing", event.status.playing)
        console.log("Current time", event.status.currentTimeInSeconds)
        console.log("Duration", event.status.durationInSeconds)
     }
   }
})

// Later, to stop listening
unsubscribe()

pause

Pauses the current playback.

Example:

try {
  ctx.playback.pause()
  console.log("Playback paused")
} catch (error) {
  console.error("Could not pause:", error)
}

resume

Resumes the paused playback.

Example:

// Resume after pausing
try {
  ctx.playback.resume()
  console.log("Playback resumed")
} catch (error) {
  console.error("Could not resume:", error)
}

seek

Seeks to a specific position in the current playback.

Parameters:

  • seconds: Number - The position to seek to in seconds

Example:

// Skip ahead 30 seconds
try {
  ctx.playback.seek(currentTimeInSeconds + 30)
  console.log("Skipped forward 30 seconds")
} catch (error) {
  console.error("Could not seek:", error)
}

cancel

Cancels the current playback tracking (does not stop the player).

Example:

// Cancel tracking without stopping playback
try {
  ctx.playback.cancel()
  console.log("Tracking canceled")
} catch (error) {
  console.error("Could not cancel tracking:", error)
}

getNextEpisode

Gets the next episode to play for the current media.

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.

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) {}
  }
})

Best Practices

Media Tracking

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

PreviousAnimeNextContinuity

Last updated 19 days ago