# 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:**

```typescript
// 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:**

```typescript
// 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:**

```typescript
// 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:**

```typescript
// 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:**

```typescript
// 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
  * `type?` : "library" | "torrentstream" | "debridstream" | string | undefined

{% hint style="info" %}
`type` can also be `episodeTab:<extension-id>` when using `ctx.anime.registerEntryEpisodeTab`
{% endhint %}

```typescript
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" | string
  * `style`: Object (Optional) - Custom CSS styles

{% hint style="info" %}
`type` can also be `episodeTab:<extension-id>` when using `ctx.anime.registerEntryEpisodeTab`
{% endhint %}

```typescript
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:**

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

#### unmount()

Removes the action from the UI.

**Example:**

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

#### setLabel(label)

Updates the action's label text.

**Parameters:**

* `label`: String - New label text

**Example:**

```typescript
// 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:**

```typescript
// 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:**

```typescript
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:**

```typescript
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:**

```typescript
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:

```typescript
// 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:

```typescript
// 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()
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://seanime.gitbook.io/seanime-extensions/plugins/ui/user-interface/action.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
