Features:
- Full EPG grid with channels and time slots
- 12-hour program window with auto-refresh every 5 minutes
- Duration-based cell widths (3px/min)
- Live program highlighting with progress bars
- Current time indicator (red line)
- Direct channel playback from guide
- Auto-scroll to currently airing programs
Changes:
- Add EPGViewModel for data fetching and state management
- Add EPGProgramCell, EPGChannelRow, EPGTimelineHeader, EPGCurrentTimeIndicator components
- Update ProgramGuideView with complete EPG implementation
- Make Channels default Live TV tab (was Program Guide)
- Fix channel images in EPG to match Channels view display
- Fix Live TV playback crash (audioStreams array bounds check)
- Apply dark pink background throughout app
Slash Commands:
- Add /init-dev - Initialize dev session with project context
- Add /sim - Build and launch in Apple TV simulator
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Add .channel to BaseItemKind.supportedCases for proper filtering
- Implement channel API routing in ItemLibraryViewModel
- Add comprehensive debug logging to track API calls and filtering
- Support channels in MediaViewModel library views
- Fix channel items not appearing in media libraries
This enables Xtream plugin channels (VOD/Series) to display correctly
in jellypig tvOS. Channels now use proper /Channels API endpoints
instead of falling back to regular /Items API.
Related to ongoing fix for Xtream content media display.
- Modified ItemLibraryViewModel to detect channel/channelFolderItem types
- Added getChannelItems() method to use Paths.getChannelItems API for channels
- Channel folders now use channelID and folderID parameters correctly
- Modified PagingLibraryView to route .channelFolderItem to library grid view
This enables proper navigation for Jellyfin.Xtream plugin channels:
Channel → Grid of Categories → Grid of Content → Item Detail
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Renamed SwiftfinApp.swift to jellypigapp.swift
- Renamed SwiftfinStore/ to jellypigstore/
- Renamed all SwiftfinStore files to jellypigstore
- Renamed SwiftfinDefaults.swift to jellypigdefaults.swift
- Renamed VideoPlayerType+Swiftfin.swift to VideoPlayerType+jellypig.swift
- Updated all project.pbxproj file references to match new names
All file names now use lowercase jellypig for consistency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* off recursive
* pr feedback
* Cleanup
Instantiate the collectionType in the `if let` since failure to cast `as? BaseItemDto` should count as false as well. Only set `parameters.isRecursive` once in if/else opposed to if -> override.
* wip
* fix recursive and item kinds
* rename, fix folders
---------
Co-authored-by: Quang <quang.ha@a2:3c:68:56:26:8d.home>
Co-authored-by: Joe <jpkribs@outlook.com>
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
Co-authored-by: Quang <quang.ha@QrM3P.local>
* WIP
* Remove Divider
* self deprecation message
* `OrderedDictionary<BaseItemKind, [BaseItemDto]>`
* Localization fun
* cleanup
* Remove play button items & order by BaseItemKind.
* Fix AttributesHStack on iPad and make sure they align to the correct side. Looks jarring on Collections since Collections are often more limited on AttributesHStack items.
* Localization fix
* cleanup
* cleanup
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* first string
* add a bunch of localization
* more hardcode to localization
* small changes for two strings
* fix space formatting
* Update Localizable.strings
Put the localizations back in. Don't know why this changes anything but 🤷♂️
* Fix encoding
Why???
Also, missing ;
* implement requested changes
---------
Co-authored-by: Joe Kribs <jpkribs@outlook.com>
* Very Very WIP
* Details page.
TODOs:
- Duplicate ViewModels are initialized.
- Routing Cleanup
- Localizations for fields
- Get Played Item Details (See ActiveSessionDetails)
- Move all details to ActivityDetailsViewModel for Users & Items
- Localizations for enums
- Enum the types if possible
* Details View complete. TODO:
- Filters
- Default with No Filters
* Ready
* Fix localization
* cleanup
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Buildable!
* Update file names.
* Default sort to sort name NOT name.
* SessionInfoDto vs SessionInfo
* Targetting
* Fix many invalid `ItemSortBy` existing. Will need to revisit later to see which can still be used!
* ExtraTypes Patch.
* Move from Binding to OnChange. Tested and Working.
* Update README.md
Update README to use 10.10.6. Bumped up from 10.8.13
* Update to Main on https://github.com/jellyfin/jellyfin-sdk-swift.git
* Now using https://github.com/jellyfin/jellyfin-sdk-swift.git again!
* Paths.getUserViews() userId moved to parameters
* Fix ViewModels where -Dto suffixes were removed by https://github.com/jellyfin/Swiftfin/pull/1465 auto-merge.
* SupportedCaseIterable
* tvOS supportedCases fixes for build issue.
* cleanup
* update API to 0.5.1 and correct VideoRangeTypes.
* Remove deviceProfile.responseProfiles = videoPlayer.responseProfiles
* Second to last adjustment:
Resolved: // TODO: 10.10 - Filter to only valid SortBy's for each BaseItemKind.
Last outstanding item: // TODO: 10.10 - What should authenticationProviderID & passwordResetProviderID be?
* Trailers itemID must precede userID
* Force User Policy to exist.
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* ItemViewModel Trailers
* iOS done.
* Sections >>> Divider
* tvOS kind of.
* Button/Menu cleanup
* Huge ActionButton overhaul
* Error Handling, ActionButton/Menu standardization, and ActionButtonLayout cleanup part 1.
* cleanup
* cleanup
* Combine ActionButton logic. Complete ActionButton rework and animation/style rework. Should this be 3 files??
* Dumb sizing error. Get size from WIDTH not HEIGHT! Height is always 100 and Width is larger.
* Pressed buttons are but focused buttons but slight less. Pressed buttons are still bigger than default, unfocused buttons. TIL.
* Cleanup / Structure
* Remove Test.
* New Setting. Version on PlayButton Row. Complete TrailerMenu revamp. Make ActionButtonLayout a single row.
* Spacing & remove test logic
* VERY WIP
* Fix the compact-ness
* Linting.
* Remove Testing logic.
* Pre-Cleanup - WIP
* Finalized. Moved ScrollingText to tvOS Only.
* MediaURL? = nil but it's already nil by default.
* Error on the View not the button. This was NOT showing for the button since it lived on the Menu. This resolves this.
* wip
* Update VersionMenu.swift
* Remove scrollingText from this PR.
* Remove labels & iOS Action Button cleanup / no foregroundStyle on de-selected.
* ActionButtonScaling
* .card all buttons in ActionButton
* Slow and less bounce-i-fy the menu animations. Also, slight padding
* Wait, don't add this padding this isn't needed.
* localize
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Filter Changes
* Use `viewModel.modifiedFilters` for tracking if the filter has been modified. Update the init and update. Hold only the modified filters in `modifiedFilters` instead of `(modifiedFilters, bool)` since that's just clunky and unnecessary.
* Reset button should be disabled when only THAT filter is non-default.
* ...
* PagingLIbraryViewModel.filterQueryTask is no longer in use since that should now be handled on the FilterViewModel
* fix merge
* cleanup
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Move ItemType to Filter
* Init but normally...
* filter on people?
* Default to easiest / least change solution.
* Reset `.collectionFolder`, `.folder`, and `.BaseItemPerson` in `PagingLibraryView` to have the default filters. This was originally in place. This Commit just ensures that iOS and tvOS have the same implementation.
* wip
* Update ItemLibraryViewModel.swift
* Update ItemLibraryViewModel.swift
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Add function to update basic server info
* Add server info update in server check view model
* Update ServerCheckViewModel.swift
---------
Co-authored-by: chickdan <=>
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Good start but some missing items:
- Upload image isn't working
- Only a single image is shown per section. Need to make this the HCollection of all images for the group
* Upload still failing but now update and set are 2 different processes because I think that's better. Spacing on the add screen is still all wrong but we're getting closer
* ~70% Complete
TODO:
- Spacing for remote portrait images is wrong & cramped
- Upload image from file browser never works & produces 400 error
- Show all images for an item.imageType opposed to just the first
- Setting image works but produces a 400 error
- Error alert looks bad
* Merge with Main
* URL Changes
* Updating logic and confirmation screen
* Lots of changes:
Selecting a Remote image is now working without error and works consistently!
Upload a local file is still broken
Item types with multiple images is working as intended now!
Overriding an image on index doesn't seem to work but it doesn't work for Web either so........
UI is way more jank but the hard parts are getting solved!
* Breaking this even more with the hopes of a better tomorrow.
* Getting better?
* Refreshing is working but I might need to make this work mroe effiently...
* 90% There!
* Ability to cancel the update
* Still no luck uploading images?
* Stop reordering on deletion/addition
* 2025 disclaimers
* Uploading finally works!
* Functional but messy.
TODO:
- Figure out better resizing if too big?
- Upload from Photos
- Move upload logic to imageViewModel and make RemtoeImageViewModel PagingLibraryViewModel conformant
- Create a ImageInfoView for Selection & Deletion.
* Now conforms to PagingLIbraryViewModel but everything else is a mess
* Close!
* First no all appears
* Fix double pop/routerdismiss
* Uploading from Photos is (Finally) Ready!
* wip
* Reuse PhotoPicker and Crop code.
* 4/6 of the codefactor changes
* Pass around the URL NOT the UIImage
* Clean up ItemImageDetails types.
* Make sure the ImageView mirrors the real shape of the image. Posters should be uniform but this is the selection for the image so the dimensions are important to demonstrate.
* Rating Type label.
* Delete confirmation dialog.
* Remove double sizing. Remove Unused ViewModel. Change PhotoPicker to a checkmark instead a 1. Since there is only ever one picture selected, no need to count the images.
* Get the image URL as needed. No more Truples. Localize ImageTypes.
* Remove attempt at ImageInfo Poster Comformance.
* Even more cleanup
* Delete vs Save flip
* Hide delete button
* Even more cleanup
* Fix tvOS build issues.
* Reduce delay & remove unused comment. Should finally be ready again.
* wip
* Update ItemImagesView.swift
* Event Only on upload failures.
* Remove unnecessary ViewModel's from tvOS.
* Add dismiss action to RemoteSearchResultView. While I am doing this here, fix it there.
* Move From Coordinator -> .Sheet. This fixes the popping issue / delay requirement!
* wip
* wip
* wip
* wip
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Edit View. Still need to make an Add View
* Finished with EditPage. Need labels tho
* Deletion deletes TOO many records. Also, need to search existing tags
* Fin
* Fix merge issues
* Check for exisitng Access Tags before allowing saving
* 2025 Disclaimer / Build Fixes
* update
* Update EditServerUserAccessTagsView.swift
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Make user profile more generic. Still need to make it work for the reset image / other stuff like delete & username.
* Username Changing and PFP deletion.
* Functional, refreshing, and good to go!
* Clean up localizations
* Migrate [UserDto] -> IdentifiedArrayOf<UserDto>
* Solve "Username should probably be at the top of this section."
* allow notification filter
* WIP:
Created `UserProfileHeroImage` but I haven't used it anywhere.
* Centralize UserProfileHeroImages
* Rename UserProfileImages
* Fix Merge Issue?
* Move to UserProfileImage
* Merge with Main
* Fix Merge?
* Clear the cache on update.
* Delete duplicate `UserProfileImage`
* wip
* wip
* Update ImagePipeline.swift
* fix tvOS build issue and update comment to be more accurate
* clean up
* fix string
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Mirror tvOS to iOS
* Fix router dismiss. Remove redundent viewModel.refresh from itemView
* reset dev team info
* View Modifier and ViewModel cleanup
* Remove testing comments / events
* Cleanup `.errorMessage($error)`
* Cleanup all viewModel.states for item editing, add errorViews if the data fails to load, and add errorMessage on failed events.
MARK sections: Var/Func always unless only Body and Var/Lets only if there are several of varying types / functions.
* Cleanup / Genre & Tag Management
* Move searching to a backgroundState. Fix the font Color when bulk editing tags / genres should be secondary when editing & not selected
* Cleanup
* Now that cancelling is handled better this should prevent the issue where the suggestions fails to update on a letter entry
* Change from using an event for searchResults to using a published searchResults var
* Moved all logic to a local list where all genres/tags are populated on refresh then filterd locally instead of calling the server for changes.
* Inheritance
* Split metadata from components then alphabetize. Also, fix but where you can't add a people
* People & Permissions
* Functional but dirty. TODO: Cleanup + Trie? Trei?
* nil coalescing operator is only evaluated if the lhs is nil, coalescing operator with nil as rhs is redundant
* TODO: Search improvements & Delay search on name change
* Cleanup & reordering
* Debouncing
* Trie implementation
* Permissions Cleanup Squeezing in: https://github.com/jellyfin/jellyfin-web/issues/6361
* enhance Trie
* cleanup
* cleanup
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* ServerUserAdminViewModel cleanup & testing. ServerUserAccessView.
* Change the enableAllLibraries to use the binding extensions
* Use coalesce for enableAllFolders & enableContentDeletion
* use contains binding
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Playback Quality - Learn More
* TODO: Fix leading not working on second line.
* Remove layoutDirection.
* Implement for tvOS. Slightly different spacing.
* VStack
* WIP - tvOS Implementaiton. SUBJECT TO CHANGE / ELIMINATION.
* Background Icon & formatting
* wip
* Review Changes. Remove unused Strings, clean up comments.
* Remove duplicate items used for testing
* Remove tvOS scrollIfLargerThanContainer for now.
* Edit Text-based Metadata
* ViewModel Cleanup
* use binding extensions
* Huge overhaul:
- Fix the notification when metadata was updated to work with 100% consistency
- Flip the locking to be true -> lock like server
- Redo the whole itemEditorViewModel to be more in-line with other viewModels | also fixes iPad weirdness
- Use itemViewModel for the edit view so I can just reuse those existing notifications instead of recreating the wheel
- More human dates for people - Date of death instead of "End date" (yikes)
* String fixes & overview size
* Fix build issues & String cleanup
* fix overview sizing, cleanup
* itemMetadataWasEdited -> temMetadataDidChange
* Creation of the NavigationBarMenuButtonModifier for an "ellipsis.circle" menu object in the toolbar. Makes it easier to ensure that this format looks the same throughout.
* Custom vs Official Rating + Menu Button Label change
* Menu button spacing and groundwork for other menu items (canDownload) since we already have the bool available. Currently disabled.
* Linting
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* WIP
* WIP
* Localization and better planning. Remove the Username as this will end up in another section. Updated planning here: https://github.com/jellyfin/Swiftfin/discussions/1283 | 5 more views required!
* Initializing an optional variable with nil is redundant line
* Remove Live TV since that will go in another section
* Cleanup Coordinator / Merge with Main
* Remove all 'Allows' from strings
* Fix Merge Issues
* Use CaseIterablePicker, Binding.map
* BackgroundState == updating, change all of the buttons to visible when custom by process of elimination opposed to the default custom value. Make all of the input fields use temp values to make it less jarring.
* Update SessionsSection.swift
* Learn more!
* Validate > 0, don't allow inputs to be less than 1 and reset tempValues when the enum is updated.
* use new binding extensions
* String fixes
* Don't test against adminDefault for users or userDefault for admins.
* Linting indentation
* Default vs UserDefault + no more reason to have temporary variables.
* cleanup
* format
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* [iOS] Creation of the enableItemEditor & enableItemDeletion settings. Creation of the ItemEditorView. Creation of Refresh/Deletion Logic and Buttons. Wrap buttons in permissions.
* You can make delete permissions without edit (admin) permissions. So, flip this so you can get to the edit page but editing is disabled if you're not an admin. The Delete option requires that the delete toggle is enabled and the user has permissions.
* Move deletion from the editView to the ItemView
* Delete from PagingLibraryView on Deletion
* Only enable delete if the user can delete something. Check deletion permission on Item level. Only allow editing for admins.
* Review Changes: ec33a6b63c
* wip
* Update RefreshMetadataButton.swift
* Update Shared/ViewModels/ItemEditorViewModel/RefreshMetadataViewModel.swift
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Update Shared/Coordinators/ItemEditorCoordinator.swift
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Reviews minus a learn more button
* LearnMoreAttempt v1
* Learn more v2 - Much better
* Learn More v3
* Learn More comments cleanup
* Learn More: https://github.com/jellyfin/Swiftfin/pull/1310#discussion_r1843149572
* clean up
* Remove Replace since it's already covered. Localize.
* clean up
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* resetUserPassword Adjustments
* Nest the Password in Advanced because I dunno it looks nicer.
* Dismiss Coordinator instead of pop.
* Build issues
* Rename my local xcode to xcode_16???
* Build plz
* Comments
* clean up
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Migrate all files from UserDashboard to AdminDashboard. Rename accordingly since this is an admin only function. Move all AdminDashboard items from SettingsCoordinator to their own AdminDashboardCoordinator. Move all ViewModels to ONLY live inside of the iOS build since tvOS is
* cleanup
* fix for sub navigation
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* API Keys
* Switch Deletion Alert for a Confirmation Dialog
* Migrate from a list to a Collection VGrid.
* Convert back to List. Also, now using my events! So, there is a confirmation and a failure message for both delete & create API.
* want vs wish
* Merge Issue Fixes
* Review Changes
* Reset newAPIName after creating a new API
* cleanup
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* All Working. TODO: Figure out why TimeInterval crashes Swiftfin if I select 'Cancel'
* Cleanup. Kind of a typeAlias but not really? Fixed the minute crash, I was make a recursive calc. All good now. Make sure temp values default to existing value at startup
* Manual Run action from Edit View
* Issues resolved.
* Labels / soft merge with Main
* Utilize events to print a success/failure message for when there is an attempted change with a TaskTrigger.
* Fix label wrong value & remove TODO for completed item.
* Fix all the merge issues.
* wip
* wip
* localize
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Split out Devices Logic - Ready to go!
* Review Items + Reworking the deleteDevices logic to all use the same deleteDevice core + deleteDevices. Delete All Devices now just uses the more generic deleteDevices
* Allow Filtering on UserID for later usage on UserDetailView.
* Fully remove DeleteAll action in favor of Delete Devices. Change view to pass in the viewModel.devices as a 'Delete All' function
* DeviceDetailsView
* Section Split out, Localization, and cleanup.
* I guess I missed there on first upload.
* Initial Select All / Delete Devices logic. Checkbox options on the list. Hopefully this is good.
* Initial Review Item!
* Custom Device Name is now a field. Change DevicesViewModel to Eventful to capture updates
* Revised Device Interaction Buttons
* Remove unused Label.
* Make DeviceRow mirror UserRow. UpdateDevicesView to have DeleteButton when in EditMode. Also, it's EDITMODE not SELECTMODE... Finally, make sure the SelectedDevice and SelectedDevices are both empty if the user tries to delete themselves and fails. Change how the single device delete works to confirm deleting from an array still works as needed.
* wip
* Review Changes: 61b3716239
* Merge issues + testing again to make sure. Checks out.
* wip
---------
Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
* Rebasing https://github.com/jellyfin/Swiftfin/pull/1212 on Main. Also, less baggage and random crap.
* Change 0 to Disabled. Better mirror iOS and tvOS Alerts for MaxNextUpDays.
* Review Changes:
Don't use the property wrappers in non-view contexts. While they technically can still work, use the subscript instead at the usage sites.
Use the dayInterval(0 ... 1000) format instead, then we don't need maxNextUpDays.
* Remove unused strings, and unused variables
* Add a tvOS TODO to double check the Done/Number button on the alert.
* Change password to be a SecureField and autosubmit on password completion
* Fix SelectUser Button
* Respond to comments and remove unnecessary changes
* Make FocusField a private enum