Skip to content

feat(series): support user-created custom shows and episode ordering - #166

Merged
Aryan447 merged 3 commits into
mainfrom
feat/custom-series
Nov 9, 2026
Merged

Aryan447 merged 3 commits into
mainfrom
feat/custom-series

Conversation

@Aryan447

@Aryan447 Aryan447 commented Nov 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • User-created custom TV shows from arbitrary video files with custom title, release year, poster cover, and drag-and-drop episode reordering.
  • Explicit season and episode number editing per video item.
  • Exclude claimed videos from automatic scanner grouping to prevent duplicate entries in Shows or Movies.
  • Add entry points: "Add to series…" in Folders/Files selection mode and "Create series" in the Shows tab header.
  • SeriesDetailScreen renders custom shows with Edit and safe Delete actions (deleting only the grouping, never the video files).

Before / After

Feature Before After
Custom series support None (scanner-only grouping) Full Room v10 persistence & Builder UI
Selection actions Add to playlist Add to playlist + Add to series…
Shows tab header Search + layout toggle Search + Create series + layout toggle
Custom series deletion N/A Deletes grouping only (files preserved)

Verification

  • git diff --check
  • Room v9 -> v10 migration implemented
  • Unit tests added in CustomSeriesTest
  • CHANGELOG.md Unreleased entry

Summary by Sourcery

Support user-curated TV series built from existing videos while integrating them into library browsing and playback workflows.

New Features:

  • Allow users to create and edit custom TV series from arbitrary videos with custom metadata, artwork, episode ordering, and season/episode numbers.
  • Add custom-series creation and assignment actions from video selections and the Shows tab.
  • Display custom series alongside detected shows with editing and safe grouping-only deletion.

Bug Fixes:

  • Prevent videos assigned to custom series from being duplicated in automatically detected shows or movies.

Enhancements:

  • Persist custom series and episode assignments in Room with a version 9-to-10 database migration.
  • Add custom-series detail, builder, selection, and empty-state UI flows.

Documentation:

  • Document custom-series creation, management, and scanner exclusion behavior in the unreleased changelog.

Tests:

  • Add unit coverage for custom-series persistence models, claimed-file exclusion, episode mapping, and drag-reordering.

@sourcery-ai

sourcery-ai Bot commented Nov 7, 2026

Copy link
Copy Markdown

Sorry @Aryan447, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 1 day and 6 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-07T07:12:38.588477Z 2f61b96 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Deploying mpvium with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1eb85de
Status:⚡️  Build in progress...

View logs

@sourcery-ai

sourcery-ai Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Schema and migrations

Define the custom-series tables and Room v10 migration, register the entities and DAO, and wire the repository into dependency injection.

  • app/src/main/java/app/aryan447/mpvium/database/MpviumDatabase.kt L33-36 (+3 small edits)
  • app/src/main/java/app/aryan447/mpvium/database/entities/CustomSeriesEntity.kt L1-15
  • app/src/main/java/app/aryan447/mpvium/database/entities/CustomSeriesItemEntity.kt L1-31
  • app/src/main/java/app/aryan447/mpvium/di/DatabaseModule.kt L492-547, L563, L604-614

Data structures

Review the video model defaults and the custom-series DAO and repository contracts used by the scanner and UI.

  • app/src/main/java/app/aryan447/mpvium/database/dao/CustomSeriesDao.kt L1-82
  • app/src/main/java/app/aryan447/mpvium/database/repository/CustomSeriesRepository.kt L1-167
  • app/src/main/java/app/aryan447/mpvium/domain/media/model/Video.kt L10-25

Implementation

Check how custom items are excluded from automatic grouping and converted into series, episodes, and continue-watching entries.

  • app/src/main/java/app/aryan447/mpvium/domain/streaming/SeriesDetector.kt L189-205, L472-594 (+5 small edits)

Verify the compact timecode calculation for inverted-duration display.

  • app/src/main/java/app/aryan447/mpvium/ui/player/controls/components/Seekbar.kt L1073-1074

UI

Review the builder flow for creating and editing custom series, selecting videos, editing episode numbers, and reordering episodes.

  • app/src/main/java/app/aryan447/mpvium/ui/streaming/series/CustomSeriesBuilderScreen.kt L1-927

Check custom-series edit and deletion behavior in the series detail screen, including preservation of underlying files.

  • app/src/main/java/app/aryan447/mpvium/ui/streaming/series/SeriesDetailScreen.kt L133-137, L359-378, L678-732 (+8 small edits)

Review the Shows entry points and empty-state action for creating a custom series.

  • app/src/main/java/app/aryan447/mpvium/ui/streaming/series/SeriesGridScreen.kt L310-315 (+7 small edits)

Check selection-mode actions and add-to-series dialog wiring in the Files and Folders browsers.

  • app/src/main/java/app/aryan447/mpvium/ui/browser/components/BrowserTopBar.kt L475-488 (+4 small edits)
  • app/src/main/java/app/aryan447/mpvium/ui/browser/components/FloatingBottomBar.kt L21, L68-69, L190-211
  • app/src/main/java/app/aryan447/mpvium/ui/browser/dialogs/AddToSeriesDialog.kt L1-195
  • app/src/main/java/app/aryan447/mpvium/ui/browser/filesystem/FileSystemBrowserScreen.kt L1097-1112 (+4 small edits)
  • app/src/main/java/app/aryan447/mpvium/ui/browser/videolist/VideoListScreen.kt L590-605 (+4 small edits)

Review the user-facing labels and guidance for custom-series actions and screens.

  • app/src/main/res/values/strings.xml L728-748

Documentation

Read the changelog entry describing custom-series creation, entry points, detail integration, and scanner exclusion.

  • CHANGELOG.md L6-9

Tests

Check the custom-series tests for identifier format, claimed-file exclusion, episode mapping, and reorder behavior.

  • app/src/test/java/app/aryan447/mpvium/domain/streaming/CustomSeriesTest.kt L1-170

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f61b96887

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

val seasonsMap = customEpisodes
.groupBy { it.seasonNumber }
.mapValues { (_, eps) ->
eps.sortedWith(compareBy({ it.seasonNumber }, { it.episodeNumber }, { it.video.displayName }))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor the saved episode order

When a user drags episodes within the same season without renumbering them, the builder saves the new position, but this sort discards it. The detail screen and next-to-watch sequence therefore revert to episode-number order; use the saved position or renumber episodes on drag.

Useful? React with 👍 / 👎.

val clickEvent = LocalPlayerButtonsClickEvent.current
val interactionSource = remember { MutableInteractionSource() }
val currentText = Utils.prettyTime(position.toInt(), false)
val totalText = Utils.prettyTime(duration.toInt(), isInverted)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Compute remaining time from the playhead

When invertDuration is enabled, the existing duration timer formats position - duration to show time remaining. Passing only duration here cannot show the remaining time, so Cinema's timecode no longer honors that preference; format the inverted value from position - duration.

AGENTS.md reference: AGENTS.md:L100-L101

Useful? React with 👍 / 👎.


val customEpisodes = seriesItems.mapIndexed { idx, item ->
val video = videoByPath[item.filePath]
?: videoByName[item.fileName]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid resolving missing episodes by ambiguous basename

If a custom episode's path is absent from the current library index and another scanned video has the same filename (for example, 01.mkv in different season folders), this fallback can silently associate the episode with that other video. Only use the basename fallback when it identifies a unique video; otherwise retain the stored path.

Useful? React with 👍 / 👎.

Aryan447 added a commit that referenced this pull request Nov 7, 2026
Fix 4 distinct Kotlin compiler errors in CI:
- Video data class: add default argument values so callers constructing Video instances without media-store attributes compile cleanly
- SeriesDetector: pass fallback uri and displayName when synthesizing fallback Video instances
- CustomSeriesBuilderScreen: replace obsolete cafe.adriel.voyager Screen import with app.aryan447.mpvium.presentation.Screen, resolving Screen type mismatches in callers
- VideoPickerSheet: resolve videos from MediaFileRepository bucket query and library items instead of nonexistent VideoFolder.videos
- SeriesGridScreen: pass onCreateSeries callback to SeriesGridContent to fix unresolved backstack reference in empty-state action

Method: unmeasured; fixes compilation errors from PR #166
- Add custom_series and custom_series_item Room v10 tables with MIGRATION_9_10
- Exclude claimed custom series videos from scanner grouping to avoid duplicate entries
- Provide 'Add to series…' in Folders/Files selection mode and 'Create series' in Shows
- Add CustomSeriesBuilderScreen with drag-reorder, explicit season/episodes, and poster picker
- Render custom series in SeriesDetailScreen with Edit and non-destructive Delete grouping
- Add unit tests in CustomSeriesTest and update CHANGELOG.md
Fix 4 distinct Kotlin compiler errors in CI:
- Video data class: add default argument values so callers constructing Video instances without media-store attributes compile cleanly
- SeriesDetector: pass fallback uri and displayName when synthesizing fallback Video instances
- CustomSeriesBuilderScreen: replace obsolete cafe.adriel.voyager Screen import with app.aryan447.mpvium.presentation.Screen, resolving Screen type mismatches in callers
- VideoPickerSheet: resolve videos from MediaFileRepository bucket query and library items instead of nonexistent VideoFolder.videos
- SeriesGridScreen: pass onCreateSeries callback to SeriesGridContent to fix unresolved backstack reference in empty-state action

Method: unmeasured; fixes compilation errors from PR #166
- Honor saved episode position by preserving custom episode order within seasons
- Avoid ambiguous basename resolution by filtering only unique display names
- Compute inverted duration in CompactTimecode from position - duration

Method: unmeasured; fixes review feedback from Codex
@Aryan447
Aryan447 merged commit aafcd4b into main Nov 9, 2026
5 of 7 checks passed
@Aryan447
Aryan447 deleted the feat/custom-series branch November 9, 2026 06:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant