Last Updated: 2025-11-05
Version: 1.0 (Work in Progress)
Build Size: ~24 KB
- ✅ TypeScript Build System - Rollup bundler with hot reload
- ✅ Authentication - Anonymous token system with auto-refresh
- ✅ State Management - Token persistence across sessions
- ✅ GraphQL Client - Persisted query execution with error handling
- ✅ Algolia Search Integration - API key management and search
| Method | Status | Description |
|---|---|---|
enable() |
✅ Complete | Initialization + token refresh |
disable() |
✅ Complete | Cleanup |
saveState() |
✅ Complete | Persists auth & Algolia tokens |
getHome() |
✅ Complete | Landing page with videos |
search() |
✅ Complete | Algolia-powered search with pagination |
searchSuggestions() |
✅ Complete | Returns empty array (not supported) |
getSearchCapabilities() |
✅ Complete | Mixed feed, 2 sort options |
getChannelCapabilities() |
✅ Complete | Mixed feed, chronological |
isChannelUrl() |
✅ Complete | Live TV + Brand/mediathek URLs |
isContentDetailsUrl() |
✅ Complete | Episodes + Movies |
isPlaylistUrl() |
✅ Complete | Series URLs |
getChannel() |
✅ Complete | Live TV channels (brand channels TBD) |
getChannelContents() |
✅ Complete | Live streams for TV channels |
getContentDetails() |
✅ Complete | Episode metadata (no video sources yet) |
getPlaylist() |
✅ Complete | Series metadata (playlist details) |
- ✅
LandingPageClient- Home feed - ✅
LiveLane- Live TV lane - ✅
Navigation- Site navigation - ✅
GetMeState- User state - ✅
HeroLaneResumePositionsWithToken- Featured with progress - ✅
ResumeLaneWithToken- Continue watching - ✅
WatchNext- Recommendations - ✅
Season- Season episodes - ✅
LaneMoreLikeThis- Related content - ✅
ResumePositionsWithToken- Watch progress - ✅
AlgoliaApiKey- Search API key - ✅
LiveChannelsAndEpg- All live channels + EPG - ✅
LivestreamOverviewByBrand- Channel by ID - ✅
Livestream- Stream details with EPG - ✅
PageLivePlayerClientSide- Live player page - ✅
EpisodeDetailPageStatic- Episode metadata - ✅
PageSeriesEpisodePlayerClientSide- Episode player (for video sources)
- ✅
JoynAssetToGrayjayVideo- Assets → Videos - ✅
JoynBrandToGrayjayChannel- Brands → Channels - ✅
JoynLiveChannelToGrayjayChannel- Live channels → Channels - ✅ Episode details → PlatformVideoDetails
- ✅ Series → PlatformPlaylistDetails
- ✅ Live streams → PlatformVideo (isLive: true)
- ✅
JoynVideoPager- Video results - ✅
JoynChannelPager- Channel lists - ✅
JoynSearchPager- Search with page tracking
| Type | Browse | Details | Sources | Notes |
|---|---|---|---|---|
| Episodes | ✅ | ✅ | ❌ | Metadata complete, video extraction needed |
| Movies | ✅ | ❌ | ❌ | Stub only |
| Series | ✅ | ✅ | N/A | As playlists |
| Live TV | ✅ | ✅ | ❌ | Channel info complete, stream URLs needed |
| Brands | ❌ | ❌ | ❌ | Stub only |
Status: Infrastructure ready, parsing needed
Query: PageSeriesEpisodePlayerClientSide
What's Needed:
- Parse playback configuration from player query response
- Extract HLS/DASH manifest URLs
- Handle DRM if present (Widevine likely required)
- Extract subtitle tracks
- Map quality levels to VideoUrlRangeDescriptor
Estimated Complexity: Medium-High (DRM handling)
Status: Stub implemented
What's Needed:
- Find GraphQL query for brand metadata
- Implement
getBrandChannel() - Implement
getBrandChannelContents()to list brand videos - Map brand videos to PlatformVideo
Estimated Complexity: Low-Medium
Status: Stub implemented
What's Needed:
- Find/use movie detail GraphQL query (likely similar to episode)
- Parse movie metadata
- Extract video sources
- Map to PlatformVideoDetails
Estimated Complexity: Low (similar to episodes)
Status: Playlist metadata works, content listing TBD
What's Needed:
- Implement method to list all episodes from a series playlist
- Use
SEASON_QUERYto get episodes per season - Iterate through all seasons
- Return ContentPager with episodes
Estimated Complexity: Low
- ❌ User Authentication - Login support (config has structure)
- ❌ User Subscriptions - Followed channels/brands
- ❌ Watch History - Resume playback positions
- ❌ Recommendations - Personalized suggestions
- ❌ Comments - Not supported by Joyn
- ❌ Live Chat - Not applicable
Code Metrics:
- TypeScript Source: ~900 lines
- Built JavaScript: ~24 KB
- GraphQL Queries: 17 defined
- Mappers: 3 functions
- Pagers: 3 classes
- Helper Functions: 15+
Coverage:
- Core Methods: 15/15 (100%)
- Content Types: 3/5 (60%)
- ✅ Episodes (partial)
- ✅ Series
- ✅ Live TV (partial)
- ⏳ Movies (stub)
- ⏳ Brands (stub)
Goal: Enable actual video streaming
Tasks:
- Parse
PageSeriesEpisodePlayerClientSideresponse - Extract manifest URLs (HLS/DASH)
- Handle DRM configuration
- Test playback in GrayJay app
Goal: Support all Joyn content
Tasks:
- Implement
getMovieDetails() - Implement
getBrandChannel()andgetBrandChannelContents() - Add episode listing for series playlists
Goal: Production-ready release
Tasks:
- Create Joyn icon (512x512 PNG)
- Comprehensive testing with dev portal
- Error handling improvements
- Documentation
- Video Sources: Not yet extracted (DRM/entitlement may be required)
- Live Stream URLs: Channel metadata works, stream URLs needed
- Brand Channels: Stub only, needs implementation
- Movies: Stub only, needs implementation
- Search Filters: Not implemented (Algolia supports it)
- EPG Data: Available via queries but not exposed yet
Joyn Content Hierarchy:
├── Channels
│ ├── Live TV (/play/live-tv?channel_id=X) ✅
│ │ └── Current livestream (isLive: true) ✅
│ └── Brands (/mediatheken/X) ⏳
│ └── Brand videos ⏳
├── Playlists
│ └── Series (/serien/X) ✅
│ └── Seasons & Episodes ⏳
└── Content Details
├── Episodes (/serien/X/S-E-title-ID) ✅ (no sources)
└── Movies (/filme/X) ⏳
Search: Algolia-powered ✅
Authentication: Anonymous tokens ✅
# Build
cd sources/grayjay-sources-grayjay-source-joyn
npm install
npm run build
# Watch mode
npm run dev
# Test
# Serve from build/ folder
cd build
npx serve -p 8080
# Load in dev portal
# http://100.100.1.57:11337/dev
# Config URL: http://100.100.1.57:8080/JoynConfig.jsonTODO.md- Detailed task listREADME.md- User-facing documentationtypes/plugin.d.ts- GrayJay plugin API typestypes/types.d.ts- Joyn-specific types
Overall Status: 🟡 ~70% Complete - Core functionality works, video extraction pending