Repository navigation
Conversation
- Added a `selection` option to `LanguagesModal` that hands the picked languages to the caller instead of saving a settings preference, with `multiple: false` for a single pick and `noneLabel` for an explicit "no language" choice - Added an `exclude` option to leave pseudo-languages out of the list - Kept every existing call site unchanged
…ion to `BackgroundImagePlaceholderDiv` - Added a `compact` option to `MultiStateButton` for narrower, lower buttons sized to their labels, for a toolbar - Added a `position` option to `BackgroundImagePlaceholderDiv` that sets where the image sits in its frame
- Added the Airing Schedule utility, with month, week and agenda views of `GET AiringSchedule/Calendar`, under the utilities menu - Put the refresh, scope and channel toggles in a toolbar, the view switcher and the period navigation beside it, and the period in the title, sliding in the direction of travel - Moved the channel filter, airing kind and provider behind a settings gear, kept with the last view for the session - Kept the month and week grids while they load, with skeletons in each day, and drew only the agenda rows in view - Refetched the airings on the `airing` feed's sweeps, marked what is on air now and which episodes have local files, and let debug builds shift the schedule's clock
- Added a season view, now the default, listing a season's anime in the server's sections with their next new episode and a countdown, as cards in one to three columns drawn only while in view - Picked the season from a slider kept in view while scrolling, and browsed every season by year from it, in place of a separate archive view - Returned to the slider, or to where you were, after picking a season or closing the browser, and kept the slider pinned while the browser opens - Showed skeleton cards while a season or the browser loads, and refetched the season's anime every few minutes and on the `airing` feed's sweeps - Added the season view's oldest year to the airing schedule's settings modal, saved to the user's WebUI settings once typing pauses
- Added `SequenceNumber` and `IsResolved` to the airing, and `includeUnresolved` to the airing reads - Labelled an unresolved airing `Ep N` from its `Number`, with a muted "Not on AniDB yet" hint in the entries, cards and the dashboard widget - Linked an unresolved airing to its series rather than an episode, and showed no local files for it
- Added a "Show Recently Aired" switch and its hours, 1 to 24, to the airing schedule settings modal, saved in `WebUI_Settings.airingSchedule.recentlyAired` - Read the current and previous seasons' sections with `at` that many hours back, rounded down to 15 minutes, so a card keeps an episode that aired since - Kept a season's cards while the next 15 minute step is read, which moves them on - Showed how long ago a card's episode aired, by the clock, in place of "Just aired"
- Split the settings modal into General and Sections tabs - Added a draggable section list with an inline editor for the title, anime types, continuing and half length, saved as you edit to `airingSchedule.sections` - The season view always reads its sections by `POST`, with the saved layout or `null` for the server default, and hides the empty ones - Dropped the section `ID`; sections are keyed by their place in the layout
- Added an "Episode Types" multi-select to the General tab, saved to `airingSchedule.episodeTypes`, `null` for every type - Sent the types as `episodeType` on the season sections read and as `type` on the calendar read
- Read `Season` and `Season/ByYear` by POST with the stored layout, which joined their query keys - Showed the left-out hint only for a custom layout without a rest group
This was referenced Oct 7, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Part 1 of 3, split from #1497. The server now has an airing schedule service (
/api/v3/AiringSchedule/*): provider plugins (AnimeSchedule.net, Syoboi Calendar, TVmaze and others) supply timed broadcast and streaming airings, with channels, delays and sub/dub tracks. The WebUI had no way to see those airings.This part adds the Airing Schedule utility page. It stands on its own: nothing outside this part is needed to review or run it.
Stack: this PR targets
master. #1501 (feat/airing-schedule-part-2, the dashboard widget) and #1502 (feat/airing-schedule-part-3, the settings page) build on this branch.Server: needs the airing schedule routes from current core master (6.0 alpha, unreleased). Against an older core the page fails to load.
What's in this part
Utilities > Airing Schedule(/webui/utilities/airing-schedule), with Season (the default), Month, Week and Agenda views.Toolbar and header
Airing Schedule | <period>; the period slides out and in the direction of travel (forward for later, back for earlier), and swaps at once on a view switch or with reduced motion. The header's right side counts the anime, seasons or airings shown.R), My Collection / All Series, Every Channel, Hide Estimates, Show Reruns. Beside it, in boxes of their own that wrap together: the view switcher (Season | Month | Week | Agenda), the navigation (previous, today or current season, next) and a settings gear.viewin the URL the page opens on the last view used (Redux, for the session). Series without files are always shown (the "Include Series Without Files" option andincludeMissingare gone).Month, Week, Agenda (read from
GET AiringSchedule/Calendar, grouped and sorted on the server)+N moreopens that day's week.+N morelists the others in place (a popover in the month's rows). Reruns only with Show Reruns, with a badge. Date-only episodes (AniDB air date) are all-day entries. Delayed airings show at their new slot. Hover shortcut on a channel to hide it, with Undo.Nowbadge on an airing while it is on air (AiredAtuntilEndsAt), tooltip "On air until HH:mm".VideoCount), with the count in its tooltip.IsResolved: false) readsEp Nfrom itsNumber, with a muted "Not on AniDB yet" hint, links to its series and never shows the files icon.Season
GET AiringSchedule/Season/ByYearwithout images.data-stuck, judged from the layout on scroll and resize).browse=true), so Back closes it; closing steps back over that entry; a pick replaces it, so Back then returns to the page before the browser opened.Esccloses it.POST AiringSchedule/Season/{year}/{season}/Sections): the server's sections (TV & Web, Half Length, Continuing, Movies, OVAs & Specials) and order, or the user's layout; empty sections are hidden; countdown to the next new episode, its regular slot and provider icon, the episode length, "Airing now" with "ends in ..." while on air and "Aired 30m ago" after; the files icon; source, overview, top tags, Missing Files / In Collection.getGridColumnCount), withminmax(0, 1fr)so phones never scroll sideways. Both are virtual lists on the page's scroll container.WebUI_Settings.airingSchedule.recentlyAired. While on, the current and previous seasons' sections are read withatthat many hours back, rounded down to 15 minutes, so a card keeps an episode that just aired ("Aired 2h ago", by the clock) and moves on as the next 15 minute step is read. The season list and the calendar views never send it.WebUI_Settings.airingSchedule.oldestSeasonYearand sent asfromYear.WebUI_Settings.airingSchedule.sections(nullfollows the server default fromGET AiringSchedule/Season/Sections/Default, which the first edit copies). Muted hints flag a section after a rest group and a layout with no rest group. The sections read always POSTs{ Sections },nullfor the default.WebUI_Settings.airingSchedule.episodeTypes(nullfor every type). It is sent asepisodeTypeon the season sections read and astypeon the calendar reads.Loading and data
AiringProvidersContext).airing:provider.sweptandairing:episode.airedinvalidate the calendar and the sections.useNow) for every countdown and on-air mark.Debug builds only:
?clockOffset=A signed offset (
-90m,7h40m,-1d6h) shifts the page's clock (still ticking): today, the current season, the default period and the slider. While shifted, the season, years and sections reads sendatwith the shifted time so the server agrees, and the header shows the shifted clock. Ignored in production builds.Look first at:
src/pages/utilities/AiringSchedule.tsx,src/components/Utilities/AiringSchedule/(SeasonView,SeasonSlider,SeasonBrowser,SeasonCard,CalendarViews,AiringEntry,Skeleton),src/core/utilities/seasonSlider.ts,seasonGrid.ts,airingSchedule.ts,clock.ts,src/hooks/useNow.ts.Shared with the other parts
Things that live in this part but exist for, or are also used by, parts 2 and 3 — review them knowing they have other consumers:
src/components/Dialogs/LanguagesModal.tsx— the opt-inselectionAPI (single pick viamultiple: false,noneLabel,exclude). No existing call site changes. Part 3's Preferred Tracks language pick is its first new consumer.src/core/react-query/airing-schedule/(queries.ts,types.ts,helpers.ts) andsrc/core/types/api/airing-schedule.ts— the calendar/provider read layer. Part 2 readsuseAiringCalendarQueryfor the dashboard widget; part 3 adds the configuration and channel queries on top.src/core/utilities/airingChannels.ts(+tests/core/utilities/airingChannels.test.ts) — channel search/grouping shared by this part's channel filter and part 3's channel administration (which extends it).src/components/AiringProviderIcon.tsxandsrc/components/AiringChannelCountryBadge.tsx— used by the views here, by part 2's widget cards, and by part 3's provider and channel lists.src/core/utilities/airingSchedule.ts(CalendarEntrygrouping,toAiringRequestDates,getLocalTimeZone) — also drives part 2's timeline.src/components/Input/MultiStateButton.tsx(compact) andsrc/components/BackgroundImagePlaceholderDiv.tsx(position) — generic component options added here for this page's toolbar and cards; available to later parts and the rest of the UI.IsResolved/SequenceNumberfields, theincludeUnresolvedread parameter and the page's handling (entries, season cards) are here; the same treatment for the dashboard widget'sAiringDetailsis in part 2, because that file is created there.src/core/types/api/settings.tsandsrc/core/react-query/settings/helpers.ts—WebUI_Settings.airingSchedule.*(oldestSeasonYear, recentlyAired, sections, episodeTypes) is this part's; part 2 adds the dashboard widget's own keys to the same files.src/core/router/index.tsxandsrc/components/Layout/TopNav.tsx— the utility route/menu entry here; part 3 adds its settings route to the same router file.Testing
pnpm lint,pnpm tscheckandpnpm buildclean on the tip;pnpm testincludes the new suites: season boundaries, the slider strip and browser history/scroll rules, grid columns, the clock offset, channel search. No dependency changes.channel=on every read) and hide shortcut.To try: open
Utilities > Airing Schedule, step through seasons with the slider, open the browser from the pill and use Back; switch to Week and go back a week or two to see the files icon on episodes you have.Feedback wanted
VITE_MIN_SERVER_VERSIONis unchanged; no released server has these routes yet, so which build should it require??clockOffset=in the shipped code, or drop it before merging?