🧩
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
  • Core Methods
  • newAnimePageButton
  • newAnimePageDropdownItem
  • newAnimeLibraryDropdownItem
  • newMediaCardContextMenuItem
  • newMangaPageButton
  • newEpisodeCardContextMenuItem
  • newEpisodeGridItemMenuItem
  • Action Object Methods
  • Additional Properties
  • Best Practices
  1. Plugins
  2. UI
  3. User Interface

Action

The ctx.action API allows your plugin to add UI elements that trigger custom actions to different parts of the Seanime interface.

Core Methods

newAnimePageButton

Creates a button that appears on anime detail pages.

Parameters:

  • props: Object containing:

    • label: String - Button text

    • intent: String (Optional) - Button style ("primary", "success", "warning", etc.)

    • style: Object (Optional) - Custom CSS styles

Example:

// Create a play button for anime pages
const playButton = ctx.action.newAnimePageButton({
  label: "Play All Episodes",
  intent: "primary",
  style: { marginRight: "8px" }
})

// Mount the button to make it visible
playButton.mount()

// Handle clicks
playButton.onClick((event) => {
  const anime = event.media
  console.log(`Play all episodes for: ${anime.title.userPreferred}`)
  // Implement playback logic
})

newAnimePageDropdownItem

Creates a dropdown menu item that appears in the anime page's action menu.

Parameters:

  • props: Object containing:

    • label: String - Menu item text

    • style: Object (Optional) - Custom CSS styles

Example:

// Add a download option to anime page dropdown
const downloadItem = ctx.action.newAnimePageDropdownItem({
  label: "Download Episodes"
})

downloadItem.mount()

downloadItem.onClick((event) => {
  const anime = event.media
  console.log(`Preparing download for: ${anime.title.userPreferred}`)
  // Show download dialog
})

newAnimeLibraryDropdownItem

Creates a dropdown menu item that appears in the anime library's global action menu.

Parameters:

  • props: Object containing:

    • label: String - Menu item text

    • style: Object (Optional) - Custom CSS styles

Example:

// Add a scan option to library menu
const scanItem = ctx.action.newAnimeLibraryDropdownItem({
  label: "Scan for Missing Files"
})

scanItem.mount()

scanItem.onClick(() => {
  console.log("Starting library scan")
  // Implement scan logic
})

newMediaCardContextMenuItem

Creates a context menu item that appears when right-clicking on media cards.

Parameters:

  • props: Object containing:

    • label: String - Menu item text

    • for: String (Optional) - Which media types to show for ("anime", "manga", or "both")

    • style: Object (Optional) - Custom CSS styles

Example:

// Add a quick-watch option to anime cards
const watchItem = ctx.action.newMediaCardContextMenuItem({
  label: "Quick Watch",
  for: "anime" // Only show for anime cards
})

watchItem.mount()

watchItem.onClick((event) => {
  const media = event.media
  console.log(`Quick watching: ${media.title.userPreferred}`)
  // Implement quick watch feature
})

newMangaPageButton

Creates a button that appears on manga detail pages.

Parameters:

  • props: Object containing:

    • label: String - Button text

    • intent: String (Optional) - Button style ("primary", "success", "warning", etc.)

    • style: Object (Optional) - Custom CSS styles

Example:

// Create a read button for manga pages
const readButton = ctx.action.newMangaPageButton({
  label: "Continue Reading",
  intent: "primary"
})

readButton.mount()

readButton.onClick((event) => {
  const manga = event.media
  console.log(`Opening reader for: ${manga.title.userPreferred}`)
  // Open manga reader
})

newEpisodeCardContextMenuItem

Creates an item that appears on episode card context menus.

Parameters:

  • props: Object containing:

    • label: String - Button text

    • style: Object (Optional) - Custom CSS styles

const episodeDetailsButton = ctx.action.newEpisodeCardContextMenuItem({
  label: "View details",
})

episodeDetailsButton.mount()

episodeDetailsButton.onClick((event) => {
  // You get the episode object
  const episode = event.episode
})

newEpisodeGridItemMenuItem

Creates an item that appears on episode grid item menus.

Parameters:

  • props: Object containing:

    • label: String - Button text

    • type : "library" | "torrentstream" | "debridstream" | "onlinestream" | "undownloaded" | "medialinks" | "mediastream"

    • style: Object (Optional) - Custom CSS styles

const episodeDetailsButton = ctx.action.newEpisodeGridItemMenuItem({
  label: "View details",
  type: "library"
})

episodeDetailsButton.mount()

episodeDetailsButton.onClick((event) => {
  // You get the episode object
  // It is of type [Anime_Episode], unless the chosen type is 'onlinestream',
  // in which case it will be of type [Onlinestream_Episode]
  const episode = event.episode
})

Action Object Methods

All action objects share these common methods:

mount()

Makes the action visible in the UI.

Example:

const button = ctx.action.newAnimePageButton({ label: "My Button" })
button.mount() // Now visible

unmount()

Removes the action from the UI.

Example:

// Remove when no longer needed
button.unmount()

setLabel(label)

Updates the action's label text.

Parameters:

  • label: String - New label text

Example:

// Change button text based on state
if (isDownloading) {
  button.setLabel("Downloading...")
} else {
  button.setLabel("Download")
}

setStyle(style)

Updates the action's custom CSS styles.

Parameters:

  • style: Object - CSS style properties

Example:

// Highlight button when active
if (isActive) {
  button.setStyle({ backgroundColor: "#4caf50", color: "white" })
} else {
  button.setStyle({})
}

onClick(callback)

Sets a function to be called when the action is clicked.

Parameters:

  • callback: Function(event) - Function to call when clicked

Example:

button.onClick((event) => {
  // For anime/manga actions, event contains the media object
  if (event.media) {
    console.log(`Clicked on ${event.media.title.userPreferred}`)
  }
  
  // Your custom action logic
  performAction()
})

Additional Properties

AnimePageButton and MangaPageButton

These button types have an additional method:

setIntent(intent)

Sets the button's visual style.

Parameters:

  • intent: String - Intent style ("primary", "success", "warning", "error", etc.)

Example:

const button = ctx.action.newAnimePageButton({ label: "Watch" })
button.setIntent("primary") // Blue button
// Other options: "primary-subtle", "success", "warning", "alert", etc.

MediaCardContextMenuItem

This action type has an additional method:

setFor(type)

Sets which media types the context menu item appears for.

Parameters:

  • type: String - "anime", "manga", or "both"

Example:

const menuItem = ctx.action.newMediaCardContextMenuItem({ label: "Open" })
menuItem.setFor("anime") // Only show for anime cards

Best Practices

Limit Number of Actions

Each plugin is limited to a maximum of 3 actions per type. Choose the most important actions to display.

Dynamic UI Updates

Update action properties based on application state:

// Good: Update button state dynamically
let isProcessing = false

button.onClick((event) => {
  if (isProcessing) return
  
  isProcessing = true
  button.setLabel("Processing...")
  button.setIntent("warning")
  button.mount()
  
  performLongOperation().then(() => {
    isProcessing = false
    button.setLabel("Done!")
    button.setIntent("success")
    button.mount()
    
    // Reset after a delay
    setTimeout(() => {
      button.setLabel("Process Again")
      button.setIntent("primary")
      button.mount()
    }, 3000)
  })
})

Conditional Mounting

Only mount actions when they're relevant:

// Good: Mount/unmount based on context
function updateButtonVisibility(media) {
  if (media.format === "MOVIE") {
    watchButton.mount()
    episodesButton.unmount() // No episodes for movies
  } else {
    watchButton.mount()
    episodesButton.mount()
  }
}

PreviousCommand PaletteNextDOM

Last updated 16 days ago