260 lines
9.7 KiB
Markdown
260 lines
9.7 KiB
Markdown
# Jellyfin SRF Play Plugin
|
|
|
|
A Jellyfin plugin for accessing SRF Play (Swiss Radio and Television) video-on-demand content and live sports streaming.
|
|
|
|
## Status
|
|
|
|
**Beta/Alpha** - This plugin has been tested on two Jellyfin instances and is working. Some clients may experience issues with hardware decoding, which appears to be client-specific behavior.
|
|
|
|
## Features
|
|
|
|
- Access to SRF Play VOD content (video-on-demand, no DRM-protected content)
|
|
- **Live Sports Streaming** - Watch scheduled sports events (skiing, Formula 1, football, tennis, etc.)
|
|
- Support for all Swiss broadcasting units (SRF, RTS, RSI, RTR, SWI)
|
|
- Automatic content expiration handling
|
|
- Latest and trending content discovery
|
|
- Quality selection (Auto, SD, HD)
|
|
- HLS streaming support with Akamai token authentication
|
|
- Proxy support for routing traffic through alternate gateways
|
|
- Smart caching with reduced TTL for upcoming livestreams
|
|
|
|
## Screenshots
|
|
|
|
### Channel Menu
|
|

|
|
|
|
The main channel interface showing the content folders.
|
|
### Playback
|
|

|
|
|
|
Video playback with HLS streaming support and quality selection.
|
|
|
|
## Testing
|
|
|
|
The plugin includes comprehensive testing:
|
|
|
|
- **Unit tests** (xUnit framework) for core services
|
|
- **API spec validation tests** for all business units (SRF, RTS, RSI, RTR, SWI)
|
|
- **Integration testing** - Tested on multiple Jellyfin instances with VOD and live sports streaming
|
|
|
|
**Run tests:**
|
|
```bash
|
|
# All tests
|
|
dotnet test
|
|
|
|
# Unit tests only
|
|
dotnet test --filter "Category!=Integration&Category!=APISpec"
|
|
|
|
# API spec tests only
|
|
dotnet test --filter "Category=APISpec"
|
|
|
|
# With coverage
|
|
dotnet test --collect:"XPlat Code Coverage"
|
|
```
|
|
|
|
See [Test Documentation](Jellyfin.Plugin.SRFPlay.Tests/README.md) for more details.
|
|
|
|
## API Information
|
|
|
|
**Base URL:** `https://il.srgssr.ch/integrationlayer/2.0/`
|
|
|
|
### Key Endpoints
|
|
|
|
**Integration Layer API v2.0:**
|
|
- `GET /mediaComposition/byUrn/{urn}` - Get video metadata and playable URLs
|
|
- `GET /video/{businessUnit}/latest` - Get latest videos
|
|
- `GET /video/{businessUnit}/trending` - Get trending videos
|
|
|
|
**Play v3 API:**
|
|
- `GET /play/v3/api/{bu}/production/livestreams?eventType=SPORT` - Get scheduled sports livestreams
|
|
- `GET /play/v3/api/{bu}/production/shows/{id}` - Get show details
|
|
- `GET /play/v3/api/{bu}/production/videos-by-show-id?showId={id}` - Get episodes for a show
|
|
|
|
**Akamai Token Service:**
|
|
- `GET /akahd/token?acl=/{path}/*` - Authenticate stream URLs for playback
|
|
|
|
### URN Format
|
|
|
|
- `urn:{bu}:video:{id}` - Video URN (VOD content)
|
|
- `urn:{bu}:scheduled_livestream:video:{id}` - Scheduled sports livestream URN (supported)
|
|
- `urn:{bu}:video:livestream_{channel}` - Live TV channel URN (not supported due to Widevine DRM)
|
|
|
|
Examples:
|
|
- `urn:srf:video:c4927fcf-4ab4-4bcf-be4e-00e4ee9e6d6b` (VOD)
|
|
- `urn:srf:scheduled_livestream:video:7b31c9a6-a96e-4c0e-bfc2-f0d6237f2233` (Sports event)
|
|
- `urn:srf:video:c4927fcf-e1a0-0001-7edd-1ef01d441651` (SRF 1 Live - DRM protected)
|
|
|
|
## Building the Plugin
|
|
|
|
### Prerequisites
|
|
|
|
- .NET 8.0 SDK
|
|
- Jellyfin 10.9.11 or later
|
|
|
|
### Build Steps
|
|
|
|
```bash
|
|
cd Jellyfin.Plugin.SRFPlay
|
|
dotnet build
|
|
```
|
|
|
|
### Output
|
|
|
|
The compiled plugin will be in `bin/Debug/net8.0/`
|
|
|
|
## Quick Install
|
|
|
|
Add this repository URL in Jellyfin (Dashboard → Plugins → Repositories):
|
|
|
|
```
|
|
https://gitea.tourolle.paris/dtourolle/jellyfin-srfPlay/raw/branch/master/manifest.json
|
|
```
|
|
|
|
Then install "SRF Play" from the plugin catalog.
|
|
|
|
## Manual Installation
|
|
|
|
1. Build the plugin (see above)
|
|
2. Copy the compiled DLL to your Jellyfin plugins directory
|
|
3. Restart Jellyfin
|
|
4. Configure the plugin in Jellyfin Dashboard → Plugins → SRF Play
|
|
5. The SRF Play channel will appear in Jellyfin with three main folders:
|
|
- **Latest Videos** - Recently published content
|
|
- **Trending Videos** - Popular content
|
|
- **Live Sports & Events** - Scheduled sports livestreams (skiing, F1, football, etc.)
|
|
|
|
## Configuration
|
|
|
|
- **Business Unit**: Select the Swiss broadcasting unit (default: SRF)
|
|
- **Quality Preference**: Choose video quality (Auto/SD/HD)
|
|
- **Content Refresh Interval**: How often to check for new content (1-168 hours)
|
|
- **Expiration Check Interval**: How often to check for expired content (1-168 hours)
|
|
- **Cache Duration**: How long to cache metadata (5-1440 minutes)
|
|
- **Enable Latest Content**: Automatically discover latest videos
|
|
- **Enable Trending Content**: Automatically discover trending videos
|
|
- **Proxy Settings**: Configure proxy server for routing SRF API traffic (optional)
|
|
- **Use Proxy**: Enable/disable proxy usage
|
|
- **Proxy Address**: Proxy server URL (e.g., http://proxy.example.com:8080)
|
|
- **Proxy Username**: Optional authentication username
|
|
- **Proxy Password**: Optional authentication password
|
|
|
|
For detailed proxy setup instructions, see [PROXY_SETUP_GUIDE.md](PROXY_SETUP_GUIDE.md).
|
|
|
|
## Troubleshooting
|
|
|
|
If you encounter issues with the plugin:
|
|
- Check [DEBUG_GUIDE.md](DEBUG_GUIDE.md) for detailed logging information
|
|
- Enable debug logging in Jellyfin to see detailed request/response information
|
|
- Common issues include DRM-protected content and geo-restrictions
|
|
|
|
## Technical Architecture
|
|
|
|
### Directory Structure
|
|
|
|
```
|
|
Jellyfin.Plugin.SRFPlay/
|
|
├── Api/
|
|
│ ├── Models/ # API response models
|
|
│ │ ├── MediaComposition.cs
|
|
│ │ ├── Chapter.cs
|
|
│ │ ├── Resource.cs
|
|
│ │ ├── Show.cs
|
|
│ │ ├── Episode.cs
|
|
│ │ └── PlayV3/ # Play v3 API models
|
|
│ │ ├── PlayV3TvProgram.cs
|
|
│ │ └── PlayV3TvProgramGuideResponse.cs
|
|
│ └── SRFApiClient.cs # HTTP client for SRF API
|
|
├── Channels/
|
|
│ └── SRFPlayChannel.cs # Channel implementation
|
|
├── Configuration/
|
|
│ ├── PluginConfiguration.cs
|
|
│ └── configPage.html
|
|
├── Services/
|
|
│ ├── StreamUrlResolver.cs # HLS stream resolution & authentication
|
|
│ ├── MetadataCache.cs # Caching layer
|
|
│ ├── ContentExpirationService.cs # Expiration management
|
|
│ ├── ContentRefreshService.cs # Content discovery
|
|
│ └── CategoryService.cs # Topic/category management
|
|
├── Providers/
|
|
│ ├── SRFSeriesProvider.cs # Series metadata
|
|
│ ├── SRFEpisodeProvider.cs # Episode metadata
|
|
│ ├── SRFImageProvider.cs # Image fetching
|
|
│ └── SRFMediaProvider.cs # Playback URLs
|
|
├── ScheduledTasks/
|
|
│ ├── ContentRefreshTask.cs # Periodic content refresh
|
|
│ └── ExpirationCheckTask.cs # Periodic expiration check
|
|
├── ServiceRegistrator.cs # DI registration
|
|
└── Plugin.cs # Main plugin entry point
|
|
```
|
|
|
|
### Key Components
|
|
|
|
1. **API Client**: Handles all HTTP requests to SRF Integration Layer and Play v3 API
|
|
2. **Channel**: SRF Play channel with Latest, Trending, and Live Sports folders
|
|
3. **Stream Resolver**: Extracts and selects optimal HLS streams with Akamai authentication
|
|
4. **Configuration**: User-configurable settings via Jellyfin dashboard
|
|
5. **Metadata Cache**: Thread-safe caching with dynamic TTL for livestreams
|
|
6. **Content Providers**: Jellyfin integration for series, episodes, images, and media sources
|
|
7. **Scheduled Tasks**: Automatic content refresh and expiration management
|
|
8. **Service Layer**: Content discovery, expiration handling, stream resolution, and category management
|
|
|
|
## Important Notes
|
|
|
|
### Content Limitations
|
|
|
|
- **No DRM content**: Only non-DRM protected content is accessible (no Widevine/FairPlay)
|
|
- **No live TV channels**: Main channels (SRF 1, SRF zwei, SRF info) use DRM and are not supported
|
|
- **Sports livestreams supported**: Scheduled sports events (skiing, F1, football, etc.) work without DRM
|
|
- **Content expiration**: SRF content has validity periods, plugin tracks and removes expired content
|
|
- **Upcoming events**: Sports events appear before they start but require channel refresh to play once live
|
|
- **No subtitles**: Subtitle support not currently implemented
|
|
|
|
### Extensibility
|
|
|
|
The plugin is designed to support all Swiss broadcasting units:
|
|
- **SRF** (Schweizer Radio und Fernsehen - German)
|
|
- **RTS** (Radio Télévision Suisse - French)
|
|
- **RSI** (Radiotelevisione svizzera - Italian)
|
|
- **RTR** (Radiotelevisiun Svizra Rumantscha - Romansh)
|
|
- **SWI** (Swiss World International)
|
|
|
|
Currently focused on SRF but easily extensible.
|
|
|
|
## Development
|
|
|
|
The plugin includes:
|
|
- Complete API integration with SRF Play (Integration Layer v2.0 and Play v3)
|
|
- **Live sports streaming** with scheduled event detection
|
|
- Channel with Latest, Trending, and Live Sports folders
|
|
- Metadata providers for series and episodes
|
|
- Image fetching and caching
|
|
- HLS stream playback with Akamai token authentication
|
|
- Automatic content expiration handling
|
|
- Scheduled tasks for content refresh
|
|
- Smart caching with dynamic TTL for upcoming livestreams
|
|
|
|
### Known Issues
|
|
|
|
- Some clients may experience issues with hardware decoding (appears to be client-specific)
|
|
- Some edge cases may need additional handling
|
|
- Performance optimization may be needed for very large content catalogs
|
|
|
|
### Contributing
|
|
|
|
Contributions welcome!
|
|
|
|
## License
|
|
|
|
See LICENSE file for details.
|
|
|
|
## Acknowledgments
|
|
|
|
This plugin was developed with inspiration from the excellent [Kodi SRG SSR addon](https://github.com/goggle/script.module.srgssr) by [@goggle](https://github.com/goggle). The Kodi addon served as a fantastic reference for understanding the SRG SSR API structure, authentication mechanisms, and handling of scheduled livestreams.
|
|
|
|
## References
|
|
|
|
- [SRF Play](https://www.srf.ch/play)
|
|
- [Jellyfin Plugin Documentation](https://jellyfin.org/docs/general/server/plugins/)
|
|
- [SRG SSR Integration Layer API](https://il.srgssr.ch/)
|
|
- [Kodi SRG SSR Addon](https://github.com/goggle/script.module.srgssr) - Reference implementation
|