Compare commits

...

1847 Commits

Author SHA1 Message Date
e58bb9af21 Move CI/CD reference docs from memory to in-repo docs/
Some checks failed
Build / Calculate version information (push) Successful in 12s
Build / build_and_upload (push) Failing after 0s
Build / build_images (push) Failing after 0s
Close stale issues / stale (push) Successful in 3s
Moves ci-cd.md (59 lines) from Claude memory into docs/ alongside
existing architecture docs. Slims MEMORY.md from 42 to 18 lines by
removing sections duplicated in CLAUDE.md (Tech Stack, Key Patterns,
Architecture Docs index).

Total memory load per session: 101 → 18 lines.

Fixes #7

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 20:03:31 +01:00
aa6d8eae4c Add Task Completion Protocol to CLAUDE.md
Some checks failed
Build / Calculate version information (push) Successful in 17s
Build / build_and_upload (push) Failing after 0s
Build / build_images (push) Failing after 0s
Close stale issues / stale (push) Successful in 13s
Replace informal implementer workflow with structured 7-step protocol
including mandatory root cause analysis for bug fixes. References /done
skill for automated enforcement.

Part of adversarial-reviewer #260.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 22:29:45 +01:00
f1e97b94a7 Add architecture docs and fork maintenance strategy (#6)
Some checks failed
Build / Calculate version information (push) Successful in 13s
Build / build_and_upload (push) Failing after 0s
Build / build_images (push) Failing after 0s
Close stale issues / stale (push) Successful in 15s
Document channel architecture, M3U/XMLTV integration with Jellyfin,
and fork maintenance strategy for the archived upstream. Also includes
CLAUDE.md updates for implementer workflow and project boundaries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 22:42:07 +01:00
5034941a79 Add Claude Code project setup
Some checks failed
Build / Calculate version information (push) Successful in 22s
Build / build_and_upload (push) Failing after 0s
Build / build_images (push) Failing after 0s
Close stale issues / stale (push) Successful in 14s
- CLAUDE.md with architecture overview and development guide
- .mcp.json with docker, ssh, gitea, csharp-lsp, and nuget MCP servers
- Skills for ersatztv and jellyfin
- .gitignore: exclude .mcp/ (built MCP tools)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:50:41 +01:00
Jason Dove
0d301df5e8 remove external dependencies (bugsnag, trakt) (#2840)
* remove bugsnag

* remove trakt client id (that will expire)
2026-02-26 10:43:48 -06:00
Jason Dove
d26ae336cb prep for release v26.3.0 [no ci] 2026-02-24 15:27:51 -06:00
Jason Dove
875069b927 fix stream seek value in graphics engine (#2838) 2026-02-23 14:54:28 -06:00
Jason Dove
fd86cb55f9 optimize qsv h264 stream startup (#2835) 2026-02-22 10:13:18 -06:00
Jason Dove
0c30c47ba9 nvidia - decode 10-bit h264 in software (#2833)
* output progress/speed even when copying video

* nvidia - decode 10-bit h264 in software

* fixes

* fix tests
2026-02-20 23:00:15 -06:00
Jason Dove
08cbf59527 lower gop size and keyframe interval (#2832)
* lower gop size and keyframe interval

* update changelog

* fix build using latest dotnet sdk

* fixes
2026-02-19 13:35:27 -06:00
Lex Rivera
a91de68a5c Add instance id support (#2828)
* Add instance id support

* actually use env variable for instance ID

* Default to ersatztv.org for instance id

* simplify

* fix ordering

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2026-02-18 09:09:44 -06:00
Jason Dove
3e3bfbd5f5 use heuristic to work around some qsv av desync cases (#2829)
* check for multiple h264 profiles using qsv decoding

* fix build

* update changelog

* pass cancellation token
2026-02-16 12:37:40 -06:00
Jason Dove
31b07305ef remove more discord references [no ci] 2026-02-15 12:44:16 -06:00
Jason Dove
49adcf7c37 replace discord links with new contact link (#2825) 2026-02-15 11:05:44 -06:00
Jason Dove
c0b8ff1a06 generate slug instead of probing and transcoding resource (#2824)
* generate slug instead of probing and using slug resource

* refactor

* more fixes
2026-02-15 09:46:07 -06:00
Jason Dove
c6d538e012 add channel slugs (#2823)
* add channel slugs

* safety
2026-02-14 19:57:35 -06:00
Jason Dove
3dbde17f68 pin dotnet sdk in docker to 10.0.102 (#2822) 2026-02-12 08:42:54 -06:00
Jason Dove
794d209941 use latest authorization method with jellyfin api (#2821)
* use latest authorization method with jellyfin api

* temp pin dotnet sdk version to 10.0.102

* fix parameter name
2026-02-12 08:29:47 -06:00
Jason Dove
7b9197d48d fix trakt api calls with new client id (#2820) 2026-02-10 11:26:09 -06:00
Jason Dove
2ad6547349 scheduler context improvements (#2819)
* improve classic scheduling context display

* add basic block scheduling context

* add scheduling context to classic filler

* improve parsing
2026-02-09 20:19:52 -06:00
Jason Dove
4fa11b6943 add scheduling context to playout details table (#2817)
* add scheduling context to playout details table

* fix missing context copies
2026-02-05 13:45:05 -06:00
Jason Dove
440d9f708e improve shuffle stability when reset (#2816) 2026-02-05 12:03:16 -06:00
Vexorion Real
4d469ec8fd Add Polish (pl) localization for ErsatzTV: Part II (#2815)
* Add Polish localization for MainLayout

* Add Polish language option to UI settings

* Add Polish to supported UI cultures

* Add Polish localization for channel UI

Added Polish translations for channel-related UI elements.

* Add Polish translation for 'Rows per Page' label

* Update Polish translation for rows per page label

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2026-02-05 09:38:02 -06:00
Jason Dove
a77a2d56ae prepare channels list for localization (#2814)
* prepare channels list for localization

* define supported ui cultures/languages in a single location

* fixes
2026-02-04 14:20:43 -06:00
Vexorion Real
240a329526 Add Polish (pl) localization to ErsatzTV (#2812)
* Add Polish localization for MainLayout

* Add Polish language option to UI settings

* Add Polish to supported UI cultures

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2026-02-04 08:30:31 -06:00
Jason Dove
45e7d61676 update dependencies (#2813) 2026-02-04 07:39:47 -06:00
Jason Dove
93811876e0 improve resource organization (#2810) 2026-02-03 14:57:45 -06:00
Jason Dove
607d9b0662 add ui localization framework (#2809)
* move dark/light mode toggle to ui settings page

* separate current culture (formatting) and ui culture (language)

* add some more sample translations

* update changelog

* fix cancellation token
2026-02-03 13:52:52 -06:00
Jason Dove
f47134d2d0 log warnings when transcoding speed is potentially insufficient (#2808)
* refactor parsing ffmpeg progress/speed

* log warnings when transcoding speed is potentially insufficient

* dont log progress on hls direct; fix tests
2026-02-03 08:49:07 -06:00
Jason Dove
ae13db981d fix secrets in release workflow 2026-02-02 14:52:27 -06:00
Jason Dove
b7cc8499a3 prep for release v26.2.0 [no ci] 2026-02-02 14:47:44 -06:00
Jason Dove
36147b9e9c fix indexing collections in elasticsearch (#2806)
* fix indexing collections in elasticsearch

* more safety
2026-01-29 18:23:07 -06:00
Jason Dove
bf8c821012 improve erasing playout items and history (#2805)
* improve erasing playout items and history

* fixes
2026-01-28 09:17:56 -06:00
Jason Dove
a0f5d8d5d5 detect more local movie artwork (#2804)
* expand test coverage

* support "backdrop" files as local movie fanart fallback
2026-01-27 16:35:28 -06:00
Jason Dove
f1072b70c7 add chapter title to filler expression (#2803)
* fix transcoding tests

* pass chapter title to filler expression

* update changelog
2026-01-27 09:40:38 -06:00
Jason Dove
e10b28bc0b add normalization options (#2802)
* add new fields to database

* update editor

* audio and video normalization settings appear to work

* implement optional color normalization

* fix transcoding tests

* update changelog
2026-01-26 23:43:56 -06:00
Jason Dove
cd2bb0f2e0 fix playout build failures due to playlist enumerator access (#2801) 2026-01-26 14:44:07 -06:00
Jason Dove
e80f687612 add marathon group by director (#2800) 2026-01-26 09:10:01 -06:00
Jason Dove
317ca1967c fix building playouts when fill with group mode is used with graphics elements (#2799) 2026-01-25 15:29:18 -06:00
Jason Dove
b86f45844c add health check to verify ffmpeg capabilities (filters) (#2798)
* add health check to verify ffmpeg capabilities (filters)

* fix loudnorm
2026-01-25 12:28:09 -06:00
Jason Dove
353f029452 fix null ref scanning other videos with nfo file (#2797)
* fix null ref scanning other videos with nfo file

* also fix movie null ref
2026-01-25 11:34:06 -06:00
Jason Dove
1754e7d5fb add health check for empty classic schedules (#2796) 2026-01-23 15:47:48 -06:00
Jason Dove
f96be8f99f update plex episode metadata during scan (#2795) 2026-01-21 16:59:01 -06:00
Jason Dove
08ceb53b2b make count an expression in classic schedules (#2794)
* make count an expression in classic schedules

* add tests
2026-01-20 09:50:45 -06:00
Jason Dove
3d81f760ee fix z-index sorting in graphics engine (#2786) 2026-01-18 09:07:21 -06:00
Jason Dove
4ce87feac1 log graphics element z index (#2785) 2026-01-17 08:15:43 -06:00
Jason Dove
f217ba185b sync jf and emby library name and type changes (#2784) 2026-01-17 06:14:45 -06:00
Jason Dove
e925bd6913 sync plex library name changes (#2783)
* sync plex library name changes

* feedback
2026-01-16 19:45:34 -06:00
Jason Dove
3f4c9e063b don't delete channel watermarks that are still used (#2781)
* don't delete channel watermarks that are still used

* fix folder cleanup check
2026-01-16 14:24:03 -06:00
Jason Dove
7f361d1ea9 update dependencies (#2780)
* update messaging

* update dependencies
2026-01-16 13:57:25 -06:00
Jason Dove
35d24ffea6 cleanup artwork cache folder (#2779)
* cleanup artwork cache folder

* fixes

* ignore watermarks that no longer exist on the file system
2026-01-16 13:38:31 -06:00
Jason Dove
a2d023ee69 local scanner artwork cleanup (#2778)
* move plex artwork removal to its own repository

* clean up old local movie artwork

* clien up old music video/artist artwork

* clean up old remote stream artwork

* clean up old song artwork

* clean up old show artwork; properly update season artwork
2026-01-16 10:23:26 -06:00
Jason Dove
36f44f14bb fix other video artwork in xmltv (#2777) 2026-01-15 22:42:16 -06:00
Jason Dove
ccb917d0df add ffmpeg profile pad mode (#2775)
* add ffmpeg profile pad mode

* update changelog
2026-01-15 09:39:45 -06:00
Jason Dove
343a4619a6 downmix ac3 to stereo to match output layout (#2774) 2026-01-14 10:40:49 -06:00
Jason Dove
e167c9318c fix failing unit tests (#2772) 2026-01-14 06:47:34 -06:00
Jason Dove
de230f92db fix issue reading xmltv fragments (#2771)
* fix issue reading xmltv fragments

* cleanup
2026-01-13 22:30:31 -06:00
Jason Dove
974020a98f optimize searching for shows, seasons and movies (#2768)
* load search logging level on startup

* optimize searching for shows, seasons and movies

* use season metadata directly
2026-01-12 19:42:49 -06:00
Jason Dove
da957c9377 restore roboto font (#2767) 2026-01-12 08:49:57 -06:00
Jason Dove
b72d150775 add day_of_week to channel stream selector content_condition (#2766) 2026-01-10 11:28:14 -06:00
Jason Dove
b0b7bd17b3 respect z_index on all graphics element types (#2765) 2026-01-09 10:26:59 -06:00
Jason Dove
1f2f04f3bd more fixes 2026-01-08 21:47:28 -06:00
Jason Dove
5bc90bb245 give id-token write permission 2026-01-08 20:47:30 -06:00
Jason Dove
f73a32ec13 restore permissions 2026-01-08 20:36:09 -06:00
Jason Dove
748ed1cf71 properly define secrets 2026-01-08 20:26:24 -06:00
Jason Dove
f2deaa6f7a properly pass secrets 2026-01-08 20:25:20 -06:00
Jason Dove
3698fa5b7d try again 2026-01-08 20:19:47 -06:00
Jason Dove
dc92cb4ac3 use separate azure login step 2026-01-08 19:59:55 -06:00
Jason Dove
69410b1a9b try to fix signing 2026-01-08 19:39:21 -06:00
Jason Dove
4aee03e066 use code signing on all windows executables (#2764) 2026-01-08 19:27:45 -06:00
Jason Dove
e16d6c67f1 prep for release v26.1.1 [no ci] 2026-01-08 16:01:29 -06:00
Jason Dove
5d8877975d fix macos build (#2763)
* fix macos build

* also update host
2026-01-08 11:51:16 -06:00
Jason Dove
367305d960 include web resources locally, using libman (#2762) 2026-01-08 11:24:48 -06:00
Jason Dove
aa08ad5765 optimize check for orphaned artwork (#2760) 2026-01-07 16:46:17 -06:00
Jason Dove
40c6c504fe prep for release v26.1.0 [no ci] 2026-01-06 15:15:00 -06:00
Jason Dove
933b6530e4 fix build 2026-01-06 13:41:25 -06:00
Jason Dove
885330f8c5 rework windows launcher build process (#2758)
* update license

* download pre-compiled windows launcher instead of building it with each commit

* remove windows launcher project which has moved to its own repo
2026-01-06 13:32:20 -06:00
Jason Dove
effb96a2c2 alternate schedule and template consistency (#2757)
* refactor classic and block schedules to use same alternate schedule selector

* handle start year and end year

* add migrations for classic and block schedules

* allow editing block template start and end year

* add tests that include years

* add date range editing to classic (alternate) schedules

* fix running tests locally

* restore media files load; needed for local folder scanners

* update changelog

* feedback
2026-01-06 12:51:07 -06:00
Jason Dove
cc521326d9 hide jellyfin timing stats by default; enable with env var (#2756) 2026-01-06 12:08:55 -06:00
James Dearlove
5c42609527 Add base URL to variant playlists (#2755)
* Add PathBase to variant playlists

* add commented code to help with testing

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2026-01-05 09:13:04 -06:00
Jason Dove
a96ef328a5 more scanning improvements related to media file table (#2754) 2026-01-04 19:16:06 -06:00
Jason Dove
89bb3759de more jf episode scanning improvements (#2753)
* more jf episode scanning improvements

* bump log level on important message

* add transaction
2026-01-03 12:43:26 -06:00
Jason Dove
12f2583c96 add timings for jf episode loading and saving during update (#2752) 2026-01-02 20:16:30 -06:00
Jason Dove
7c82ecdfff use separate load queries for jf episode inserts and updates (#2751) 2026-01-02 16:28:19 -06:00
Jason Dove
38343e3ea2 lazy load media card images (#2750) 2026-01-02 13:40:44 -06:00
Jason Dove
bcd2ea7db3 db optimizations around names and case-sensitivity (#2749)
* generate (case-insensitive) unique names for fields that should be unique

* move name case-insensitivity down to schema level

* update changelog
2026-01-02 09:25:23 -06:00
Jason Dove
80f6e468eb collect and print timings during jellyfin show library scans (#2748)
* collect and print timings during jellyfin show library scans

* update p99
2026-01-01 20:02:24 -06:00
Jason Dove
474e647d6d more jellyfin performance improvements (#2747)
* fix slow db and api logging so it also works in scanner project

* don't request people from jellyfin by default
2025-12-31 22:28:15 -06:00
Jon Crall
daff1c6533 Add select all controls to media lists (#2738)
* Add select all controls to media lists

* Refine select-all helper and add coverage

* Adjust select-all button alignment

* Tighten select-all helper semantics

* Allow tests to access internal members

* Rename select-all helper and avoid shift tracking

* Simplify select-all reset helper

* Keep pager centered and move select-all right

* Add missing div

* create test project for main app; move and rename new tests

* remove core => main app reference

* cleanup unused imports

* Fix button behavior when the screen is small

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2025-12-31 15:18:07 -06:00
Jason Dove
14d2dd0c3a optimize jellyfin database fields and indexes (#2746)
* optimize jellyfin database fields and indexes

* copy paste
2025-12-31 14:30:53 -06:00
Jason Dove
c606319030 add some performance troubleshooting env vars (#2745)
* add slow query logging

* add slow api logging for jellyfin

* add configurable jellyfin page size

* feedback
2025-12-31 14:04:12 -06:00
Jason Dove
1b72b8491c improve multi-episode grouping logic (#2744) 2025-12-31 11:24:07 -06:00
Jason Dove
9fea25a77d allow string values for count instruction in sequential schedules (#2741)
* allow string values for count instruction in sequential schedules

* fix potential div by zero
2025-12-30 18:19:33 -06:00
Jason Dove
74b049b6e3 fix nvenc playback when color metadata changes mid-stream (#2740)
* fix nvenc playback when color metadata changes mid-stream

* update dependencies (needed to fix unit test runner)

* limit noautoscale to when it's not already present
2025-12-30 11:55:25 -06:00
Jason Dove
b2caf8ee8d fix remote stream indexing due to missing titles (#2739) 2025-12-30 08:51:06 -06:00
Jason Dove
b582b4cbf7 fix downgrade health check failure for mariadb (#2737) 2025-12-24 22:29:57 -06:00
Jason Dove
0af81ad839 add target loudness to ffmpeg profile (#2727)
* add target loudness to ffmpeg profile

* fix filter
2025-12-19 14:46:17 -06:00
Jason Dove
2f0cd1eb6c update dependencies (#2726) 2025-12-19 13:56:26 -06:00
Jason Dove
e4f1a93db0 fix some mysql migrations that failed on mariadb (#2725) 2025-12-17 22:40:03 -06:00
Jason Dove
6562d616fb smart collection names must be case insensitive (#2721)
* smart collection names must be case insensitive

* use explicit ci collation for mysql
2025-12-13 18:32:02 -06:00
Jason Dove
d8122edad6 fix duplicate smart collection names (#2720)
* fix duplicate smart collection names

* fix update error
2025-12-13 14:59:06 -06:00
Jason Dove
99b8c56a31 rework fallback filler (#2719)
* fallback fixes

* use hardware encoding for fallback filler

* rework fallback filler

* fixes
2025-12-13 09:02:48 -06:00
Jason Dove
09858df654 fix case when cuda hw decode falls back to sw (#2718)
* fix case when cuda hw decode falls back to sw

* use a new filter
2025-12-12 15:11:32 -06:00
Jason Dove
038286c92b use playlist item count when playlists are used as filler (#2716)
* use playlist item count when playlists are used as filler

* expand test
2025-12-10 22:14:07 -06:00
Jason Dove
8575ab5c32 fix bt2020 playback (#2714)
* fix bt2020 playback

* update pixel format

* update changelog
2025-12-10 19:50:47 -06:00
Jason Dove
8b768a2990 allow playlists to have no items included in epg (#2713) 2025-12-10 16:15:04 -06:00
Jason Dove
f9e4c4d386 improve build time by only running analyzers explicitly (#2710)
* improve build time by only running analyzers explicitly

* don't exclude scanner from analyzers

* Revert "don't exclude scanner from analyzers"

This reverts commit d927f9850a.

* fix sed syntax for linux
2025-12-09 14:17:05 -06:00
Jason Dove
a1f9b86fc1 add download media sample button to playback troubleshooting (#2709)
* add download media sample button to playback troubleshooting

* fixes
2025-12-09 11:49:07 -06:00
Jason Dove
5dc20ebd1b use software pad with amd vaapi h264 main (#2708) 2025-12-06 10:03:24 -06:00
Jason Dove
d30e8b4102 only use packed headers with vaapi when supported by encoder (#2706) 2025-12-05 11:20:16 -06:00
Jason Dove
c14f373f23 implement rectangles packet for script element (#2704)
* implement rectangles packet for script element

* fixes
2025-12-04 20:57:26 -06:00
Jason Dove
a90fe26d50 script element packet spike (#2703)
* script element packet spike

* fixes
2025-12-04 15:40:18 -06:00
Jason Dove
7a263ddaed add migration to fix any incorrect channel sort numbers (#2701) 2025-12-03 19:23:59 -06:00
Jason Dove
3e0a9aae1e fix channel sort number when reordering channels (#2700)
* fix channel sort number when reordering channels

* tryparse
2025-12-03 18:33:47 -06:00
Jason Dove
72dc401829 fix chronological sorting for other videos (#2699) 2025-12-03 10:38:29 -06:00
Jason Dove
85e25ca6ea add channel start time template data (#2698)
* add channel start time template data

* rename
2025-12-03 10:16:09 -06:00
Jason Dove
9c23b03758 fix mirror channels (#2697) 2025-12-03 09:56:52 -06:00
Jason Dove
e12888ebee fix recent regression to subtitle graphics element (#2696) 2025-12-03 07:33:17 -06:00
Jason Dove
468ff087d4 fix loading epg entries for motion and script elements (#2693) 2025-12-02 15:46:22 -06:00
Jason Dove
54606c76f9 framerate improvements (#2692)
* framerate improvements

* fixes
2025-12-02 12:20:09 -06:00
Jason Dove
6bd49ffcec add remote stream metadata (#2690)
* add remote stream metadata

* use ifilesystem for last write time

* clean up unused inheritance

* optimize channel data query

* revert removeartwork change

* properly handle remote stream artwork in orphaned artwork check
2025-12-01 12:48:03 -06:00
Jason Dove
c524bc0d7d add script graphics element (#2681)
* add script graphics element

* pass template data as json to stdin

* update changelog
2025-11-30 14:20:18 -06:00
Jason Dove
42bcadf936 work around buggy radeonsi hevc_vaapi behavior (#2680)
* try to workaround amd crop metadata ffmpeg bug

* limit workaround to hevc_vaapi encoder

* update changelog
2025-11-30 12:14:20 -06:00
Jason Dove
1f31beab5b fix plex other video library detection (#2679) 2025-11-30 08:35:04 -06:00
Jason Dove
b45c22092d fix startup on systems unsupported by nvencsharp (#2678) 2025-11-30 06:26:57 -06:00
Jason Dove
7bd8cefe2e more dotnet 10 updates (#2676)
* update more libraries to dotnet 10

* fix dockerfiles

* fix numeric types
2025-11-29 15:47:08 -06:00
Jason Dove
f101d0b366 prep for release v25.9.0 [no ci] 2025-11-29 10:36:17 -06:00
Jason Dove
73aabdabda fix transcoding tests (#2675) [no ci] 2025-11-29 10:34:32 -06:00
Jason Dove
bcea96d53a always log scanner exit code when it is non-zero (#2670)
* always log scanner exit code when it is non-zero

* remove test abort
2025-11-26 12:50:19 -06:00
Jason Dove
d7952e4cfa fix docker assets (#2669) 2025-11-26 11:25:56 -06:00
Jason Dove
758399e339 fix missing net9.0 to net10.0 in docker/github (#2668) 2025-11-26 10:54:24 -06:00
Jason Dove
6c635a4be9 upgrade to dotnet 10 (#2667)
* upgrade to dotnet 10

* remove packages that would be pruned

* properly fix tests
2025-11-26 10:49:01 -06:00
Jason Dove
9d637cdd54 update dependencies (#2661) 2025-11-25 16:06:48 -06:00
Jason Dove
cc287ffc6e fix hls direct streams remaining open (#2660) 2025-11-24 22:40:26 -06:00
Jason Dove
371659c5c5 cache bust new logo (#2659) 2025-11-24 20:10:57 -06:00
Jason Dove
7afb1866ad update logo (#2658) 2025-11-24 20:01:53 -06:00
Jason Dove
7bc1dd63fe fix file system test on windows (#2657) [no ci] 2025-11-24 13:40:04 -06:00
Jason Dove
076b8a7188 fix editing certain playouts when using mysql (#2656) 2025-11-24 13:31:00 -06:00
Jason Dove
ec0d8ea6ac work around sequential schedule validation limit (#2655)
* remove readalltext

* remove unused method

* remove fileexists

* remove folderexists

* remove readalllines

* remove fake local file system

* show playlist name in playout build errors

* add basic sequential schedule validator tests

* work around sequential schedule validation limit
2025-11-24 12:08:43 -06:00
Jason Dove
e40d192aea limit hw sw decode downgrade polaris (#2654)
* use a more precise carve out for polaris workaround

* fix decode capability ordering
2025-11-22 12:35:29 -06:00
Jason Dove
bd7fd8984c fix 10-bit decoding with amd polaris (#2653)
* fix color conversion on amd polaris

* try software decode for polaris

* update changelog
2025-11-22 11:29:17 -06:00
Jason Dove
2682912f5a update icon (#2652) 2025-11-21 13:34:23 -06:00
Jason Dove
505e135482 use fonts cache folder for subtitle graphics elements (#2651) 2025-11-18 10:18:22 -06:00
Jason Dove
fdf1e70e0d fix subtitle graphics element path and fonts (#2650) 2025-11-18 10:16:03 -06:00
Jason Dove
5c51710e2f add disabled and hidden channel indicators (#2649) 2025-11-16 10:47:10 -06:00
Jason Dove
3cb84c2491 refresh classic playouts by default (#2647) 2025-11-15 20:45:28 -06:00
Jason Dove
21f4439aa4 block ui improvements (#2646)
* template editor improvements

* more keyboard navigation

* replace template tree view with template table
2025-11-13 19:25:44 -06:00
Jason Dove
d88e721d2f optimize database calls related to search index (#2645) 2025-11-13 13:27:37 -06:00
Jason Dove
b6d509b9cd add search query collection type to block schedules (#2644)
* add search query collection type to block schedules

* fix history
2025-11-13 10:48:04 -06:00
Jason Dove
6603500132 fix content_total_duration in graphics engine (#2643) 2025-11-12 20:07:54 -06:00
Jason Dove
48b1aa3e64 fix block playout build bug (#2642) 2025-11-12 16:53:06 -06:00
Jason Dove
42b35f7aae add channel playback troubleshooter (#2641)
* fix motion graphics loop when seeking

* add channel playback troubleshooter

* fix errors
2025-11-12 13:21:18 -06:00
Jason Dove
8b18f2a304 expose arbitrary epg data to graphics engine (#2633) 2025-11-11 12:41:45 -06:00
Jason Dove
1e0bba0dc6 allow custom song background images (#2632)
* allow custom song background images

* allow custom missing album art
2025-11-11 10:40:45 -06:00
Jason Dove
3984bc7dbe add troubleshoot playback links for movies and episodes (#2631) 2025-11-11 06:33:10 -06:00
Jason Dove
e0977fa65b update dmg icon (#2630) 2025-11-11 06:12:46 -06:00
Jason Dove
d9c668c7f6 more dependency updates (#2629) 2025-11-11 05:45:46 -06:00
Jason Dove
dcea6d474f update dependencies (#2627) 2025-11-10 22:20:42 -06:00
Jason Dove
ba37c6dabe update macos again (#2626) 2025-11-10 20:19:38 -06:00
Jason Dove
d652372f78 update macos project (#2625) 2025-11-10 19:52:34 -06:00
Jason Dove
e2d8dee8cd artwork updates (#2624)
* add new logo svg; replace favicons

* replace background

* allow error/offline background customization
2025-11-10 16:01:47 -06:00
Jason Dove
d93c404607 fix interlaced check again (#2623)
* fix interlaced check again

* add interlaced ratio to media item info
2025-11-10 09:14:40 -06:00
Jason Dove
bc400de94c clear custom title when stopping guide group in scripted schedule (#2622) 2025-11-10 08:51:34 -06:00
Jason Dove
b9a73226a8 fix interlaced check (#2621)
* fix interlaced check

* reset any incorrect interlaced probe results
2025-11-10 08:39:44 -06:00
Jason Dove
d0505cd5c5 add better check for interlaced content (#2620) 2025-11-10 06:39:04 -06:00
Jason Dove
d9cdbc72de fix tests [no ci] 2025-11-09 13:50:18 -06:00
Jason Dove
2b0079fedc allow graphics elements with yml and yaml extension (#2617) 2025-11-09 13:40:34 -06:00
Jason Dove
9d2cff53c5 fix removing tags from local libraries (#2616) 2025-11-09 13:30:37 -06:00
Jason Dove
ac361b3165 add troubleshoot button to classic schedules (#2615)
* add troubleshoot button to classic schedules

* move troubleshoot button
2025-11-09 10:17:24 -06:00
Jason Dove
dd9317e3e8 fix mpegts script on windows (#2614) 2025-11-08 10:09:56 -06:00
Jason Dove
7530c592ff add graphics element name (#2613)
* add graphics element name

* update dependencies
2025-11-08 08:26:00 -06:00
Jason Dove
132466b3d3 add avisynth script support to all local libraries (#2612)
* detect avisynth demuxer

* cache ffmpeg capabilities

* check for working avisynth

* scan avs files in all local libraries

* update changelog
2025-11-07 20:48:54 -06:00
Jason Dove
d709cc9f21 include streamlink in amd64 docker image (#2611)
* include streamlink in docker images

* tweak command
2025-11-07 14:12:43 -06:00
Jason Dove
5083e748ed fix mpegts script loading (#2610) 2025-11-07 13:30:37 -06:00
Jason Dove
053b3cd1d7 add mpegts script system (#2609)
* add basic mpegts script

* use custom mpegts script

* update changelog
2025-11-07 13:20:17 -06:00
Joe Kirchoff
c3c7ff2669 Update audio codec in default FFmpeg profile name (#2608)
Quick fix for mismatch against profile audio codec setting.
2025-11-07 05:27:09 -06:00
Jason Dove
e6824cf251 graphics engine: add scaled resolution and place within source content (#2606) 2025-11-06 14:15:55 -06:00
Jason Dove
d87561d140 update subtitle titles (#2605) 2025-11-06 06:11:57 -06:00
Jason Dove
f79fa9a50a fix subtitle title updates (#2604) 2025-11-06 06:03:32 -06:00
Jason Dove
629b3d7d9f fix effective block tests (#2600)
* fix effective block tests running on github

* update dependencies

* pass tz again

* use tzconvert for time zones in tests

* temporary logging

* maybe fix

* test cleanup
2025-11-05 06:48:49 -06:00
Jason Dove
453737a521 add custom_title to start_epg_group (#2599) 2025-11-04 16:08:07 -06:00
Jason Dove
dd38ba19ea add collection type search query (#2598) 2025-11-04 12:22:41 -06:00
Jason Dove
8e2a15296f sync subtitle titles from jellyfin (#2595) 2025-11-03 11:04:44 -06:00
Jason Dove
d2cbfcb79a fix error screen generation (#2594) 2025-11-02 10:41:56 -06:00
Jason Dove
89133255d3 fix classic schedule start time calculation across a UTC offset change (#2593)
* fix classic schedule start time calculation across a UTC offset change

* update changelog
2025-11-02 09:38:18 -06:00
Jason Dove
c6245bae0c fix indexing songs with null artists/album artists (#2592) 2025-11-02 09:25:46 -06:00
Jason Dove
2912e71c10 fix xmltv generation for on-demand playout mode (#2591) 2025-11-01 23:10:02 -05:00
Jason Dove
9e54d42e5f reduce search index batch size (#2590) 2025-11-01 22:45:14 -05:00
Jason Dove
63f342e6a7 fix on-demand playouts having empty xmltv (#2589) 2025-11-01 22:08:49 -05:00
Jason Dove
5a7c59d602 insert unscheduled gaps as utc (#2588) 2025-11-01 20:28:24 -05:00
Jason Dove
4822ba5486 fix block start time calculation (#2587) 2025-11-01 20:16:04 -05:00
Jason Dove
b24617fe7c add some graphics engine template data fields (#2586)
* move resolution out of media item template data key

* add some media item template data
2025-11-01 08:29:56 -05:00
Jason Dove
5045a411b1 fix sequential schedule building across offsets (#2584) 2025-10-31 09:20:09 -05:00
Jason Dove
425fb34317 show playout warnings count in left menu (#2583) 2025-10-31 09:05:25 -05:00
Jason Dove
e5ef9be09c fix explicit audio decoder on combined input (#2582) 2025-10-30 14:37:16 -05:00
Jason Dove
e9338b534b fix seeking content with dts audio (#2581)
* fix seeking content with dts audio

* formatting
2025-10-30 14:13:00 -05:00
Jason Dove
191e694545 fix block playout ui crash (#2580) 2025-10-29 14:16:59 -05:00
Jason Dove
727a978689 fix block history and smart_collection search bugs (#2579)
* fix block history when using mirror offset

* fix smart_collection search crashes
2025-10-29 14:01:14 -05:00
Jason Dove
7a133d46da fix remote stream scripts (#2573) 2025-10-28 12:57:13 -05:00
Jason Dove
b1fbf651a2 log remote stream scripts (#2572) 2025-10-28 09:49:48 -05:00
Jason Dove
0dbdcc3674 fix hls direct with jellyfin 10.11 (#2570) 2025-10-26 18:09:37 -05:00
Jason Dove
9eb7bbf0e6 prep for release v25.8.0 [no ci] 2025-10-26 09:22:02 -05:00
Jason Dove
e851a295a6 fix scripted schedule building across offsets (#2569) 2025-10-26 09:07:21 -05:00
Jason Dove
3b254735e6 fix transcoding tests; fix vaapi subtitle crop (#2568)
* fix transcoding tests using text subtitles

* fix vaapi picture subtitle overlay with crop

* more test improvements
2025-10-26 08:51:24 -05:00
Jason Dove
1f8834c280 block playout fixes; hls direct fixes (#2566)
* fix block playout builder with empty collection

* fix hls direct when selecting audio

* allow embedded subtitles with hls direct
2025-10-25 06:35:56 -05:00
Jason Dove
545db4db9b update dependencies (#2565)
* logging cleanup

* update dependencies
2025-10-24 09:17:45 -05:00
Jason Dove
e590298b93 add deep scans for external collections (#2562) 2025-10-23 19:32:38 -05:00
Jason Dove
a47510fef3 add aac (latm) audio format (#2561)
* add aac (latm) audio format

* update changelog
2025-10-23 15:56:13 -05:00
Jason Dove
e089b12c2b trakt list fixes (#2560)
* show reset playout build failures

* fix scheduling trakt list playlists that contain shows
2025-10-23 11:15:55 -05:00
Jason Dove
82e0fcaec8 maintain source fps when using qsv (#2558) 2025-10-22 14:27:01 -05:00
Jason Dove
f7c699248c fix collection and network scanners (#2557) 2025-10-22 08:59:06 -05:00
Jason Dove
2d53063ce9 edit jellyfin and emby connection info (#2556) 2025-10-21 19:10:48 -05:00
Jason Dove
626048f9c3 change how scanner and main process communicate (#2555)
* report scanner progress using api

* process scanner search index updates through api

* update changelog

* update dependencies
2025-10-21 15:08:49 -05:00
Jason Dove
2ef2b0299a switch back from fmp4 to ts segments (#2554)
* restore pts offset calculation

* use ts segments again

* update changelog
2025-10-21 12:17:05 -05:00
Jason Dove
fcce53a3df fix a couple ui errors (#2551) 2025-10-20 10:54:43 -05:00
Jason Dove
d4353f6d42 add episode thumbnail to xmltv template (#2550) 2025-10-19 12:13:40 -05:00
Jason Dove
64ea413b6f fix nvidia 10 bit text subtitles and permanent watermark (#2549)
* fix nvidia 10 bit text subtitles and watermark

* update changelog
2025-10-19 11:18:15 -05:00
Jason Dove
d14ebf3522 properly track discontinuity sequences with fmp4 (#2548)
* properly track discontinuity sequences with fmp4

* update dependencies
2025-10-19 10:31:11 -05:00
Jason Dove
889904e70d fix management of fmp4 init segments (#2546) 2025-10-18 22:52:45 -05:00
Jason Dove
35e7922836 fix mpegts wrapper with fmp4 segmenter source (#2545) 2025-10-18 16:37:31 -05:00
Jason Dove
ffe15629cb consolidate streaming modes (#2544)
* consolidate segmenters

* let old segmenter mode query params continue to work
2025-10-18 10:54:30 -05:00
Jason Dove
ba5a027525 reduce playout log spam (#2543) 2025-10-18 08:59:17 -05:00
Jason Dove
a33ac4a048 fix qsv audio sync (#2542)
* fix qsv audio sync

* cast a wider net

* always reset qsv pts
2025-10-17 20:01:25 -05:00
Jason Dove
7ae028e2e9 fix trakt list sync (#2540) 2025-10-16 14:00:56 -05:00
Jason Dove
6404dee646 update dependencies (#2539) 2025-10-15 08:41:38 -05:00
Jason Dove
940d26419c fix buffer logging (#2535) 2025-10-14 15:55:27 -05:00
Jason Dove
9bae8e73bf slightly increase throttled readrate in segmenter (#2534) 2025-10-14 14:53:56 -05:00
Jason Dove
f41f4b19d4 wait for two initial segments in playback troubleshooting (#2532) 2025-10-14 11:45:11 -05:00
Jason Dove
917acf9683 fix hls segmenter fmp4 on windows (#2531)
* fix hls segmenter fmp4 on windows

* try to fix by using working directory
2025-10-14 10:29:08 -05:00
Jason Dove
da4687ac0f fix nvidia capabilities on windows (#2530) 2025-10-14 09:32:10 -05:00
Jason Dove
d1af6599f0 fix segmenter repeating content when stream first starts (#2529) 2025-10-14 08:53:22 -05:00
Jason Dove
4e43817f8e add graphics engine text halo (#2528) 2025-10-14 06:41:32 -05:00
Jason Dove
ebcd9a35a7 fix scaling image subs with vaapi (#2526) 2025-10-13 19:42:01 -05:00
Jason Dove
ea5956a268 improve stream startup (#2525) 2025-10-13 16:26:06 -05:00
Jason Dove
65ff1f5502 improve live stream reliability (#2524) 2025-10-13 15:41:48 -05:00
Jason Dove
5ef8b04119 fix intermittent watermark opacity (#2523) 2025-10-13 12:00:58 -05:00
Jason Dove
99837e808a fix speed parsing (#2522) 2025-10-13 11:49:39 -05:00
Jason Dove
7c2083d3f2 add playback troubleshooting speed indicator (#2521)
* more api fixes

* add playback troubleshooting speed indicator
2025-10-13 11:25:56 -05:00
Jason Dove
b851a7daba api changes for ffmpeg profiles (#2520) 2025-10-13 06:44:32 -05:00
Jason Dove
48e7c85f7b api changes to support etvcli (#2519) 2025-10-12 10:13:30 -05:00
Jason Dove
bf4182f115 add copy block button (#2518) 2025-10-11 13:35:22 -05:00
Jason Dove
fb9ca8953e add text element formatting options (#2517) 2025-10-11 12:45:20 -05:00
Jason Dove
48310e044b optimize first run (#2516)
* do not accept ui requests until database is ready

* add empty database to greatly speed up initial startup

* remove middleware
2025-10-11 09:05:31 -05:00
Jason Dove
144b3fe80b fix remote stream durations in playouts (#2515) 2025-10-11 08:30:24 -05:00
Jason Dove
4a754c4e6a add helper text for sequential schedule file (#2514) 2025-10-11 06:43:59 -05:00
Jason Dove
7059669023 add schedule file names to playouts table (#2513) 2025-10-10 21:55:22 -05:00
Jason Dove
c03f81a465 add block playout troubleshooting tool (#2512)
* rename yaml validation to sequential schedule validation

* some better exception handling

* add block playout troubleshooting page

* add paged block playout history

* add history details

* update changelog
2025-10-10 20:50:01 -05:00
Jason Dove
e3d07050bf graphics element template data improvements (#2511)
* add other video template data

* add path and related functions
2025-10-10 13:47:18 -05:00
Jason Dove
5a88bfc310 use old ffmpeg pipeline for single permanent watermark (#2510) 2025-10-10 10:14:29 -05:00
Jason Dove
dd92a65742 more nvidia capabilities safety (#2509) 2025-10-09 22:16:30 -05:00
Jason Dove
07ffa1642b fix nvidia troubleshooting on arm64 (#2508) 2025-10-09 22:07:07 -05:00
Jason Dove
6fc602323f catch proper exception (#2507) 2025-10-09 21:46:54 -05:00
Jason Dove
d5fd8e7be6 another attempt at fixing nvidia startup (#2506)
* another attempt at fixing nvidia startup

* update dependencies
2025-10-09 21:36:55 -05:00
Jason Dove
dba5485300 fix nvidia startup errors on arm64 (#2505) 2025-10-09 21:26:27 -05:00
Jason Dove
6847a133ca prep for release v25.7.1 [no ci] 2025-10-09 10:40:05 -05:00
Jason Dove
fd60c120ae add more cuda logging (#2503) 2025-10-08 20:04:18 -05:00
Jason Dove
371d1d89fb push cuda context when checking capabilities (#2502) 2025-10-08 19:44:29 -05:00
Jason Dove
ec6bc797f4 update cuda failure logging (#2501) 2025-10-08 19:13:24 -05:00
Jason Dove
4c57167864 package windows artifacts using zip instead of 7z (#2496) 2025-10-07 10:11:51 -05:00
Jason Dove
9016523757 cleanup some exceptions; add health check (#2495)
* handle artwork timeouts so they aren't reported

* catch some more cancellation errors

* add free space validation on startup

* add downgrade health check

* update dependencies
2025-10-07 09:50:55 -05:00
Jason Dove
6a38c91d54 update changelog [no ci] 2025-10-06 16:25:28 -05:00
Jason Dove
9ec4d0a85c show graphics engine scriban errors in log (#2491)
* show graphics engine scriban errors in log

* better fix
2025-10-06 16:24:40 -05:00
Jason Dove
4cb98242ba do not allow deleting default ffmpeg profile (#2490)
* remove dead code

* do not allow deleting default ffmpeg profile
2025-10-06 06:11:36 -05:00
Jason Dove
0e2084838a use a table for blocks (#2489) 2025-10-05 09:45:29 -05:00
Jason Dove
f3f900b4ca fix playback troubleshooting (#2488) 2025-10-05 06:06:56 -05:00
Jason Dove
c39858b2d8 fix hls direct (#2487) 2025-10-04 15:36:36 -05:00
Jason Dove
0363609923 allow h264 video profile using vaapi (#2485) 2025-10-04 08:40:10 -05:00
Jason Dove
a02aa37957 do not delete ffmpeg profile used by channel (#2484) 2025-10-04 08:29:07 -05:00
Jason Dove
86a7563da5 prep for release v25.7.0 [no ci] 2025-10-03 19:35:06 -05:00
Jason Dove
cd4715a32e update changelog [no ci] 2025-10-03 10:49:00 -05:00
Jason Arends
fc04118bf9 Emby: accept non-File protocols for Movie items (only require MediaSources present) (#2483) 2025-10-03 10:41:03 -05:00
Jason Dove
dd5fd1ef8f fix cropping jellyfin and emby content that is too small (#2481)
* fix cropping jellyfin and emby content that is too small

* fix transcoding tests with nvidia

* update dependencies
2025-10-02 20:13:40 -05:00
Jason Dove
404f898b2f fix build 2025-10-02 13:41:49 -05:00
Jason Dove
3e8ac9914c refactor playout build errors (#2480)
* refactor classic playout builds

* refactor sequential playout builds

* refactor block playout building

* don't fail building an empty block schedule

* fix scripted playout build errors
2025-10-02 13:36:39 -05:00
Jason Dove
a0788532a0 ignore embedded text subtitles that have not been extracted (#2479)
* ignore text subtitles that have not been extracted

* fix bug with channel paging
2025-10-02 12:41:04 -05:00
Jason Dove
b3daad7c3b improve playout error formatting (#2477) 2025-10-01 21:55:55 -05:00
Jason Dove
598de5d5d6 add playout build status (#2476)
* add playout build status

* show build status in playout list

* update changelog
2025-10-01 21:40:39 -05:00
Jason Dove
5c174eabdb add playback troubleshooting logs (#2475) 2025-10-01 16:29:04 -05:00
Jason Dove
18905a79dc add stream selector to playback troubleshooting (#2474) 2025-10-01 11:10:38 -05:00
Jason Dove
077fed6cac fix vaapi h264 constrained baseline decode (#2473)
* fix vaapi h264 constrained baseline decode

* update changelog
2025-09-30 19:32:45 -05:00
Jason Dove
fac0f36d35 add codec info to multivariant playlist (#2472)
* add codec info to multivariant playlist

* upgrade dependencies
2025-09-30 13:58:24 -05:00
Jason Dove
287adc34b5 add qsv av1 encoder (#2471) 2025-09-30 13:13:26 -05:00
Jason Dove
6ff153f01d add vaapi av1 encoder (#2470) 2025-09-30 12:18:29 -05:00
Jason Dove
e3af0f0b69 add nvidia av1 encoder (#2469) 2025-09-30 11:43:12 -05:00
Jason Dove
b46de50801 add hls segmenter fmp4 streaming mode (#2468)
* add streaming mode segmenter fmp4

* allow hevc channel preview
2025-09-30 10:04:02 -05:00
Jason Dove
77163e6746 use gif watermark metadata in graphics engine (#2465) 2025-09-29 14:28:02 -05:00
Jason Dove
1763c897eb fix filler expression with playlists (#2464) 2025-09-29 14:05:27 -05:00
Jason Dove
ac45d6acd4 use cuvid to check nvidia decode capabilities (#2461)
* detect nvidia decode capabilities

* use cuvid to check b-ref mode
2025-09-27 18:44:48 +00:00
Jason Dove
8b4b7cf16a fix nvidia in docker; minimize nvenc sessions (#2460) 2025-09-27 17:13:56 +00:00
Jason Dove
b820b798cb use nvenc to detect encoder capability (#2459) 2025-09-27 16:30:14 +00:00
Jason Dove
dc92a96bd9 fix playlist preview (#2457) 2025-09-25 13:54:44 +00:00
Jason Dove
18523dce64 add scripted playout timeout setting (#2456)
* add setting for scripted playout build timeout

* update dependencies
2025-09-25 02:33:49 +00:00
Jason Dove
ffb50a9404 fix link [no ci] 2025-09-21 20:06:56 -05:00
Jason Dove
7462039301 update readme [no ci] 2025-09-21 20:05:57 -05:00
Peter Dey
c71269058e Display hostname & build configuration when build config is not "release" (#2449)
* Display hostname & build configuration when build config is not "release" (default).

* Add missed ARG line for arm64/Dockerfile
2025-09-21 19:04:15 +00:00
Jason Dove
9ec220c122 add page to edit channel numbers (#2454) 2025-09-21 18:31:16 +00:00
Jason Dove
fc97a2da3c update issue template [no ci] 2025-09-21 09:02:13 -05:00
Jason Dove
ddc1120904 fix maintaining embedded text subtitles from media server (#2453)
* properly reset extracted flag on subtitles

* optimize subtitle updates; extract after targeted deep scan

* fix extracted text subtitle playback from media servers
2025-09-21 13:54:08 +00:00
Jason Dove
e70e4fb826 fix some invalid external subtitle data (#2451) 2025-09-21 03:13:20 +00:00
Jason Dove
b790b5944c fix external ssa subtitles from media servers (#2450) 2025-09-20 21:13:42 +00:00
Jason Dove
0ca1859802 limit nvidia workaround to h264 (#2448) 2025-09-20 17:31:55 +00:00
Jason Dove
07a160fcc6 work around nvidia green line (#2447) 2025-09-20 16:12:08 +00:00
Jason Dove
788a1ecdc4 add deco break content (#2446)
* add initial models

* migrations

* edit break content mode

* add and remove break content from ui

* use autocompletes in deco editor

* save break content to db

* allow break content playlists

* refactor default filler build

* fix slow startup

* start to implement adding break content

* use clone; try to fix block breaks

* fix updating history

* use consistent removebefore values

* cleanup logging

* only allow playlist break content

* update changelog
2025-09-19 18:48:51 +00:00
Jason Dove
004da8b7aa use better fields for filler preset duration (#2442) 2025-09-18 15:56:51 +00:00
Jason Dove
c8679144c5 add text element text_fit options (#2441) 2025-09-18 14:08:24 +00:00
Jason Dove
a389c1bbbe more search fields and highlighting (#2440) 2025-09-18 11:36:24 +00:00
Jason Dove
ecacf3960f add search fields to filter collections and schedules tables (#2439) 2025-09-18 10:44:11 +00:00
Jason Dove
aa5ba5a78e fix recent nvidia regression (#2437)
* fix recent nvidia regression

* update transcoding tests for graphics engine
2025-09-18 03:15:23 +00:00
Jason Dove
9e111a103e fix fallback on mirror channels (#2436) 2025-09-17 18:14:25 +00:00
Jason Dove
8bc3457de0 fix hls playlist filtering (#2435)
* add failing test

* fix hls playlist filtering
2025-09-17 15:42:23 +00:00
Jason Dove
febabcff6f fix running tests in github (timezone issue) (#2434) 2025-09-17 14:16:54 +00:00
Jason Dove
f26e48c063 block schedules: skip items and collections that will never fit (#2433)
* add first block playout builder test

* block schedules: skip items and collections that will never fit
2025-09-17 13:53:50 +00:00
Jason Dove
6465c416ff motion end behavior (#2431)
* add end behavior enum and properties

* support loop end behavior

* implement end behavior hold

* update changelog
2025-09-17 03:35:49 +00:00
Jason Dove
a0e0bb8753 fix motion element timing (#2430) 2025-09-17 01:09:00 +00:00
Jason Dove
b9451a6585 add motion graphics elements (#2428)
* crude motion graphics element

* fix motion element rendering

* implement motion element scaling

* implement motion start seconds

* update changelog
2025-09-16 21:34:08 +00:00
Jason Dove
0c49f4799f fix playback of content with unknown color range (#2427) 2025-09-16 16:20:43 +00:00
Jason Dove
ea008776b1 more nvidia 10-bit fixes (#2426)
* fix playback with invalid ffmpeg profile

* fix 10 bit output with nvidia and graphics engine
2025-09-16 14:44:22 +00:00
Jason Dove
9aa7c44388 add watermarks and graphics elements to block items (#2424) 2025-09-16 02:39:25 +00:00
Peter Dey
d855e4f20d Add initial support for Rockchip Media Process Platform (rkmpp) hardware acceleration (#2418)
* Add Rockchip Media Process Platform (rkmpp) acceleration

* remove fourcc stuff; it's exclusive to videotoolbox

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2025-09-16 00:51:56 +00:00
Jason Dove
9da655e210 keep at least 10 bit color throughout nvidia tonemap pipeline (#2423) 2025-09-15 20:47:15 +00:00
Jason Dove
03b9db7835 fix green output with libplacebo and nvidia 10 bit (#2422) 2025-09-15 19:40:27 +00:00
Jason Dove
245165c9d9 add rerun collection type (#2421)
* rename collection type

* split collections into separate pages

* add rerun collection types, migration, editor

* add rerun to classic schedule items

* rerun plumbing in classic playout builder

* start to implement rerun enumerator

* add scheduledAt to enumerator movenext

* maintain rerun history in db

* fix shuffle

* fix rerun allowed playback orders

* fix updating rerun collections

* update changelog; fix editing

* update changelog
2025-09-15 18:27:55 +00:00
Jason Dove
fe5dd80f70 prep for release v25.6.0 [no ci] 2025-09-14 12:54:06 -05:00
Jason Dove
8155e2e441 add shuffle in order for collections in playlists (#2417) 2025-09-14 13:08:42 +00:00
Jason Dove
307b9dadd2 partial v4l2m2m accel support (#2416)
* start to add v4l2m2m accel

* add v4l2m2m pipeline

* add encoders

* fix decoders and encoders

* output software frames from decoders

* more buffers

* hide v4l2m2m from ui
2025-09-14 11:48:24 +00:00
Jason Dove
5379a893f7 generate fake epg data for graphics elements when troubleshooting (#2415) 2025-09-14 03:01:16 +00:00
Jason Dove
64bb1b0d61 fix classic schedule flood bug (#2414)
* clean up some logging

* fix classic schedule flood bug
2025-09-14 02:36:50 +00:00
dependabot[bot]
89968f722a Bump jetbrains.resharper.globaltools from 2025.2.0 to 2025.2.1 (#2378)
---
updated-dependencies:
- dependency-name: jetbrains.resharper.globaltools
  dependency-version: 2025.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-13 15:11:19 +00:00
Jason Dove
bc721755f5 add graphics elements to decos (#2413)
* add deco graphics elements, selector and tests

* add migrations

* edit deco graphics elements from ui

* update changelog
2025-09-13 15:02:48 +00:00
Jason Dove
9182a8ad18 cleanup graphics element loading (#2412) 2025-09-13 13:39:20 +00:00
Jason Dove
c5265943f5 fix inefficient database migration (#2411) 2025-09-13 03:42:54 +00:00
Jason Dove
07a55da76e process graphics element yaml files with scriban (#2410)
* add content rating to media item template

* process graphics element yaml files with scriban
2025-09-13 03:04:46 +00:00
Jason Dove
3722bc8c9c add some database startup logging (#2409)
* add some database startup logging

* fix unscheduled playout gap offset

* fix database logging
2025-09-13 00:50:47 +00:00
Peter Dey
87bc779d48 Show fillers in the playout view in alternative shading (#2405)
* Add shading to filler rows in the playout view

* Insert rows in Playout listing for gaps in the playout (station offline)

* Make FillerKind in PlayoutItemViewModel optional.
Remove Unscheduled enum in FillerKind.

* Correctly handle "Show Filler" also for Unscheduled fillers.
* Moved the Unscheduled item generation for the playout view to GetFuturePlayoutItemsByIdHandle to handle ShowFiller
* Includes for the PlayoutItemDetails moved to an extension for maintainability.
* Bugfix: Page size was more than the desired for pagination because of the inserted unscheduled items.

* Add specified colours for playout fillers to make them less intense.

* use common queryable

* add playout gap model and migrations

* insert playout gaps after playout build

* optimize get future playout items handler

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2025-09-13 00:30:34 +00:00
Jason Dove
f124554fba add some debug logging for music video scanning (#2408) 2025-09-12 16:56:29 +00:00
Jason Dove
17c7774603 add playlist item count and shuffle playlist items (#2407)
* marathon cleanup

* add playlist item count, and shuffle playlist items
2025-09-12 14:19:05 +00:00
Jason Dove
4e065fe922 update dependencies (#2406) 2025-09-11 18:04:48 +00:00
Jason Dove
2cca3123aa fix issue [no ci] 2025-09-11 09:43:52 -05:00
Jason Dove
dabc67976a update github issues 2025-09-11 09:41:46 -05:00
Jason Dove
bd6954121f log api requests (#2404) 2025-09-10 00:50:03 +00:00
Jason Dove
a2fd23a131 fix deco selection logic (#2403) 2025-09-09 18:07:50 +00:00
Jason Dove
388623f82e fix changing playout source from mirror to generated (#2402) 2025-09-09 17:19:00 +00:00
Jason Dove
6b275f8a13 fix hwaccel health check on mobile (#2401)
* fix hw accel health check on mobile

* allow classic schedules to fast forward
2025-09-09 16:57:49 +00:00
Jason Dove
0d69dd58a4 add classic schedule marathon (#2400) 2025-09-09 15:38:07 +00:00
Jason Dove
79e8fa0877 ignore specials when using season, episode order (#2399) 2025-09-08 15:12:51 +00:00
Jason Dove
044c8b7ad3 fix graphics engine with scaling behavior crop (#2398) 2025-09-08 13:36:13 +00:00
Jason Dove
e8b51e8442 fix watermarks and graphics when using mid-roll (#2397) 2025-09-08 10:59:25 +00:00
Jason Dove
d8e8abb691 channel mirror validation improvements (#2396)
* improve channel mirror validation

* fix playout offset
2025-09-08 01:12:58 +00:00
Jason Dove
e9093d0c48 fix block playout build crash from empty collections (#2395) 2025-09-08 00:42:02 +00:00
khreezy
cb78b21d1c add support for aif, aifc, aiff (#2325)
* adds .aiff to supported audio file extension in local folder scanner

* add support for aif, aifc, aiff

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2025-09-07 19:24:43 +00:00
Jason Dove
906ec44a6e fix scripted pre-roll overlap (#2394)
* fix scripted pre-roll overlap

* cleanup
2025-09-07 18:36:10 +00:00
Jason Dove
e96ac0202b add mirror playout offset (#2391) 2025-09-07 16:45:41 +00:00
Jason Dove
5e7da19e5e add channel mirror (#2390)
* add channel playout source (doesn't do anything yet)

* configure mirror channel

* fix mirror playback

* sync epg for mirror channel

* update changelog
2025-09-07 16:00:27 +00:00
Jason Dove
e25b669cc4 fix scaling content in certain locales (#2389) 2025-09-07 14:20:11 +00:00
Jason Dove
d80c6737a9 fix mysql permissions (#2388) 2025-09-07 13:21:48 +00:00
Jason Dove
ef5de99f9c add create_playlist, pre_roll_on, pre_roll_off to scripted schedules (#2387) 2025-09-06 20:47:44 +00:00
Jason Dove
e047812a68 rework some scripted schedule model names (#2386) 2025-09-06 18:52:34 +00:00
Jason Dove
3da5144a0d update entrypoint so reset_playout is not required to return an updated context (#2385) 2025-09-06 16:22:07 +00:00
Jason Dove
31355ab887 add pad_until_exact and wait_until_exact scripted schedule calls (#2384) 2025-09-06 15:43:07 +00:00
Jason Dove
63bac272cd fix adding classic schedule items (#2383) 2025-09-06 00:15:05 +00:00
Jason Dove
8d5a208129 fix adding single items to playlists (#2382) 2025-09-05 18:44:08 +00:00
Jason Dove
487d99dc69 openapi improvements (#2381)
* generate openapi definitions as separate build task

* first defns

* install etv-client module in docker

* include python entrypoint in docker

* update changelog
2025-09-05 17:11:43 +00:00
Jason Dove
40ab7c2cff add graphics elements on classic schedule items (#2380) 2025-09-05 11:53:29 +00:00
Jason Dove
a6de96c2ea fix openapi client generation again (#2379) 2025-09-05 10:52:34 +00:00
Jason Dove
0d82e0234b fix scripted schedule validation (#2377) 2025-09-05 01:27:16 +00:00
Jason Dove
1e9e41b808 use tagged openapi for docs; no tags for client (#2376) 2025-09-05 01:01:28 +00:00
Jason Dove
57e9b4d264 more api docs (#2375) 2025-09-04 18:00:48 +00:00
Jason Dove
73b8d68a09 add existing api endpoints to scalar docs (#2374) 2025-09-04 16:36:26 +00:00
Jason Dove
03921e1ff7 more docs reorganization (#2373) 2025-09-04 15:20:02 +00:00
Jason Dove
70aae67873 reorganize scalar docs (#2372) 2025-09-04 14:59:17 +00:00
Jason Dove
67cb931a47 fix verbs, add scalar docs (#2371) 2025-09-04 14:01:16 +00:00
Jason Dove
704c1ec535 return context from scripted schedule api calls that modify the context (#2370) 2025-09-04 13:42:00 +00:00
Jason Dove
06332c8360 allow custom scripted schedule arguments (#2368) 2025-09-03 21:39:30 +00:00
Jason Dove
03b4419f67 rework scripted schedules (#2367)
* start to reorganize scripted playout building

* add openapi

* add all content fns

* add playout instructions

* add control instructions

* add request models

* prevent build loop

* rename

* update changelog

* tweak changelog
2025-09-03 20:53:14 +00:00
Jason Dove
7ac93c6aad fix transcoding bt709/pc (#2363) 2025-09-02 18:28:09 +00:00
Jason Dove
6ca72baa00 prep for release v25.5.0 [no ci] 2025-09-01 19:59:13 -05:00
Jason Dove
6b953ab5ca fix long season placeholder text (#2362) 2025-09-02 00:35:22 +00:00
Jason Dove
272f528f7a fix segmenter v2 with videotoolbox accel (#2361)
* fix segmenter v2 with videotoolbox

* more capabilities checks
2025-09-01 13:35:37 +00:00
Jason Dove
07c1156a63 update yaml schema for new pad_to_next fields (#2360) 2025-09-01 01:53:17 +00:00
Jason Dove
eadacc7f8c add stop_before_end and offline_tail to pad_to_next (#2359) 2025-08-31 23:03:46 +00:00
Jason Dove
380070731a startup improvements (#2356)
* redirect to index when initializing

* clear stale sqlite migration lock on startup
2025-08-30 13:16:54 +00:00
Jason Dove
7720e6ba39 fix hls segmenter v2 with amf accel (#2355) 2025-08-29 20:01:31 +00:00
Jason Dove
8a1cf72209 more alternate schedule fixes (#2354)
* always start with the first schedule item

* reset program schedule items to zero-based index on save

* log offline gaps from strict start times
2025-08-28 14:48:39 +00:00
Jason Dove
b9759c983c fix alternate schedule transitions in classic schedules (#2353) 2025-08-27 21:31:48 +00:00
Jason Dove
9462156148 fix mysql playout builds (#2352)
* more cancellation tokens and fixes

* so much cancellation token

* fix mysql playout builds
2025-08-27 18:09:56 +00:00
Jason Dove
1c07df5bc3 use cancellation tokens in many places (#2350)
* use cancellation tokens everywhere

* more cancellation tokens
2025-08-27 03:20:35 +00:00
Jason Dove
a6198892f0 more mysql ui fixes (#2349) 2025-08-26 03:02:40 +00:00
Jason Dove
02a91c4e14 fix editing remote libraries with mysql/mariadb (#2348) 2025-08-26 01:44:59 +00:00
Jason Dove
b62a76d339 fix mysql migrations (#2347) 2025-08-26 00:40:19 +00:00
Jason Dove
d9f2f51aee fix fallback filler playback (#2346) 2025-08-25 21:56:00 +00:00
Jason Dove
8e77330781 timeout all scripted playout builds (#2345)
* check for progress in is_done

* timeout all scripted playout builds
2025-08-25 18:15:08 +00:00
Jason Dove
66c28e9b5f rework scripted schedule signatures; add start_time and finish_time (#2344) 2025-08-25 17:07:14 +00:00
Jason Dove
51ec84c94a fix block playout history regression (#2343)
* minor tweaks

* fix block change detection bug

* history cleanup cleanup
2025-08-25 16:09:20 +00:00
Jason Dove
a072e4357e add scripted add_all, add_duration, pad_to_next, pad_until (#2342)
* add add_all

* add add_duration

* add pad_to_next

* add pad_until
2025-08-24 17:49:18 +00:00
Jason Dove
605c57bef3 add scripted control instructions (#2341)
* add start_epg_group, stop_epg_group

* fix imports

* add graphics_on, graphics_off

* add skip_items

* add skip_to_item

* add watermark_on, watermark_off
2025-08-24 16:14:43 +00:00
Jason Dove
4e2310d008 add all content sources to scripted schedules (#2340)
* add show content

* add multi collection content

* add smart collection content

* add playlist content

* fix infinite loop

* add marathon content
2025-08-24 14:39:34 +00:00
Jason Dove
61a99c250a expose current_time as a python datetime (#2339) 2025-08-24 11:58:37 +00:00
Jason Dove
bbddd50f00 add new scheduling engine, basic scripted schedule system (#2337)
* start to add content to scheduling engine

* add first content instruction

* add search content

* allow scripted schedule creation

* don't use scheduling engine in sequential playout builder, yet
2025-08-24 03:11:58 +00:00
Jason Dove
53f281ce32 add xmltv block behavior setting (#2336)
* replace playout externaljsonfile and templatefile with schedulefile

* add scripted schedule-based playout

* wip - not functional yet

* temp disable scripted playout creation

* allow fast-forwarding block playouts

* add xmltv block behavior setting
2025-08-23 20:16:12 +00:00
Jason Dove
e06ee54070 rename yaml playout to sequential schedule (#2335)
* clarify some schedule and playout terms

* more renaming
2025-08-23 14:27:32 +00:00
Jason Dove
af23c6d541 copy watermark overrides when copying schedule (#2334) 2025-08-23 12:51:04 +00:00
Jason Dove
988ed8db04 fix changing default alternate schedule (#2331) 2025-08-18 15:37:21 +00:00
Jason Dove
31c18162e1 add deco watermark mode merge (#2330) 2025-08-18 11:42:27 +00:00
Jason Dove
0318e71745 refactor watermark selection (#2328)
* move watermark options into watermark selector

* fix graphics engine overlay performance

* more refactoring

* add some tests for existing watermark selector behavior

* remove extra ffprobe call on all watermarks

* remove a bunch of unused code; add failing tests

* implement new watermark selection

* add tests for new selector

* probably sufficient (though verbose) test coverage

* more tests

* remove some unused code

* simplify watermark selection

* remove old selection code and tests

* more tests
2025-08-18 01:04:36 +00:00
Jason Dove
1e7f9a5709 fix saving yaml playout history (#2327)
* fix saving yaml playout history

* cleanup
2025-08-17 01:21:07 +00:00
Jason Dove
330195d5e3 fix seeking into extracted text subtitles (#2326) 2025-08-17 00:23:51 +00:00
Jason Dove
5d081ceeff fix editorconfig and run code cleanup (#2324)
* fix formatting rules

* reformat ersatztv

* reformat ersatztv.application

* reformat ersatztv.core

* refactor ersatztv.core.tests

* reformat ersatztv.ffmpeg

* reformat ersatztv.ffmpeg.tests

* reformat ersatztv.infrastructure

* cleanup infra mysql

* cleanup infra sqlite

* cleanup infra tests

* cleanup ersatztv.scanner

* cleanup ersatztv.scanner.tests

* sln cleanup

* update dependencies
2025-08-16 14:44:48 +00:00
Jason Dove
6d32dac51b fix graphics engine opacity (#2323)
* fix skia opacity wip

* fix graphics engine opacity
2025-08-16 02:59:07 +00:00
Jason Dove
4f02bedf69 fix image loading regression in graphics engine (#2322) 2025-08-15 21:30:54 +00:00
Jason Dove
d71443ef60 add subtitle graphics element (#2321) 2025-08-15 19:48:04 +00:00
Jason Dove
d5608ac75f multiple bug fixes (#2320)
* fix incorrect media counts in local libraries

* completely replace imagesharp with skiasharp

* fix song troubleshooting playback

* fix usings
2025-08-15 16:06:55 +00:00
Jason Dove
a6b01cbe28 convert graphics engine from imagesharp to skiasharp (#2319)
* use skiasharp in graphics engine

* start to use richtextkit

* move out some template functions

* move files

* add base graphics element

* use default style in text element

* support partial styling in text element

* fix static images

* load fonts from text element definition
2025-08-15 14:27:22 +00:00
midnite8177
d0af507bef add ability to deep scan just a single tv show for Plex, Emby, and Jellyfin (#2318)
* add ability to deep scan just a single tv show for Plex, Emby, and Jellyfin

Including "/api/libraries/{id:int}/scan-show" REST API endpoint to
trigger.

* restrict plex search results to the intended library

* restrict scanning to media server libraries that are marked to sync with etv

* fix previous commit

* also guard library scan api

* add scan buttons to show ui

* scan single plex show by id

* scan jellyfin and emby single shows by id

* update changelog

---------

Co-authored-by: Jeff Slutter <MrMustard@gmail.com>
Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2025-08-14 16:07:56 +00:00
midnite8177
f626954eb7 add external chapter file scanning (#2317)
* add external chapter file scanning

Support Matroska chapter xml files next to media file with extension .xml or .chapters

* only update chapters in db

---------

Co-authored-by: Jeff Slutter <MrMustard@gmail.com>
Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2025-08-14 03:34:47 +00:00
Jason Dove
62e140ec98 block scheduling ui cleanup (#2316)
* sort block tree views

* fix naming validation for block scheduling

* show deco group name in deco editor

* show block group name in block editor

* show template group name in template editor

* show deco template group name in deco template editor

* fix template rename crash

* fix block rename crash

* fix deco template rename crash
2025-08-14 01:37:21 +00:00
Jason Dove
93bb7a0531 skip unused hwaccel with amf (#2315) 2025-08-13 22:03:52 +00:00
Jason Dove
f31a48c429 fix episodes from multiple plex servers (#2314) 2025-08-13 20:56:27 +00:00
Jason Dove
0841bc400b fix saving watermarks and graphics on playout items (#2313) 2025-08-13 19:37:46 +00:00
Jason Dove
8cc0d30c0e add some template helper functions for text elements (#2312) 2025-08-13 18:50:04 +00:00
Jason Dove
4b18ee6b66 add custom stream selector content_condition (#2311) 2025-08-13 16:34:17 +00:00
Jason Dove
558e2ce333 rename opacity to opacity_percent for consistency (#2310) 2025-08-13 15:21:25 +00:00
Jason Dove
c9e6e601c2 automatically refresh graphics elements (#2309) 2025-08-13 15:11:14 +00:00
Jason Dove
d28d0a9805 fix yaml playout progress (#2308) 2025-08-13 13:21:53 +00:00
Jason Dove
ac75a67709 block history fixes (#2307)
* fix deco to only have one collection id for filler/fallback

* fix duplicate playout history for deco filler
2025-08-13 01:02:41 +00:00
Jason Dove
5e463758da ignore unreliable anamorphic flag from jellyfin (#2306) 2025-08-12 23:32:11 +00:00
Jason Dove
2cb0d12701 load a configurable number of epg entries for text graphics (#2305)
* wip

* load a configurable number of epg entries for text graphics

* cleanup
2025-08-12 21:00:55 +00:00
Jason Dove
44ec0f8a0f add more template data to text graphics element (#2304) 2025-08-12 14:33:52 +00:00
Jason Dove
b149f7f2a3 fix overlapping playout items check (#2303) 2025-08-12 11:35:12 +00:00
Jason Dove
771bfba01c fix overlapping block playout items (#2302)
* check for overlapping playout items

* tweak block filler builder

* fix overlapping block playout items

* update changelog

* minor cleanup
2025-08-12 11:14:24 +00:00
Jason Dove
820c2a5ccc fix watermark validation (#2301) 2025-08-11 18:55:45 +00:00
Jason Dove
91c4e8f575 add seek seconds to playback troubleshooting (#2300) 2025-08-11 18:10:36 +00:00
Jason Dove
a04adf45c0 fix green padding with vaapi i965 driver (#2298) 2025-08-11 17:39:01 +00:00
Jason Dove
8cbc3b083a fix placing watermarks within source content (#2297)
* fix placing watermarks within source content

* formatting
2025-08-11 16:02:16 +00:00
Jason Dove
1cac210765 fix segmenter v2 transitions (#2296) 2025-08-11 15:00:25 +00:00
Jason Dove
6f9952924b fix adding new schedule items (#2295) 2025-08-11 12:56:24 +00:00
Jason Dove
1bf5b9567b use graphics engine with segmenter v2 (#2294) 2025-08-11 11:56:48 +00:00
Jason Dove
a9f2037648 cleanup some unused watermark references (#2293) 2025-08-11 03:02:57 +00:00
Jason Dove
03c5b7e664 refactor some tests; upgrade dependencies (#2292)
* refactor some tests

* upgrade dependencies

* disable new test
2025-08-11 00:17:01 +00:00
Jason Dove
0e7ec6e3b9 fix qsv transitions when remote streaming (#2291) 2025-08-10 11:47:47 +00:00
Jason Dove
3f247288d3 fix on demand for block and yaml schedules (#2290) 2025-08-10 00:50:59 +00:00
Jason Dove
df0801f2c6 add image graphics element (#2288) 2025-08-09 17:42:23 +00:00
Jason Dove
908125f8a9 allow selecting multiple watermarks on decos (#2287)
* load fonts on demand

* add new table

* populate new table

* edit and use multiple watermarks in deco

* remove old field

* update changelog
2025-08-09 17:00:12 +00:00
Jason Dove
942cf9e225 allow selecting multiple watermarks on schedule items (#2286)
* add and populate new table

* add watermark multiselect

* remove old column

* update changelog

* fix tests
2025-08-09 13:53:37 +00:00
Jason Dove
075f3fcac7 pass music video variables to text element (#2285)
* pass music video variables to text element

* remove unused file
2025-08-09 01:29:20 +00:00
Jason Dove
f4eadae8ff set variables from yaml playout graphics_on instruction (#2284) 2025-08-08 23:02:13 +00:00
Jason Dove
2dc5bf58a7 add graphics_on and graphics_off yaml playout instructions (#2283) 2025-08-08 20:22:07 +00:00
Jason Dove
76a589b538 add text graphics element to playback troubleshooting (#2282)
* refactor graphics engine; async frame generation

* add text graphics element to playback troubleshooting
2025-08-08 19:18:15 +00:00
Jason Dove
9f3db05c17 fix graphics engine on vaapi (#2281) 2025-08-08 14:15:46 +00:00
Jason Dove
7ca2763109 allow multiple watermarks in playback troubleshooting (#2280) 2025-08-08 11:33:12 +00:00
Jason Dove
14539d00d4 add watermark z-index (#2279) 2025-08-08 00:43:00 +00:00
Jason Dove
bd09f3dfdc fix block filler progression (#2278) 2025-08-07 21:18:45 +00:00
Jason Dove
0c22eefad2 fix block playout progression (#2277) 2025-08-07 21:11:49 +00:00
Jason Dove
2f06e5b6f7 add linear fade functions to watermark opacity expression (#2276)
* add linear fade functions to watermark opacity expression

* cleanup
2025-08-07 20:46:16 +00:00
Jason Dove
f9db92d5e6 add content_total_seconds to watermark opacity expression (#2275) 2025-08-07 19:56:56 +00:00
Jason Dove
f2b6f5b919 enable graphics engine in playback troubleshooting (#2274)
* enable graphics engine in playback troubleshooting

* fix text subtitles with graphics engine (watermarks)
2025-08-07 18:37:55 +00:00
Jason Dove
c7fcaf8886 refactor playout building (#2273)
* refactor playout building

* remove playout items
2025-08-07 15:20:26 +00:00
Jason Dove
5a5c049835 support multiple watermarks in yaml schedules (#2267)
* add multiple watermarks per playout item

* fixes

* update yaml playout watermark to support multiple watermarks

* use graphics engine for intermittent watermarks
2025-08-06 21:22:20 +00:00
Jason Dove
a28f40e14b remove debug log 2025-08-06 13:27:33 -05:00
Jason Dove
a2fc99229e add watermark opacity expression (#2266)
* add watermark opacity expression

* implement watermark opacity expression parameters

* minor fixes
2025-08-06 18:26:44 +00:00
Jason Dove
036b6e63c7 add new graphics engine (#2265)
* spike new graphics engine

* fix remote watermarks; add graphics engine to vaapi

* add graphics engine to qsv
2025-08-06 15:04:43 +00:00
Jason Dove
fd7c3fc25a prep for release v25.4.0 [no ci] 2025-08-05 12:08:31 -05:00
Jason Dove
93dca6e0e0 fix framerate check for remote streams (#2264) 2025-08-05 14:35:13 +00:00
Jason Dove
e34368bf07 fix some yaml schema oneOf => anyOf (#2263) 2025-08-05 13:35:26 +00:00
Jason Dove
a4b485f562 add yaml validation tool (#2259)
* reorganize troubleshooting page

* add yaml troubleshooting tool
2025-08-05 03:07:26 +00:00
Jason Dove
6159b6a5b2 support more music video thumbnail filenames (#2258) 2025-08-04 23:17:16 +00:00
Jason Dove
11100a788b fix yaml guid validation (#2257) 2025-08-04 22:22:37 +00:00
Jason Dove
b40ac9ef52 replace channel active mode with is enabled and show in epg (#2256)
* add channel enabled setting

* remove channel active mode
2025-08-04 21:24:26 +00:00
Jason Dove
c055e59723 add channel transcode mode and idle behavior (#2255)
* add channel transcode mode and idle behavior

* allow custom_title on all yaml content instructions
2025-08-04 20:25:31 +00:00
Jason Dove
b52159e8db rename channel progress mode to playout mode (#2254) 2025-08-04 19:27:22 +00:00
Jason Dove
a728c5e31e add smart collection editor to support renaming (#2253) 2025-08-04 16:24:08 +00:00
Jason Dove
61ce1bad08 always schedule full duration (#2252) 2025-08-04 15:31:04 +00:00
Jason Dove
ab2b926de0 add searching log category (#2251) 2025-08-04 14:51:13 +00:00
Jason Dove
3b955255ce fix building yaml playouts with no imports (#2249) 2025-08-04 03:43:30 +00:00
Jason Dove
16dd2c2d81 add yaml import section (#2248) 2025-08-04 02:21:56 +00:00
Chris Simpson
48f93b8af8 Support individual chapters as filler (#2208)
* Use chapters in duration filler

* add new option, migrations, and update filler preset editor

* Revert "Use chapters in duration filler"

This reverts commit d87a8a240a78c1cbca7b311125f8d3a84645d296.

* scaffold splitting filler by chapter

* implement chapters as filler

* update changelog

* re-add migrations

* Add duration for ChapterMediaItem

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2025-08-04 00:18:14 +00:00
Jason Dove
8b12ee459a fix transitions on nvidia, vaapi, qsv (#2247) 2025-08-03 20:26:16 +00:00
Jason Dove
b3d0b44e77 fix qsv transitions (#2246)
* fix qsv transitions

* revert unintended change
2025-08-03 16:01:48 +00:00
Jason Dove
163fd0c1f3 restore noautoscale in nvidia pipeline (#2245) 2025-08-03 14:57:30 +00:00
Jason Dove
b6ec16c6a7 fix transitions using nvidia accel (#2244) 2025-08-03 14:14:36 +00:00
Jason Dove
aa3bd3b750 add yaml playout rewind instruction (#2243) 2025-08-03 13:29:44 +00:00
Jason Dove
f04b7ead09 fix yaml playout builds (#2241) 2025-08-03 01:18:27 +00:00
Jason Dove
8921273900 detect some videotoolbox decoders (#2240) 2025-08-02 18:38:49 +00:00
Jason Dove
0489741123 add videotoolbox capabilities (#2239)
* implement videotoolbox hardware capabilities

* add videotoolbox troubleshooting info

* update changelog
2025-08-02 17:16:24 +00:00
Jason Dove
c3e882085b remove extra windows Resources folder 2025-08-02 10:08:45 -05:00
Jason Dove
3ab9112c15 fix folders in windows artifact 2025-08-02 09:30:17 -05:00
Jason Dove
33b789db67 remove unneeded commands from windows build 2025-08-02 09:17:14 -05:00
Jason Dove
ed5206b855 rework windows artifact builds (#2238) 2025-08-02 14:11:54 +00:00
Jason Dove
baf7aa20d1 build windows artifacts on linux (#2237) 2025-08-02 13:50:54 +00:00
Jason Dove
7bd0de99e1 fix gaps in yaml playouts (#2235)
* dont run multiple dotnet builds in background

* fix gaps in yaml playouts
2025-08-02 03:42:42 +00:00
Jason Dove
96093c8cc8 build artifacts as background processes (#2234) 2025-08-02 03:27:18 +00:00
Jason Dove
8430a3048c fix yaml playout builds after refactor (#2233) 2025-08-02 03:12:37 +00:00
Jason Dove
06d9e59a7a add yaml mid roll instruction (#2232)
* refactor filler expression

* add yaml mid roll instruction

* schedule midroll for yaml count and all instructions

* update changelog
2025-08-02 00:16:50 +00:00
Jason Dove
9c434079d5 add playlist support to filler preset (#2231) 2025-08-01 19:13:18 +00:00
Jason Dove
12c88a006d add yaml post_roll instruction (#2230) 2025-08-01 17:02:36 +00:00
Jason Dove
f0ca358c2b fully validate yaml playouts (#2229) 2025-08-01 16:20:53 +00:00
Jason Dove
093abf7ad8 add yaml playout pre_roll instruction (#2228)
* add yaml playout pre_roll instruction

* add basic yaml validation

* validate all yaml playout content items

* fix yaml to json conversion

* update changelog
2025-08-01 15:20:10 +00:00
Jason Dove
f768093df7 update dependencies (#2226) 2025-07-31 17:09:39 +00:00
Jason Dove
3830db60bf another small update for a new build 2025-07-31 12:00:36 -05:00
Jason Dove
5984b38ce0 small change to get new build 2025-07-30 16:51:26 -05:00
Jason Dove
e0175fc4e5 add light mode (#2223) 2025-07-29 18:48:12 +00:00
Jason Dove
4f104cff5b some fixes for alternate schedules (#2222) 2025-07-29 11:55:34 +00:00
Jason Dove
a2f678fe8e fix adding new items from plex libraries (#2220) 2025-07-28 22:55:53 +00:00
Jason Dove
b3ac0c68a8 fix green padding with 10-bit content on i965 vaapi (#2219) 2025-07-28 21:42:23 +00:00
Jason Dove
605d8a98ab fix adding new items from jellyfin and emby (#2218) 2025-07-28 20:37:34 +00:00
Jason Dove
00f40c2568 fix migrations for new databases (#2217) 2025-07-28 20:18:08 +00:00
Jason Dove
74733a8026 fix duplicate database migration; fix ssa subtitles (#2216) 2025-07-28 19:23:59 +00:00
Jason Dove
1df9104854 add subtitle selection to playback troubleshooting (#2215) 2025-07-28 18:44:49 +00:00
Jason Dove
6c6ccfa94b fix seeking with text subtitles (#2214) 2025-07-28 16:19:20 +00:00
Jason Dove
e9d494c24e add troubleshoot playback to media card overflow menu (#2210) 2025-07-27 13:06:57 +00:00
Jason Dove
deff33c76c fix pad_to_next always running over time (#2207) 2025-07-26 20:22:40 +00:00
Jason Dove
b5d1839d55 always tell ffmpeg to stop transcoding at duration (#2206) 2025-07-26 19:28:43 +00:00
Jason Dove
ab0f431c85 fix app startup with mysql (#2205)
* don't run pragma command on mysql

* add not required pathhash

* make media file path hash required

* update changelog
2025-07-26 17:48:03 +00:00
Jason Dove
9511e6e6a7 prep for release v25.3.1 [no ci] 2025-07-24 22:36:56 -05:00
Jason Dove
7f2b5ba47f fix fallback filler playback (#2202) 2025-07-25 03:26:56 +00:00
Jason Dove
478d19405d remove docker tag suffixes (#2201) 2025-07-25 03:00:26 +00:00
Jason Dove
e363ab00bb prep for release v25.3.0 [no ci] 2025-07-24 20:43:49 -05:00
Jason Dove
dd9a6d5a06 add chapters to search index (#2199) 2025-07-24 21:03:58 +00:00
Jason Dove
fde05a0299 fix docker tag typo 2025-07-24 15:29:12 -05:00
Jason Dove
d3f8163580 use updated ersatztv-ffmpeg base images (#2198) 2025-07-24 20:27:06 +00:00
Jason Dove
07e4ff907f include docker-arm in unified image health check (#2196)
* include docker-arm in unified image health check

* update
2025-07-24 20:20:00 +00:00
Jason Dove
34874ac548 try to fix docker manifest step 2025-07-24 15:03:47 -05:00
Jason Dove
03e4c0207b use multi-platform docker images (#2195) 2025-07-24 19:56:46 +00:00
Jason Dove
b9faf87887 don't use arm64 runner for arm32 builds (#2194) 2025-07-24 03:21:21 +00:00
Jason Dove
2257d26173 fix some issues with live stream playback (#2193) 2025-07-24 01:58:32 +00:00
Jason Dove
8f6d208e31 use arm64 runners for arm builds (#2192)
* use arm64 runners for arm builds

* use matrix for linux builds on prs

* remove unused "kind"
2025-07-23 21:36:20 +00:00
Jason Dove
5ccea53131 fix media file path length for mysql (#2191) 2025-07-23 03:10:13 +00:00
Jason Dove
da6cb09658 fix tonemapping with amd vaapi (#2187)
* fix amd vaapi tonemap

* fixes
2025-07-22 17:35:06 +00:00
Jason Dove
260949893c fix some stream continuity issues (#2186) 2025-07-22 15:56:14 +00:00
Jason Dove
89b495dc90 qsv and pts fixes (#2184)
* try to fix qsv freezing

* update changelog

* fix unit tests
2025-07-21 19:00:07 +00:00
Jason Dove
74d6b32828 change how qsv is initialized on windows (#2183) 2025-07-21 17:23:30 +00:00
Jason Dove
626af6876b add start from beginning option to playback troubleshooting (#2182) 2025-07-21 16:17:16 +00:00
Jason Dove
2a05cc6e32 add remote stream is_live property (#2181) 2025-07-21 13:19:51 +00:00
Jason Dove
7a4c832156 add media card overflow menu (#2180)
* add media card overflow menu

* remove commented code
2025-07-21 11:00:39 +00:00
Jason Dove
011f16da9f fix variant selection for hls remote streams (#2177) 2025-07-20 18:24:04 +00:00
Jason Dove
79496e688b fix video stream selection for remote streams (#2176) 2025-07-20 17:31:21 +00:00
Jason Dove
5c43ae47b1 add basic remote stream library (#2175)
* initial remote stream library support; scanning seems to work ok

* flood schedule remote streams kind of works

* switch remote stream definitions to yaml files

* implement remote stream script playback

* update changelog
2025-07-20 16:10:32 +00:00
Jason Dove
c29788bc3f add movie nfo country to search index (#2173) 2025-07-19 21:56:13 +00:00
Jason Dove
3501e7c8d5 disable multiple mode select when not using playout mode multiple (#2172) 2025-07-19 20:42:05 +00:00
Jason Dove
867c88d8fc add trakt playlist option (#2171)
* add generate playlist option; add system playlists

* fix official lists; sync items to playlist
2025-07-19 16:56:25 +00:00
Jason Dove
70fbd4c746 add option to auto refresh trakt lists (#2169) 2025-07-19 14:19:07 +00:00
Jason Dove
1cbd48cea0 log nfo file name with nfo parsing errors (#2168) 2025-07-19 02:22:06 +00:00
Jason Dove
c953176cee change watermark width and margins to allow decimals (#2167) 2025-07-18 21:28:32 +00:00
Jason Dove
e0cef62969 fix block playout epg time zone (#2166) 2025-07-18 17:14:11 +00:00
Jason Dove
9e56f6552f support more multi-part grouping names (#2165) 2025-07-18 16:48:08 +00:00
Jason Dove
6a84c564d6 add multi-episode group size (#2164) 2025-07-18 14:46:00 +00:00
Jason Dove
54be3761dd add multiple mode to schedule items (#2163) 2025-07-18 14:03:56 +00:00
Jason Dove
cf6b9cf29a enable write-ahead logging on all sqlite databases (#2162) 2025-07-18 11:17:21 +00:00
Jason Dove
464c1e2ea8 fix bugs with playout mode multiple (#2160) 2025-07-18 01:53:19 +00:00
dependabot[bot]
107e8cfded Bump Jint and System.CommandLine (#2152)
Bumps Jint from 4.3.0 to 4.4.0
Bumps System.CommandLine from 2.0.0-beta5.25306.1 to 2.0.0-beta6.25358.103

---
updated-dependencies:
- dependency-name: Jint
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: System.CommandLine
  dependency-version: 2.0.0-beta6.25358.103
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-17 18:23:04 +00:00
Jason Dove
837f824660 include hardware info in troubleshooting archive (#2159)
* add cpu and gpu info to troubleshooting general

* include capabilities in troubleshooting archive
2025-07-17 16:23:57 +00:00
Jason Dove
223bdff8d6 playback troubleshooting improvements (#2157) 2025-07-17 14:53:11 +00:00
Jason Dove
578cdb1e14 add playback troubleshooting tool (#2155)
* support media info for more content types

* add playback troubleshooting page

* reorganize playback troubleshooting

* fix watermarks and delay

* update changelog
2025-07-17 03:51:36 +00:00
Jason Dove
848b88bd2d link ffmpeg health check to ersatztv-ffmpeg release (#2154)
* link ffmpeg health check to ersatztv-ffmpeg release

* bump windows ffmpeg to use the same version as linux
2025-07-16 17:13:25 +00:00
Jason Dove
b85571b159 allow uploading large watermarks (#2151) 2025-07-15 13:51:26 +00:00
Jason Dove
43e1cbd919 yaml playout watermarks (#2149) 2025-07-14 03:25:20 +00:00
Jason Dove
39b107eb0f add matched_points to filler expression (#2148) 2025-07-13 15:14:13 +00:00
Jason Dove
0ee62dbc7d fix recent regression to health check links (#2147) 2025-07-13 13:15:16 +00:00
Jason Dove
833bf3506a rework schedule items editor (#2146) 2025-07-13 00:57:27 +00:00
Jason Dove
cd75046348 rework playlist editor (#2145) 2025-07-12 23:17:47 +00:00
Jason Dove
448d29546c rework block editor (#2143) 2025-07-12 19:47:25 +00:00
Jason Dove
f2c49bd0fd rework alternate schedule and playout template editors (#2142)
* rework alternate schedules editor

* rework playout templates editor
2025-07-12 18:51:44 +00:00
Jason Dove
174c743cb7 more mobile layout updates (#2141)
* update trash layout

* cleanup block and yaml playout editors

* spacing cleanup

* rework multi-collection editor

* rework deco template editor

* rework template editor
2025-07-12 15:50:44 +00:00
Jason Dove
2a9f23cce6 update layout for group editors (#2140)
* update block group editor

* update playlist group editor

* update template group editor

* update deco group editor

* update deco template group editor

* update deco editor

* update logs layout

* update changelog
2025-07-12 13:45:50 +00:00
Jason Dove
451c534062 allow block items to disable watermarks (#2139)
* allow block items to disable watermarks

* fix test
2025-07-12 03:55:18 +00:00
Jason Dove
e16cb30ab1 add mid-roll filler expression (#2138) 2025-07-12 01:23:16 +00:00
Jason Dove
e0df454ac6 more layout updates for mobile (#2137)
* update trakt, filler, filler editor ui

* update schedules and playouts

* update playout editor

* update dependencies

* update yaml playout editor

* update path replacement editor
2025-07-11 21:08:37 +00:00
Jason Dove
e79a03b522 fix displaying local tv artwork in ui (#2136) 2025-07-11 14:44:16 +00:00
Jason Dove
1a09bb26d7 lots of mobile updates including detail pages (#2135)
* update artist page layout

* update season page layout

* rework collection view

* cleanup

* update collection editor
2025-07-11 14:21:39 +00:00
Jason Dove
ffd3e3604c rework many media pages (#2134)
* rework many list pages

* refactor

* rework movie details and season list
2025-07-11 02:47:30 +00:00
Jason Dove
7e40a809ff improve search results ui on mobile (#2133)
* show brief health check messages on mobile

* update libraries layout

* improve search results ui on mobile
2025-07-10 19:19:34 +00:00
Jason Dove
cecf18a7b5 improve mobile layout for some media source pages (#2132) 2025-07-10 17:28:51 +00:00
Jason Dove
7df33425fa improve health check display on mobile (#2131) 2025-07-10 15:23:10 +00:00
Jason Dove
5dfaa1a7ad improve mobile layout for some pages with tables (#2130) 2025-07-10 14:38:17 +00:00
Jason Dove
28a65e74bb use new form layout for local library editor (#2129) 2025-07-10 11:48:20 +00:00
Jason Dove
4a66f0ae43 use new form layout for watermark editor (#2127)
* use new form layout for watermark editor

* cleanup
2025-07-09 21:24:03 +00:00
Jason Dove
fb2466d32d vaapi tonemap fixes (#2125) 2025-07-07 20:58:45 +00:00
Jason Dove
beaaa62ed9 fix nvidia edge case with missing bit depth info (#2123)
* fix nvidia edge case with missing bit depth info

* revert docker-compose changes
2025-07-07 16:31:11 +00:00
Jason Dove
0b445f8cfd cache bust more css (#2119) 2025-07-07 02:50:34 +00:00
Jason Dove
7e30444857 dependencies and code cleanup (#2117)
* fix validation in new form layout

* pin mediatr to last oss version

* update dependencies

* cleanup code in core

* cleanup code in ffmpeg

* cleanup code in infra

* cleanup code in scanner

* cleanup code in application

* cleanup main code

* cleanup test code

* solution-wide code cleanup
2025-07-06 15:56:17 +00:00
Jason Dove
fa6a31b4fc use new form layout for schedule editor (#2116) 2025-07-06 11:32:11 +00:00
Jason Dove
b01ad9dbae restore incorrectly deleted file (#2114) 2025-07-05 17:40:00 +00:00
Jason Dove
d324967afa use new form layout for ffmpeg profile editor (#2113) 2025-07-05 13:07:01 +00:00
Jason Dove
aff4fb0deb use new form layout for channel editor (#2112) 2025-07-05 11:20:53 +00:00
Jason Dove
93afcd2f57 more settings updates (#2111)
* update logging settings layout

* update hdhomerun settings layout

* update scanner settings layout

* update playout settings layout

* update xmltv settings layout

* update changelog
2025-07-05 00:45:32 +00:00
Jason Dove
921a108684 ui updates (#2109)
* split settings into multiple pages

* show health check badge in nav menu

* undo transcoding test changes
2025-07-04 18:20:22 +00:00
Jason Dove
a6fa93d44e fix nvidia compatibility with ffmpeg 7.2+ (#2108)
* tweak random seed

* fix dotnet install in docker test

* fix nvidia compatibility with ffmpeg 7.2+
2025-07-03 15:08:18 +00:00
Jason Dove
a42234a7c3 update plex plot during deep scan (#2105) 2025-07-02 17:14:21 +00:00
Jason Dove
7c5137a4af remove some decode threading limits (#2103) 2025-07-02 00:34:07 +00:00
Jason Dove
5a9d27e196 make yaml playout count an expression (#2102) 2025-07-01 16:24:11 +00:00
Jason Dove
cd4a9c1d16 fix hdhr endpoint classification (#2101) 2025-07-01 15:13:16 +00:00
Jason Dove
f6249d9fa4 channel logo and watermark fixes (#2100)
* channel logo and watermark fixes

* update changelog
2025-07-01 13:40:30 +00:00
Jason Dove
e2ffa70529 support episodedetails and musicvideo as top-level other video nfo tags (#2098) 2025-07-01 02:59:18 +00:00
Jason Dove
3e07bc6136 fix history for playlists in yaml playouts (#2097) 2025-07-01 00:47:53 +00:00
Jason Dove
d6bfc2fd05 marathon playout history fixes (#2096) 2025-06-30 21:39:31 +00:00
Jason Dove
35116c64cd fix potential crash with recent marathon updates (#2095) 2025-06-30 19:23:31 +00:00
Jason Dove
037cee873f yaml marathon history (#2094)
* better playlist tests

* fix history for marathon content in yaml playouts
2025-06-30 19:05:09 +00:00
Jason Dove
cd28afcd91 dont reload appsettings.json at runtime (#2093)
* dont reload appsettings.json at runtime

* also disable here
2025-06-29 17:15:34 +00:00
Jason Dove
7457301d3e yaml playout skip items expression (#2092) 2025-06-29 14:31:56 +00:00
Jason Dove
7b7d378df7 run all mac builds on macos-14 (#2091) 2025-06-29 13:35:57 +00:00
Jason Dove
f6dcaf9108 fix qsv audio sync (#2090) 2025-06-29 03:49:04 +00:00
Jason Dove
6cc2f1de17 yaml playout improvements (#2088)
* add stop_before_end

* more yaml playout improvements
2025-06-28 16:27:58 +00:00
Jason Dove
c6ee41484e allow other videos and images to use the same folders (#2087) 2025-06-28 14:50:33 +00:00
Jason Dove
36d38c740f only scan plex networks on plex show libraries (#2086) 2025-06-28 12:56:49 +00:00
Jason Dove
0f795e4e2f add plex network metadata (#2085)
* initial plumbing

* scan for plex networks

* save network contents to db as tags

* eliminate network tag id churn

* add network and show_network to search index

* update last networks scan

* show networks on tv show page

* update changelog
2025-06-28 12:49:26 +00:00
Jason Dove
583cbf7b14 add channel active mode (#2083) 2025-06-27 21:19:26 +00:00
Jason Dove
27c701b936 fix software tonemap with nvidia (#2082) 2025-06-27 20:47:09 +00:00
Jason Dove
6e2c19d354 process missing language as und (#2081) 2025-06-27 14:45:30 +00:00
Jason Dove
4d83dc019c don't return stream selection when subtitles don't match (#2080) 2025-06-27 14:25:07 +00:00
Jason Dove
462057a4b1 prioritize stream selection by language (#2079) 2025-06-27 13:31:50 +00:00
Jason Dove
a04c72788f fix arm64 docker build (#2078) 2025-06-27 11:48:21 +00:00
Jason Dove
f94a440b62 stream selector improvements (#2077)
* add tests for audio blocklist and audio allowlist

* add subtitle allow list and block list

* add subtitle condition

* add audio condition

* cache bust mudblazor css
2025-06-27 11:40:06 +00:00
Jason Dove
f80069bb97 add custom channel stream selector system (#2076)
* add some basic channel stream selector models

* change windows ffmpeg url

* implement basic stream selection

* fixes
2025-06-27 03:00:59 +00:00
Jason Dove
c2769a08b4 stop building hwaccel-specific images (#2075)
* stop building hwaccel images

* update changelog
2025-06-26 17:26:11 +00:00
Jason Dove
e679fee940 update CHANGELOG for clarity [no ci] 2025-06-24 19:11:04 -05:00
Jason Dove
2271d5497b prep for release v25.2.0 [no ci] 2025-06-24 12:03:56 -05:00
Jason Dove
f71b6527c0 allow external channel logo urls (#2067) 2025-06-24 00:43:24 +00:00
Jason Dove
20d2fe71cd update macos app (#2066) 2025-06-23 21:19:42 +00:00
Jason Dove
1994f171d5 update windows launcher to respect ETV_UI_PORT (#2065) 2025-06-23 20:15:03 +00:00
Jason Dove
76f7c88375 add etv env vars to troubleshooting > general info (#2064) 2025-06-23 14:54:06 +00:00
Jason Dove
3805b9e48c update dependencies that require api migrations (#2063)
* migrate system.commandline to 2.0.0-beta5 api

* bump sixlabors.imagesharp

* migrate skiasharp to 3.x api
2025-06-23 13:49:24 +00:00
Jason Dove
9267edbcc9 fix scanning libraries (#2062) 2025-06-23 13:09:14 +00:00
Jason Dove
c4c164df6a detect cycles in yaml sequence definitions (#2060) 2025-06-23 02:55:35 +00:00
Jason Dove
b90463e3af detect cycles in smart collection queries (#2059) 2025-06-23 01:45:17 +00:00
Jason Dove
1fb27e3cfa fix nuget issues with transitive dependencies (#2058)
* try to fix nuget issues

* another attempt at surfacing warnings

* restore proper runtime

* remove old an unneeded dependencies

* upgrade transitive dep

* use newer dotnet in github
2025-06-22 20:22:37 +00:00
Jason Dove
06f233e5bd upgrade to dotnet 9 (#2056) 2025-06-22 19:04:39 +00:00
Jason Dove
9917774671 allow searching by smart collection (#2055) 2025-06-22 15:43:12 +00:00
Jason Dove
5be929da18 add collection (name) to search index (#2054) 2025-06-22 14:51:17 +00:00
Jason Dove
25f4fb22e5 yaml sequence improvements (#2053) 2025-06-21 19:28:41 +00:00
Jason Dove
b04b517f7b add dockerfile to run transcoding test suite (#2052) 2025-06-21 18:08:23 +00:00
Jason Dove
d756c0c7c0 properly filter vaapi driver health check to vaapi ffmpeg profile (#2050) 2025-06-21 11:36:02 +00:00
Jason Dove
20e5b8a11a add button to clone schedule item (#2048) 2025-06-20 21:52:45 +00:00
Jason Dove
5c8489cbed improve vaapi driver health check (#2047)
* improve vaapi driver health check

* fix duplicate check

* cleanup again
2025-06-20 19:16:52 +00:00
Jason Dove
7cfa298c72 fix xmltv grouping with post-roll filler (#2046) 2025-06-20 14:53:04 +00:00
Jason Dove
4b0faf4da1 unify hardware acceleration in docker (#2045) 2025-06-20 02:52:05 +00:00
Jason Dove
07cbf9936b fix shuffle in order and fill with group mode incompatibility (#2044) 2025-06-19 22:10:30 +00:00
Jason Dove
2138d6437c use noautoscale when also using hwaccel cuda (#2043) 2025-06-18 17:06:19 +00:00
Jason Dove
5b9601a57b maintain cuda pixel format throughout nvidia pipeline (#2042) 2025-06-18 02:59:10 +00:00
Jason Dove
aeda5050d3 nvidia decoder fixes (#2041)
* replace FluentAssertions with Shouldly

* fix song transcoding tests

* only specify hwaccel when hardware decode is required

* update changelog
2025-06-17 18:26:49 +00:00
Jason Dove
ea46a7a5ca add tonemap algorithm setting to ffmpeg profile (#2039) 2025-06-15 00:38:37 +00:00
Jason Dove
69a1e718df use ffmpeg 7.1.1 for nvidia docker (#2038) 2025-06-14 23:20:22 +00:00
Jason Dove
4a59dafe51 optimize tonemapping performance (#2037)
* add env var to disable vulkan

* tonemap after scaling

* vulkan tonemapping still needs to happen before scaling
2025-06-14 21:32:38 +00:00
Jason Dove
6b90da8982 add pad_vaapi filter (#2036) 2025-06-14 13:36:24 +00:00
Jason Dove
1184dc565c use ffmpeg 7.1.1 for base, arm, arm64 docker (#2035)
* use ffmpeg 7.1.1 for base, arm, arm64 docker

* keep newline
2025-06-14 11:16:30 +00:00
Jason Dove
d82ccf8fb5 use hardware-accelerated tonemapping with qsv (#2034)
* add tonemap for qsv

* update changelog
2025-06-14 01:19:35 +00:00
Jason Dove
4d83cc705f use ffmpeg 7.1.1 for vaapi docker (#2033) 2025-06-14 00:34:17 +00:00
Jason Dove
f80addacba use the clip algorithm for software tonemapping (#2032) 2025-06-13 20:12:31 +00:00
Jason Dove
18c2a816dc use ffmpeg 7.1.1 on windows (#2031) 2025-06-13 13:36:19 +00:00
Jason Dove
4f085c1950 fix detecting nvidia capabilities on blackwell gpus (#2030) 2025-06-13 03:14:22 +00:00
Jason Dove
dad0662fa6 use libplacebo to tonemap with nvidia/vulkan (#2029) 2025-06-12 20:49:06 +00:00
Jason Dove
dfdfa6f349 use hardware-accelerated tonemapping with vaapi (#2028)
* add tonemap_vaapi filter

* let vaapi pipeline handle hdr content

* use tonemap_opencl with vaapi

* update changelog
2025-06-12 16:13:43 +00:00
Jason Dove
5fe3e97b31 add software tonemap filter to support hdr content (#2027) 2025-06-12 14:47:59 +00:00
Jason Dove
da1cfab5f4 remove jellyfin admin user id requirement (#2025) 2025-06-09 13:33:47 +00:00
Jason Dove
6d152e4b4a use more accurate BANDWIDTH value in multi-variant playlist (#2023) 2025-06-07 20:45:07 +00:00
Jason Dove
2ca722523b improvements to plex connection management (#2020) 2025-05-31 18:44:55 +00:00
Jason Dove
d9a3496bf5 add fixed start time behavior option to schedules and schedule items (#2017) 2025-05-30 09:30:09 +00:00
Jason Dove
c8f5b51d93 use cache busting to avoid ui errors after upgrading mudblazor (#2016) 2025-05-30 00:22:49 +00:00
Jason Dove
956734ce39 globalization fixes (#2014)
* fix crashes caused by decimal separator

* improvements to playout reset ui

* remove code quality workflow
2025-05-26 16:32:25 +00:00
Jason Dove
e44a391f00 fix navigation when using ETV_BASE_URL (#2013) 2025-05-25 15:29:36 +00:00
Jason Dove
b43b66dd35 start to make ui minimally responsive (#2004) 2025-04-28 21:39:48 +00:00
Jason Dove
140a663da4 update dependencies (#2003)
* update dependencies

* more dependency updates
2025-04-28 17:20:45 +00:00
Jason Dove
876d79c11c update changelog [no ci] 2025-04-22 15:34:28 -05:00
Jason Dove
57a4480c3f try to push docker images to ghcr.io (#2000) 2025-04-22 20:24:14 +00:00
Jason Dove
8f1b57eb88 another attempt at fixing separate ports behind reverse proxy (#1994) 2025-04-14 18:53:25 +00:00
Jason Dove
70472ac84e add public port env vars; allow streaming through ui port (#1993) 2025-04-14 18:21:05 +00:00
Jason Dove
6aab8f53b8 fix changelog [no ci] 2025-04-14 11:57:01 -05:00
Jason Dove
b30b458574 allow ui and streaming to run on different ports (#1992)
* allow ui and streaming to run on different ports

* revert global.json change
2025-04-14 16:48:19 +00:00
Jason Dove
6fe6382485 add remote ip and user agent to http request logging (#1990) 2025-04-07 18:57:08 +00:00
Jason Dove
100ae0adda add api endpoint to empty trash (#1988) 2025-04-06 14:26:40 +00:00
Jason Dove
f0d5200843 bump image sharp lib to fix build (#1986) 2025-04-04 02:48:12 +00:00
Jason Dove
af36218cc2 add linux-musl-x64 artifact (#1985) 2025-04-04 02:45:09 +00:00
Jason Dove
eca62e8bec fix error synchronizing collections from plex server that has zero collections (#1964) 2025-01-15 21:42:22 -06:00
Jason Dove
03d4ab8c72 no longer mark releases as pre-release [no ci] 2025-01-10 12:26:53 -06:00
Jason Dove
57b590cd0f prep for release v25.1.0 [no ci] 2025-01-10 12:12:39 -06:00
Jason Dove
f0a5d89f73 fix song progress with 4:3 resolutions (#1961) 2024-12-27 16:09:58 -06:00
Jason Dove
17a77694a0 add tag_full field to search index (#1956) 2024-12-09 13:55:47 -06:00
Jason Dove
838c2a1661 fix default song background for 4:3 resolutions (#1951)
* fix default song background for 4:3 resolutions

* use 16:9 progress overlay for now
2024-11-28 08:56:38 -06:00
Jason Dove
375a306edc fix vaapi capabilities detection when display is not drm (#1949)
* fix vainfo device syntax

* update logging

* don't pass vaapi_device when display is not drm

* fix hw accel

* proper accel fix

* Revert "proper accel fix"

This reverts commit 5dbadb1f79.

* Revert "fix hw accel"

This reverts commit b6b132d7b9.

* Revert "don't pass vaapi_device when display is not drm"

This reverts commit 0459210718.

* still show vaapi device
2024-11-25 14:27:21 -06:00
Jason Dove
759052c725 add vaapi display option to ffmpeg profile (#1948)
* add vaapi display option

* fix vaapi capabilities cache key

* update logging
2024-11-25 13:14:21 -06:00
Jason Dove
dc112f0c7d add default song album art; adjust default blurhashes (#1946)
* fix song progress on white backgrounds

* remove yellow from default song backgrounds

* add default album art for generated song images

* update changelog
2024-11-20 22:27:09 -06:00
Jason Dove
c8ec87b01f add optional progress bar to generated song videos (#1945)
* optionally include progress bar in generated song video

* update progress bar size/location

* move everything up 10% when song progress is enabled

* add watermark border to song progress bar

* always show accurate progress bar

* lower progress bar to 90% alpha

* update changelog
2024-11-20 15:57:00 -06:00
Jason Dove
fbb7a661fb fix guide group generation for duration yaml instruction (#1943) 2024-11-19 06:26:19 -06:00
Jason Dove
37ceac5651 add advance option to epg_group yaml playout instruction (#1942) 2024-11-18 22:07:21 -06:00
Jason Dove
0953e258a5 add rewind_on_reset option wait_until yaml playout instruction (#1941) 2024-11-18 19:31:51 -06:00
Jason Dove
fdbd8a07b6 update macos runner to macos-13; macos-12 is no longer supported (#1940) 2024-11-18 09:59:37 -06:00
Jason Dove
5465c45a51 fix plex collection sync (#1939) 2024-11-18 09:41:52 -06:00
Jason Dove
a0bef3568b fix selecting audio stream with preferred title (#1937)
* update dependencies to fix build errors

* fix selecting audio stream with preferred title
2024-11-16 19:28:30 -06:00
Jason Dove
f75bb25a1a fix building playouts with certain playlist changes (#1935)
* fix building playouts with certain playlist changes

* update changelog
2024-11-13 14:38:07 -06:00
Jason Dove
e4ff825ae8 fix displaying playout item durations that are greater than 24 hours (#1932)
* fix displaying playout item durations that are greater than 24 hours

* upgrade refit to make build happy

* upgrade all dependencies
2024-11-08 10:11:57 -06:00
Jason Dove
6c4f63ad91 fix scaling behavior crop (#1928) 2024-10-26 08:38:44 -05:00
Jason Dove
c0a14ba81c add button to reset all playouts (#1927) 2024-10-24 11:23:47 -05:00
Jason Dove
c063720169 use new channel identifiers in M3U and XMLTV to disambiguate in Plex (#1920) 2024-10-16 09:37:33 -05:00
Jason Dove
5d0f40978d fix deleting local libraries with mysql (#1919) 2024-10-16 08:46:45 -05:00
Jason Dove
063f463951 update dependencies (#1918) 2024-10-16 08:40:03 -05:00
Jason Dove
e7817b1460 fix deco default filler hardware acceleration (#1916)
* fix hw accel for deco default filler

* use custom filler kind for deco default filler
2024-10-11 14:33:30 -05:00
Jason Dove
7d6faee27b properly destroy channel preview (#1910) 2024-10-04 12:29:40 -05:00
Jason Dove
7bba422880 fix emptying trash (#1905) 2024-09-25 10:27:34 -05:00
Jason Dove
db6ae27384 fix mysql database cleaner (#1902) 2024-09-20 08:42:52 -05:00
Jason Dove
4b9fc5004f update changelog for release v0.8.8-beta [no ci] 2024-09-19 11:15:41 -05:00
embolon
f40eaef898 [scheduling] Add a new mode RandomRotation that randomly picks an item from a randomly choosen group (show/artist) for block schedule (#1885)
* init

* minor naming change

* address to comments round 1

* update dependencies

* formatting

* make sure it rotates

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2024-09-10 13:36:20 -05:00
embolon
91e85cc9c1 [Filler] Add random count for filler preset (#1886)
* init

* minor update

* clean up

* minor cleanup

* update changelog

* update changelog again

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2024-09-03 10:25:20 -05:00
Jason Dove
2c44efb971 update dependencies (#1891) 2024-09-03 10:09:37 -05:00
Jason Dove
c2b7be66af restart hls session in some cases (#1880) 2024-08-23 12:59:48 -05:00
Jason Dove
8b911332a6 fix watermark opacity for transparent watermarks (#1877) 2024-08-22 11:35:44 -05:00
Jason Dove
4130f7316c fix block playout history loading (#1876) 2024-08-22 09:05:21 -05:00
Jason Dove
3f6eb5a121 fix some collection related bugs with images (#1874) 2024-08-21 10:36:42 -05:00
Jason Dove
1209c54eb9 prevent saving overlapping blocks (#1872) 2024-08-15 10:37:57 -05:00
Jason Dove
94db4bf679 fix local subtitle scans for non-lowercase extensions (#1865)
* fix local subtitle scans for non-lowercase extensions

* remove some unneeded changes
2024-08-07 20:47:27 -05:00
Jason Dove
2977590a14 add deco setting to use watermarks during filler (#1861) 2024-08-05 13:40:24 -05:00
Jason Dove
b4c168e85e use trakt user slug for proper url generation (#1859) 2024-08-05 09:41:24 -05:00
Jason Dove
55b7a35689 fix missing movie metadata (#1854) 2024-08-03 08:05:50 -05:00
Jason Dove
a24592a8c4 add database cleaner (#1853)
* fix broken tests

* add database cleaner
2024-08-02 10:46:52 -05:00
Jason Dove
9b60ff0863 optionally shuffle marathon groups (#1850) 2024-07-31 17:33:08 -05:00
Jason Dove
efdf0bb6d4 group music videos by album (#1849) 2024-07-31 16:13:13 -05:00
Sylvain
39ca27cb3d Overlay Generated Channel Logo when active but no artwork is found (#1848) 2024-07-31 10:04:42 -05:00
Jason Dove
9e2f7b7815 fix deco selection for watermark and filler (#1847) 2024-07-30 21:57:21 -05:00
Jason Dove
101d46e283 dont remove block items that are filler (#1846) 2024-07-30 20:38:13 -05:00
Jason Dove
521e4eac41 add yaml marathon search content source (#1845)
* use search queries to populate marathons

* group marathon by artist

* add marathon group by album
2024-07-30 20:30:13 -05:00
Jason Dove
894fc284b2 fix deco template name display (#1844)
* fix deco template name display

* try to fix mac build
2024-07-30 19:45:25 -05:00
Jason Dove
a8cf22e43e group marathon by season (#1843) 2024-07-30 19:24:56 -05:00
Jason Dove
4c9c047530 add basic marathon content (#1842) 2024-07-30 18:21:24 -05:00
Jason Dove
912f79097d add collection, smart collection, multi collection, playlist content sources to yaml playouts (#1841)
* add collection content to yaml playout

* add smart_collection content

* add multi_collection content

* add playlist content
2024-07-30 10:46:08 -05:00
Jason Dove
8aa55fdfce replace new_epg_group instruction with epg_group; copy sequence custom title to sequence items 2024-07-30 08:36:14 -05:00
Jason Dove
8dc1cab222 fix media card selection (#1840) 2024-07-30 06:21:38 -05:00
Jason Dove
961fe8bbf2 improve shuffling behavior; add custom_title (#1838)
* improve yaml shuffling behavior

* add custom_title to playout instructions
2024-07-29 19:53:06 -05:00
Jason Dove
75f991d670 yaml history fix (#1836) 2024-07-29 16:21:51 -05:00
Jason Dove
e3c981004b show all items in epg by default (#1835) 2024-07-29 15:48:20 -05:00
Jason Dove
befaa037e2 default duration to make a new epg group per item; default duration to NOT use offline tail (#1834) 2024-07-29 15:26:13 -05:00
Jason Dove
5e0fb31069 add reset playout and scan library api endpoints (#1833)
* add api to reset playout

* add library scan api

* update changelog
2024-07-29 13:50:33 -05:00
Jason Dove
7d83e66ba6 add yaml playout history; allow yaml playouts to be extended (#1832)
* add multi_part; refactor skipping items

* save and apply history for yaml playouts

* do not remove history on yaml playout reset
2024-07-29 13:09:14 -05:00
Jason Dove
391528cd94 add pad_until instruction (#1831)
* revert dotnet workaround

* add pad_until instruction
2024-07-29 06:36:14 -05:00
Jason Dove
b737775f9a add yaml skip to item instruction (#1830)
* work around MSB3374 error

* add skip to item instruction
2024-07-28 22:12:54 -05:00
Jason Dove
728c5130b5 try without quotes 2024-07-28 17:34:25 -05:00
Jason Dove
e4253276e0 let's try completely separate folders 2024-07-28 16:49:07 -05:00
Jason Dove
1fc55bc693 try to fix build again 2024-07-28 16:44:38 -05:00
Jason Dove
4ad22e402f use global.json dotnet version in workflows (#1829)
* use global.json dotnet version in workflows

* list output files

* work around weird folder emptying behavior on windows
2024-07-28 16:39:19 -05:00
Jason Dove
ec99d5976d add shuffle sequence instruction (#1827) 2024-07-28 13:51:26 -05:00
Jason Dove
59f11f1a1a add yaml playout sequences (#1826) 2024-07-28 13:22:01 -05:00
Jason Dove
694f25f8b3 upgrade to mudblazor 7 (#1825) 2024-07-28 11:31:04 -05:00
Jason Dove
5947555e86 improve trakt list url validation (#1824)
* improve trakt url validation and logging

* update changelog
2024-07-28 09:24:54 -05:00
Jason Dove
fb63116b36 more subtitles fixes (#1823) 2024-07-27 22:20:44 -05:00
Jason Dove
56a58d7a84 fix missing audio and subtitle language codes (#1822) 2024-07-27 20:44:49 -05:00
Jason Dove
6f66909957 add "all" instruction (#1821)
* add "all" instruction

* use string for value we don't care about
2024-07-27 14:26:33 -05:00
Sylvain
01090f62e6 Fixing URL Encoding for logo generation (#1818) 2024-07-27 10:37:37 -05:00
Jason Dove
e4e4f68eb4 refactor yaml playout builder (#1820)
* update changelog

* refactor some handlers

* refactor skip items instruction

* more refactoring
2024-07-27 10:33:21 -05:00
Sylvain
8488fe5d3d Used a UUID in HDHomeRun config to allow multiple instances on a same network (#1810)
* Used a UUID in HDHomeRun config to allow multiple instances on a same network

* tweak some async calls

* try to fix line endings

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2024-07-27 08:51:45 -05:00
Jason Dove
f06ef5262a add new_epg_group instruction; add filler_kind propery (#1819) 2024-07-27 08:38:00 -05:00
Jason Dove
ae6bcc4933 add yaml playout skip items instruction (#1816) 2024-07-26 20:37:02 -05:00
Jason Dove
b83fe53ef1 add wait until instruction (#1815) 2024-07-26 19:52:43 -05:00
Jason Dove
d50f2ace07 fix regression selecting subtitle streams for certain languages (#1814) 2024-07-26 17:44:17 -05:00
Sylvain
23684f607a Generating Channel Logo when no logo is provided (#1807)
* Generating Channel Logo when none is provided

* Moved TTF in the cached Resources folder

* Using WebUtility.UrlEncode instead of Raw String Replace

* Fixed mistyping

* Moved Channel Logo Generator to etv.core

* Return 301 to static logo if there is any error during Logo generation

* minor fixes

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2024-07-26 15:13:00 -05:00
Jason Dove
fa20c5e01e template playout => yaml playout (#1813) 2024-07-26 14:33:55 -05:00
Jason Dove
53bd745678 add playout template show content (#1812) 2024-07-26 13:10:27 -05:00
Jason Dove
f3e5a4e7d8 add playout template duration scheduler (#1811)
* fix loop with missing content

* implement template duration scheduler
2024-07-26 12:03:46 -05:00
Jason Dove
0b29bb32b1 playout template pad to next fixes (#1809)
* prevent loop

* add discard attempts and fallback to pad_to_next
2024-07-26 10:23:38 -05:00
Jason Dove
d9a7615cf6 add experimental playout template system (#1808)
* add template playout kind

* add template scheduler count

* implement pad to next

* only allow resetting template playouts

* update changelog
2024-07-26 08:34:18 -05:00
Jason Dove
50f2cb7a33 fix adding pad filler to short content (#1806) 2024-07-25 19:14:16 -05:00
Jason Dove
b1b2c2a1e0 add deco default filler trim to fit setting (#1800)
* add deco default filler trim to fit setting

* implement trim to fit

* update changelog
2024-07-22 14:14:02 -05:00
Jason Dove
d842cd57f6 fix building block playouts without default filler (#1799) 2024-07-22 09:05:31 -05:00
Jason Dove
4f393d7b06 fix two letter language code stream selection (#1798) 2024-07-22 06:54:08 -05:00
Jason Dove
46f7289db8 add deco default filler (#1797)
* first pass at default filler for block scheduling

* configure default filler in ui

* update changelog
2024-07-19 13:29:42 -05:00
Jason Dove
80ccbbf299 fix duration playout loop (#1796) 2024-07-18 12:18:49 -05:00
Jason Dove
3765894cb7 remove invalid values from filler preset editor (#1793) 2024-07-17 16:51:39 -05:00
Jason Dove
a8b658a5ea add "on demand" channel progress mode (#1790)
* update dependencies

* add channel progress mode

* implement on demand channel progress

* update changelog
2024-07-16 12:21:52 -05:00
Sylvain
0e3c32bd83 Adding more HEAD handling (https://github.com/ErsatzTV/ErsatzTV/pull/1786) (#1787) 2024-07-13 06:28:28 -05:00
Jason Dove
9dd4a85bf9 fix adding items to empty playlists (#1784) 2024-07-11 12:17:41 -05:00
Sylvain
a0a047ba18 Added API Artwork Router (#1776)
* Added API Artwork Router

* Simplifying code
2024-07-08 15:15:14 -05:00
Sylvain
687a4f4f10 Alow HEAD requests on /iptv/channels.m3u (#1779) 2024-07-08 13:10:36 -05:00
Sylvain
b91ab5d898 Fixing Artwork OtherVideo rel (#1774)
* Fixing Artwork OtherVideo rel

* show other video artwork in ui

* don't run code quality on PRs

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2024-07-05 09:16:09 -05:00
Jason Dove
256042947d use macos-12 runners for github actions (#1773) 2024-07-05 06:39:09 -05:00
Sylvain
85029cbbcd Escaping & on xmltv file (#1772) 2024-07-05 05:56:14 -05:00
Jason Dove
b5d679212d cache bust xmltv images (#1771) 2024-07-03 12:14:40 -05:00
Sylvain
36e86587ef Allow Other Videos Library Type on Plex to be sync (#1766)
* Allow Other Videos Library Type on Plex to be sync

* Migrating database: Creating PlexOtherVideo table

* Using Plex Media path to create tags for OtherVideos

* missed these in the merge

* Getting PlexLibrary for Tag set on OtherVideo

* fix migrations

* set tag metadata on plex other videos

* update changelog

---------

Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
2024-07-02 15:41:09 -05:00
Jason Dove
f41fa669be update media server scanning and paging (#1770)
* update media server scanning and paging

* remove unused types
2024-07-02 13:12:09 -05:00
Jason Dove
f62e841af4 update changelog for release v0.8.7-beta [no ci] 2024-06-26 22:11:36 -05:00
Jason Dove
109960c457 fix some more search queries (#1763) 2024-06-26 22:08:59 -05:00
Jason Dove
6858103be5 fix transcoding 10-bit source content using qsv on windows (#1762) 2024-06-26 16:21:42 -05:00
Jason Dove
f7f1a0493b update macos submodule again 2024-06-25 10:43:31 -05:00
Jason Dove
6c18648fd7 update macos submodule (#1760) 2024-06-25 10:31:37 -05:00
Jason Dove
ab3afcfad0 use ffmpeg 6.1 everywhere instead of ffmpeg 7 (#1754) 2024-06-21 12:30:07 -05:00
Jason Dove
5734356d29 fix template and deco template editors with mysql (#1750) 2024-06-17 15:36:14 -05:00
Jason Dove
beee038be3 fix video_bit_depth search field for plex media (#1745) 2024-06-10 15:46:23 -05:00
Jason Dove
a5c8e2b401 fix duration scheduling bug (#1744) 2024-06-10 12:30:56 -05:00
Jason Dove
c8113bdf25 fix vaapi decoder capability check (#1740)
* fix decoder video profile check

* clarify changelog
2024-06-04 06:10:02 -05:00
Jason Dove
9466cf7626 update vaapi docker bundled ffmpeg (#1729) 2024-05-25 12:13:05 -05:00
Jason Dove
43fcf9e63a upgrade to ffmpeg 7 on windows (#1727) 2024-05-24 11:31:28 -05:00
Jason Dove
242a7ae382 add b-frames option to ffmpeg profile (#1726)
* add b-frames option to ffmpeg profile

* update dependencies

* cleanup
2024-05-24 08:50:11 -05:00
Jason Dove
6dc526a817 fix dotnet in vaapi docker (#1724) 2024-05-23 07:38:01 -05:00
Jason Dove
182c02b865 use ffmpeg 7 with vaapi again (#1723) 2024-05-22 20:09:38 -05:00
Jason Dove
7c1f0d6dbd treat mid-roll as post-roll when chapter markers are missing (#1722) 2024-05-21 15:51:35 -05:00
Jason Dove
2c97c49763 custom config folders env vars (#1714)
* use custom config folder location

* allow customizing config and transcode folder locations
2024-05-10 09:28:58 -05:00
Jason Dove
f5038c2b66 play all items in playlist before starting again (#1711) 2024-05-07 17:05:12 -05:00
Jason Dove
85eb7623da fix playlist playouts (#1709)
* fix playlist playouts

* remove some logging
2024-05-06 20:40:10 -05:00
Jason Dove
a87ec2d75d cleanup (#1708)
* fix blazor naming

* code cleanup

* update dependencies
2024-05-06 17:00:52 -05:00
Jason Dove
ef6c8b0816 allow clearing (omitting) video profile setting (#1706) 2024-05-05 19:23:26 -05:00
Jason Dove
dc3578660f fix flood playout item watermark (#1705) 2024-05-05 09:08:08 -05:00
Jason Dove
ce958bb7bb enable video profile editing for qsv (#1704) 2024-05-05 08:53:34 -05:00
Jason Dove
33a8b29a27 fix block playout random seeds (#1703) 2024-05-04 09:09:04 -05:00
Jason Dove
48a504735c fix xmltv generation when no block items are selected for guide (#1702) 2024-05-03 09:18:06 -05:00
Jason Dove
0b64e97df6 fix media card (#1701) 2024-05-02 16:38:20 -05:00
Jason Dove
5d89f5d0a4 fix template editors (#1700) 2024-05-02 12:59:13 -05:00
Jason Dove
50a6ed4cea fix docker again 2024-05-02 10:31:01 -05:00
Jason Dove
66b8c8aa0e fix docker builds (#1699) 2024-05-02 10:23:07 -05:00
Jason Dove
398a3c041a detect /dev/dri/card* devices (#1698)
* remove unused nupkg

* cleanup obsolete properties

* detect /dev/dri/card devices
2024-05-02 10:17:38 -05:00
Jason Dove
6ce7265427 add qodana workflow (#1697) 2024-05-02 08:34:17 -05:00
Jason Dove
b4fe38d4ae segmenter v2 fixes (#1696) 2024-05-01 12:53:56 -05:00
Jason Dove
e19b639527 add playlist item play all option (#1694) 2024-04-28 13:00:22 -05:00
Jason Dove
a6d5df3ca6 more add to playlist buttons; fix playlist preview (#1693) 2024-04-28 08:59:14 -05:00
Jason Dove
202ae33e37 add individual media items to playlists (#1692)
* add movies to playlists

* add search results to playlist

* update changelog
2024-04-28 06:33:57 -05:00
Jason Dove
c46b3787d8 set guide mode filler as appropriate on playlist items (#1691) 2024-04-27 20:31:03 -05:00
Jason Dove
706a2d14a2 add playlists (#1690)
* update dependencies

* add playlists

* add playlist support to schedules

* playout builder (flood) supports playlists

* update changelog
2024-04-27 19:58:40 -05:00
Jason Dove
11f99216a3 fix plex library scans with mysql/mariadb (#1689) 2024-04-24 13:16:53 -05:00
Jason Dove
b9a7ad2f5a add video presets for nvenc, qsv, software h264 and hevc encoders (#1688)
* add video preset to ffmpeg profile

* add some hevc video presets
2024-04-23 14:26:30 -05:00
Jason Dove
07e7e5fe66 fix block playout playback when no deco is configured (#1687) 2024-04-23 13:10:11 -05:00
Jason Dove
4a19d046e4 fix mysql db migrations 2024-04-22 22:40:53 -05:00
Jason Dove
c1d6ddcc57 add h264 profile option to ffmpeg profile (#1686)
* add video profile for nvenc/software h264 encoders

* add h264 profile for all other encoders

* update changelog
2024-04-22 22:03:18 -05:00
Jason Dove
35eb200aee more segmenter v2 improvements (#1685)
* more segmenter v2 improvements

* changelog updates
2024-04-21 19:17:06 -05:00
Jason Dove
19af303d76 improve segmenter v2 hevc compliance with fmp4 (#1684) 2024-04-21 10:01:11 -05:00
Jason Dove
da20393a39 allow m3u8 playlist head requests (#1683) 2024-04-21 08:18:05 -05:00
Jason Dove
d78110f6f1 fix macos config folder regression (#1682)
* migrate macos config folder on startup, if needed

* add macos config folder health check

* update macos fix; update changelog
2024-04-17 09:18:09 -05:00
Jason Dove
c1bedb661c rever vaapi docker to ffmpeg 6.1 (#1681) 2024-04-16 22:27:26 -05:00
Jason Dove
d31d6f20cf upgrade to ffmpeg 7 in all docker images (#1680)
* upgrade nvidia docker to ffmpeg 7

* upgrade all docker images to ffmpeg 7

* update changelog
2024-04-16 18:24:40 -05:00
Jason Dove
7469559bb3 fix external subtitle detection (#1679) 2024-04-15 12:31:06 -05:00
Jason Dove
af5dc0968b add xmltv days to build setting (#1678) 2024-04-12 09:44:08 -05:00
Jason Dove
6e7880386b update plex show title (#1677)
* update plex show title when changed in plex

* fix test build
2024-04-12 09:21:11 -05:00
Jason Dove
8945a87f9b fix segmenter semaphore (#1676)
* disable dead air watermarks by default

* fix session worker semaphore

* update changelog
2024-04-11 19:38:57 -05:00
Jason Dove
e305222141 add dead air fallback to deco system (#1668)
* add dead air fallback to deco editor

* fix deco watermark logic

* use dead air fallback from decos
2024-04-05 23:11:14 -05:00
Jason Dove
2e2523c380 another wildcard search fix (#1667) 2024-04-05 09:12:46 -05:00
Jason Dove
b461631be9 properly update plex part keys (#1666) 2024-04-04 22:40:21 -05:00
Jason Dove
19fc068a73 add deco system (#1665)
* add deco groups and decos; set default deco for block playout

* use block playout default deco for watermark

* add deco templates, groups and deco template editor

* associate deco template with playout template

* use deco template item watermark for playback

* update changelog for decos
2024-04-04 14:38:56 -05:00
Jason Dove
e5f15df196 rework active date range; add tests (#1664) 2024-04-03 13:43:20 -05:00
Jason Dove
6ac2384cbc add active date range to block playout templates editor (#1663)
* update dependencies

* add active date range to block playout templates editor
2024-04-03 10:50:43 -05:00
Jason Dove
cd6673da82 update changelog for v0.8.6-beta [no ci] 2024-04-03 05:04:35 -05:00
Jason Dove
8113827802 allow block durations with 5-minute increments (#1662) 2024-04-02 10:27:27 -05:00
Jason Dove
4e56117e0e use jwt for mpeg-ts streaming mode (#1661) 2024-03-29 21:36:49 -05:00
Jason Dove
7702999b9a properly restore all local library items from trash during scans (#1660) 2024-03-29 20:03:19 -05:00
Jason Dove
14a707a4e2 improve plex item change detection (#1659) 2024-03-29 15:15:42 -05:00
Jason Dove
340ab61a26 add more logging to other video library scans (#1658) 2024-03-29 14:02:12 -05:00
Jason Dove
d91d991251 always interpret asterisk as wildcard search (#1657) 2024-03-29 13:27:18 -05:00
Jason Dove
3ce341eee5 fix build error for single file artifacts (#1656) 2024-03-29 12:21:58 -05:00
Jason Dove
476fe991b6 other video library scanner improvements (#1655)
* improve scanner detection when developing on macos

* support ogv files in local libraries

* improve health check wording

* try to properly restore other videos that are no longer missing
2024-03-29 12:00:46 -05:00
Jason Dove
39df3504fc content rating shouldn't ever be a phrase (#1653) 2024-03-22 09:43:51 -05:00
Jason Dove
60bb369d0c add search query parser (#1652)
* add search query parser

* add some search tests; use consistent analyzers for indexing and searching
2024-03-22 09:41:08 -05:00
Jason Dove
aae704f3a5 fix searching id fields (#1651) 2024-03-21 19:33:50 -05:00
Jason Dove
a45583d77a fix type and tag searches (#1649) 2024-03-20 22:52:16 -05:00
Jason Dove
923b36604c fix many search queries (#1648) 2024-03-20 22:29:51 -05:00
Jason Dove
b21d16b0f1 add show_content_rating to search index (#1647) 2024-03-20 19:46:19 -05:00
Jason Dove
a5aaceeee5 fix path replacement logic with inconsistent casing (#1646) 2024-03-19 08:50:00 -05:00
Jason Dove
e52d45fcf8 fix mysql migration (#1645)
* update dependencies; resync mysql db

* manually fix mysql migration
2024-03-18 11:09:27 -05:00
Jason Dove
21d39bc26f fix multi collection editor id collision (#1644) 2024-03-15 09:48:01 -05:00
Jason Dove
233a1c228a fix block creation (#1643)
* fix block creation

* update dependencies
2024-03-13 08:32:58 -05:00
Jason Dove
56988be57b properly isolate library folders between library paths (#1642) 2024-03-10 20:06:37 -05:00
Jason Dove
aded03d962 fix deleting local libraries and local library paths (#1640) 2024-03-09 12:12:22 -06:00
Jason Dove
2119c88c97 always downsample after loudnorm (#1639) 2024-03-07 09:15:02 -06:00
Jason Dove
a5d83a970a use mkv container for 8-bit segmenter v2 content (#1637) 2024-03-06 12:42:48 -06:00
Jason Dove
986785d863 always use nv12 for 8 bit vaapi encoding (#1636) 2024-03-06 12:03:14 -06:00
Jason Dove
087901d177 adjust block unique constraint (#1634)
* upgrade dependencies

* allow blocks with same name in different groups

* code cleanup
2024-03-05 10:39:06 -06:00
Jason Dove
70c4036dc9 fix ten bit source and destination with segmenter v2 (#1633)
* fix software and vaapi 10 bit content

* fix nvidia 10 bit content

* some qsv improvements
2024-03-04 15:29:45 -06:00
Jason Dove
955add1efd fix av1 software decoder priority (#1632) 2024-03-03 22:29:25 -06:00
Jason Dove
99cd01f73b update iptv routing (#1631) 2024-03-02 22:16:46 -06:00
Jason Dove
ef29e8c5a1 fix vaapi transcoding with a53 cc data (#1625) 2024-02-23 11:27:51 -06:00
Jason Dove
3b4c993530 add xmltv time zone option (#1624) 2024-02-21 12:46:09 -06:00
Jason Dove
bcc58bd668 allow segmenter v2 playback on intel vaapi/qsv (#1623) 2024-02-20 15:45:59 -06:00
Jason Dove
6957a76156 fix concat segmenter for nvidia and qsv (#1622) 2024-02-19 15:29:19 -06:00
Jason Dove
4bafc316cc fix playlist for segmenter v2 (#1621) 2024-02-19 14:11:06 -06:00
Jason Dove
35817f09ac add hls segmenter v2 streaming mode (#1620)
* concat segmenter process kind of works

* segmenter v2 improvements

* rework to allow hw accel in concat segmenter

* remove shortest; use different audio alignment filter

* hls v2 improvements

* fix tests

* update changelog
2024-02-19 13:59:33 -06:00
Jason Dove
f4520a5520 allow decimal image duration (#1619)
* add missing mysql migration

* allow decimal image duration
2024-02-16 20:01:40 -06:00
Jason Dove
3a906816fc allow playback of items with duration of 1 second (#1618) 2024-02-16 13:41:52 -06:00
Jason Dove
707292c50f add configurable image duration (#1617) 2024-02-16 13:05:28 -06:00
Jason Dove
71e9ea867a store local library folder hierarchy in db (#1616) 2024-02-16 06:16:19 -06:00
Jason Dove
c490832f66 fix episode artwork in channel guide (#1613) 2024-02-14 20:21:46 -06:00
Jason Dove
e00568cc23 fix build error (#1612) 2024-02-13 10:51:17 -06:00
Jason Dove
356e0f101a fix edge case where channel would fail to start (#1611) 2024-02-13 10:01:02 -06:00
Jason Dove
1f6e843a26 fix segmenter timestamp continuity (#1610) 2024-02-12 08:50:18 -06:00
Jason Dove
9587692486 optimize image playback (#1609) 2024-02-11 12:54:18 -06:00
Jason Dove
f8c4f44216 add basic image library support (#1608)
* add basic image library support

* add image page

* update changelog
2024-02-11 11:24:19 -06:00
Jason Dove
d55ba235bf evenly divide epg time for schedule blocks (#1607)
* add checkbox to include block items in program guide

* evenly divide epg time for schedule blocks
2024-02-10 20:59:29 -06:00
Jason Dove
60b479e330 scanning fixes (#1606)
* fix music video fallback metadata

* properly re-scan song metadata
2024-02-10 06:44:27 -06:00
Jason Dove
b866d07911 fix song libraries using string collections (#1605) 2024-02-09 13:38:54 -06:00
Jason Dove
93db79f8c4 load song comment (#1604) 2024-02-09 11:37:55 -06:00
Jason Dove
a15854d0ad more guide templates; new song metadata library (#1603)
* refactor template processing

* use template for song xmltv entries

* use template for other video xmltv entries

* update changelog
2024-02-09 11:27:44 -06:00
Jason Dove
c743d07425 include external subtitles in search index (#1602) 2024-02-07 13:28:43 -06:00
Jason Dove
8c3b8e81ca separate request logging into its own category (#1601) 2024-02-07 08:40:31 -06:00
Jason Dove
49050a57d2 load music video artists for channel guide template (#1600) 2024-02-06 10:46:34 -06:00
Jason Dove
49c53c5c96 add stale issue workflow (#1599) 2024-02-05 22:00:57 -06:00
Jason Dove
1510c56e69 generate music video xmltv fragment from template (#1598)
* generate music video xmltv fragment from template

* load all music video data
2024-02-05 19:56:19 -06:00
Jason Dove
3ec610d65f properly encode xmltv fragments (#1597) 2024-02-05 18:15:38 -06:00
Jason Dove
69f9b6f137 add channel guide templates (#1596)
* generate channels xmltv fragment from template

* generate movie xmltv fragment from template

* generate episode xmltv fragment from template

* add channel guide template changelog
2024-02-05 14:55:08 -06:00
Jason Dove
08837bda80 properly categorize some existing streaming debug logs (#1595)
* properly categorize some existing streaming debug logs

* cleanup
2024-02-05 06:37:48 -06:00
Jason Dove
9089e2ee04 add iptv request logging (#1594) 2024-02-04 21:34:41 -06:00
Jason Dove
abed22b560 prevent unnecessary search index updates (#1592)
* add sub_language and sub_language_tag fields to search index

* prevent unnecessary search index updates

* update changelog

* update dependencies
2024-02-02 06:33:06 -06:00
Jason Dove
e0f9ab4b88 batch search index updates (#1591) 2024-02-01 21:30:33 -06:00
Jason Dove
231a214223 add new subtitle settings (#1590) 2024-02-01 11:45:22 -06:00
Jason Dove
82bfa8019e tweak subtitle display in media info (#1589) 2024-01-31 19:17:04 -06:00
Jason Dove
d9bbe4df1b auto generate jwt token for channel preview (#1588) 2024-01-31 15:08:23 -06:00
Jason Dove
e0aa44d41b fix updating jellyfin movies (#1587) 2024-01-31 13:38:35 -06:00
Jason Dove
3d99c2593d allow previewing jwt channels (#1586) 2024-01-31 12:03:04 -06:00
Jason Dove
d6dfc1edaa persist data protection keys in etv config folder (#1585) 2024-01-30 19:41:39 -06:00
Jason Dove
7d5cd229d4 add show_studio search field (#1584) 2024-01-30 16:50:57 -06:00
Jason Dove
cd0219c5c3 update changelog for release v0.8.5-beta [no ci] 2024-01-30 15:34:28 -06:00
Jason Dove
4cf8b83de4 ignore subtitles when they are unavailable (#1583) 2024-01-30 14:29:13 -06:00
Jason Dove
6923b25177 add more log level switches (#1582)
* label block and json playouts as experimental

* add more log level switches
2024-01-30 13:10:19 -06:00
Jason Dove
5dce905b8e clear block playout items without clearing history (#1581) 2024-01-30 09:10:49 -06:00
Jason Dove
46c26b5ea7 include all block playout items in xmltv (#1580)
* include all block playout items in xmltv

* double check whether channel preview will work
2024-01-30 06:44:19 -06:00
Jason Dove
7fffc8cf63 channel preview player (#1579)
* add channel preview

* add button to stop transcoding session
2024-01-29 20:52:52 -06:00
Jason Dove
18deff0b83 add session api endpoints (#1578) 2024-01-29 11:31:16 -06:00
Jason Dove
16007a888e fix actions and changelog (#1576) 2024-01-27 10:14:53 -06:00
Jason Dove
7eb1227ba4 fix action version (#1575) 2024-01-26 06:17:55 -06:00
Jason Dove
1d1d5bf9bc use software overlay for intermittent watermark on nvidia (#1574)
* use software overlay for intermittent watermark on nvidia

* update some github action versions

* update changelog
2024-01-26 06:16:00 -06:00
Jason Dove
45c04366c9 remove dynaudnorm filter (#1573) 2024-01-25 19:56:14 -06:00
Jason Dove
60b3bc92f4 use super shuffle in block playouts (#1572) 2024-01-24 15:29:19 -06:00
Jason Dove
12234c3e21 allow shuffling block items (#1571)
* allow shuffling block items

* fix drop down search results
2024-01-23 22:42:28 -06:00
Jason Dove
d37ce2d38a update xmltv channel list on channel edit (#1570) 2024-01-23 13:10:52 -06:00
Jason Dove
6f49233864 fix image upload corruption (#1569) 2024-01-23 10:49:19 -06:00
Will
a67a6047c1 Update README.md (#1567)
Remove the link for Hardware-accelerated transcoding which was just linking back to itself
2024-01-22 14:33:16 -06:00
Jason Dove
33f67b88f0 show chapter markers in media info (#1568) 2024-01-22 14:19:35 -06:00
Jason Dove
b88deaafe5 add tests, replace playout items when collections are updated (#1566) 2024-01-22 10:10:22 -06:00
Jason Dove
83fc3081d8 add some logging around playlist trimming (#1565) 2024-01-22 05:47:00 -06:00
Jason Dove
15d4b0f82b remove v2 ui and node (#1564) 2024-01-16 13:28:46 -06:00
Jason Dove
88fac0de04 add option to stop scheduling before or after block duration end (#1563) 2024-01-16 12:53:56 -06:00
Jason Dove
4805d0d40f add button to copy block item (#1562) 2024-01-16 10:30:50 -06:00
Jason Dove
ef3b941a39 fix mysql migration (#1561)
* clean up block playout preview logic

* fix some bugs with playout templates editor

* fix mysql migration
2024-01-16 05:40:29 -06:00
Jason Dove
a59f71039c preview block playout in block editor (#1558)
* block editor cleanup

* preview block playout

* cleanup
2024-01-15 19:39:18 -06:00
Jason Dove
1ad42fffb1 fix mac builds (#1557) 2024-01-15 10:29:07 -06:00
Jason Dove
2ce8db9e01 basic block duration enforcement (#1556) 2024-01-15 06:26:14 -06:00
Jason Dove
c409fd8b47 fix playout build hang for block playouts (#1555) 2024-01-14 19:40:29 -06:00
Jason Dove
907b8074f1 allow more collection types and playback orders in blocks (#1554) 2024-01-14 12:51:45 -06:00
Jason Dove
adbd0bcec0 block schedule refactor (#1553)
* erase block playout history and items from playouts page

* remove block from template

* refactor block scheduling; improve history behavior
2024-01-14 10:22:04 -06:00
Jason Dove
2c4379886a limit blocks to television shows and seasons (#1551) 2024-01-14 06:46:38 -06:00
Jason Dove
caef4a139e block scheduling skip unchanged blocks (#1550)
* schedule blocks in order

* block minutes must be multiple of 15

* improve block minutes entry, validation and display

* confirm deleting blocks and block groups

* confirm deleting templates and template groups

* skip unchanged blocks in playout
2024-01-14 06:16:53 -06:00
Jason Dove
dcbe4837bf first pass at block scheduling (#1548)
* add blocks, block groups

* basic block and block item editing

* add template groups and basic template editing (name)

* add blocks to template calendar

* edit playout templates

* add calendar preview to playout templates

* add basic block playout building

* add mysql migration

* update changelog
2024-01-13 22:01:21 -06:00
Jason Dove
5e530b9301 fix scale behavior crop with qsv (#1546) 2024-01-12 13:21:49 -06:00
Jason Dove
2a28bf68bf fix crop mode with nvidia accel (#1545) 2024-01-11 11:42:26 -06:00
Jason Dove
f39eac97c0 fix fill with group when show is also included individually (#1544) 2024-01-11 10:44:50 -06:00
Jason Dove
9fd6589831 disambiguate seasons (#1543) 2024-01-11 09:08:52 -06:00
Jason Dove
e2a516f5e8 fix external json playouts with mysql (#1542) 2024-01-09 05:26:57 -06:00
Jason Dove
64502315a3 generate xmltv for external json playouts (#1541) 2024-01-08 20:54:40 -06:00
Jason Dove
56bc58fce9 reorganize to fix build (#1540) 2024-01-08 20:00:35 -06:00
Jason Dove
0330b9326d add external json playout type for dizquetv interop (#1539)
* add external json playout

* basic local playback works

* fallback to streaming from plex

* update external json file

* update changelog
2024-01-08 19:45:43 -06:00
Jason Dove
6708d6b4d7 support filling with groups of song artists (#1537) 2024-01-05 10:32:04 -06:00
Jason Dove
c18be5559b fix delete old segments (#1536)
* code cleanup

* ignore errors deleting old hls segments
2024-01-04 10:42:04 -06:00
Jason Dove
18ed20e203 fix multiple zero when using fill with group (#1535) 2024-01-02 15:29:50 -06:00
Jason Dove
965c7d0eac update changelog [no ci] 2024-01-02 10:34:57 -06:00
Jason Dove
545bf1b775 fill with group (#1534)
* use browser's accept-language header

* add fill with group mode to schedule items

* update dependencies

* fixes

* fix tests
2024-01-02 10:18:49 -06:00
Jason Dove
bb299d4ee7 maybe these don't need npm (#1533) 2023-12-30 20:13:11 -06:00
Jason Dove
0e6c7d2bc3 fix npm in docker builds (#1532) 2023-12-30 20:03:29 -06:00
Jason Dove
576f0cd7e7 more dotnet 8 fixes (#1530) 2023-12-30 13:47:45 -06:00
Jason Dove
9471cb55dd upgrade from dotnet 7 to dotnet 8 (#1529)
* upgrade sdk

* fix warnings in ersatztv.ffmpeg

* fix warnings in ersatztv.core

* fix warnings in ersatztv.infrastructure

* fix warnings in ersatztv.application

* disable analysis for migrations projects

* fix warnings in ersatztv.scanner

* fix warnings in ersatztv

* upgrade project framework

* update github actions and dockerfiles
2023-12-30 13:29:57 -06:00
Jason Dove
3a84af1626 update dependencies (#1527) 2023-12-27 04:44:30 -06:00
Jason Dove
3d3bb64844 fix path replacements page with mysql (#1521) 2023-12-11 17:54:15 -06:00
Jason Dove
8fc1f36638 use explorer to open logs folder on windows (#1520) 2023-12-05 18:28:10 -06:00
Jason Dove
1823a5bae5 update changelog for release v0.8.4-beta [no ci] 2023-12-02 16:45:33 -06:00
Jason Dove
fc871e6f74 fix detection of amf hw accel on windows (#1519) 2023-12-02 09:05:02 -06:00
Jason Dove
24780cbe84 fix disappearing collection tags (#1517) 2023-11-30 20:31:37 -06:00
Jason Dove
c6ed258021 validate filler mode pad settings (#1516) 2023-11-26 12:54:06 -06:00
Jason Dove
7586647b73 fix ffmpeg version health check on windows (#1515) 2023-11-23 06:05:49 -06:00
Jason Dove
d91e945124 update changelog for release v0.8.3-beta [no ci] 2023-11-22 11:36:31 -06:00
Jason Dove
9dabffbac1 support more formats for show fallback metadata (#1514) 2023-11-21 15:52:25 -06:00
Jason Dove
d310b5c09d fix nvidia hardware decoding on windows (#1513) 2023-11-21 06:36:05 -06:00
Jason Dove
ba48b3a676 update dependencies (#1512) 2023-11-20 21:57:43 -06:00
Jason Dove
d8a51b5d6d fix season display bug (#1511) 2023-11-20 21:17:11 -06:00
Jason Dove
97674cff89 fix bug scheduling duration filler (#1510) 2023-11-20 21:02:26 -06:00
Jason Dove
4820615308 proper fix to the sdk mismatch (#1509) 2023-11-16 13:37:20 -06:00
Jason Dove
1ddf27ce88 pin dotnet sdk version used in github actions (#1508) 2023-11-16 13:21:51 -06:00
Jason Dove
cd98a89acd enable docker arm builds again (#1507) 2023-11-16 13:07:49 -06:00
Jason Dove
a2a6afc3e3 temp disable arm docker builds (#1506) 2023-11-16 09:58:46 -06:00
Jason Dove
dfaba8c7b0 use release version of ffmpeg 6.1 (#1505) 2023-11-16 09:57:13 -06:00
Jason Dove
5d11a6b46f use separate model for plex collection scanning since the api types are inconsistent (#1504) 2023-11-16 06:43:48 -06:00
Jason Dove
b95a89b11f plex collection rework (#1503)
* start to rework plex collection scanning

* sync plex collections to db

* sync plex collection items

* update changelog
2023-11-14 10:41:21 -06:00
Jason Dove
948b3735bd fix file not found music videos (#1502)
* fix indexing music videos in file not found state

* update dependencies
2023-11-14 05:50:51 -06:00
Jason Dove
5ecf271773 fix jellyfin library scan (#1501)
* update dependencies

* fix jellyfin library scan
2023-11-10 06:26:23 -06:00
Jason Dove
b287c0d6ec add jellyfin season number fallback (#1497) 2023-11-06 09:37:12 -06:00
Jason Dove
b667659c05 use notarytool directly instead of gon (#1493) 2023-11-05 07:46:15 -06:00
Jason Dove
22d3025e8e include noto cjk fonts in docker (#1492) 2023-11-05 06:15:57 -06:00
Jason Dove
8f5b181372 mysql media server library scan fixes (#1491)
* fix some mysql movie library updates

* fix some mysql show library updates

* update dependencies
2023-10-30 06:45:00 -05:00
Jason Dove
f5060522aa windows nvidia h264 workaround (#1487)
* work around bad h264_cuvid behavior on windows with ffmpeg snapshot

* use latest ffmpeg build on windows

* nvdec => cuda
2023-10-16 11:40:12 -05:00
Jason Dove
14a88bd225 optimize ffmpeg capability cache (#1486)
* minimize cached ffmpeg capabilities

* use set intersect

* try disabling work ahead on nvidia/windows
2023-10-16 08:42:26 -05:00
Jason Dove
0550c60a78 allow older ffmpeg for testing (#1485)
* allow older ffmpeg for testing

* use proper option name
2023-10-14 21:13:18 -05:00
Jason Dove
d3bdcf9bc4 allow plex personal media show libraries (#1483) 2023-10-13 13:33:10 -05:00
Jason Dove
714f68a887 add language_tag and seconds fields to search index (#1479)
* add `language_tag` and `seconds` fields to search index

* simplify
2023-10-10 20:36:50 -05:00
Jason Dove
17bed524f2 fix ui display of multiple languages (#1474) 2023-10-08 18:21:48 -05:00
Jason Dove
c3fe263978 validate hardware accel, use hw accel for error messages (#1471)
* only display supported hw accels in ffmpeg profile editor

* qsv capability improvements

* qsv fixes

* update changelog
2023-10-08 11:21:04 -05:00
Jason Dove
5291832e6c fix clipboard and logs (#1466)
* fix copy to clipboard in some cases

* improve subtitle language selection logging

* log playout item details
2023-10-06 19:36:42 -05:00
Jason Dove
b39dd693f0 update dependencies and windows ffmpeg (#1462)
* update dependencies

* update windows ffmpeg version
2023-10-05 19:14:06 -05:00
Jason Dove
46bf9ef990 fix intel vaapi pgs subtitle pixel format (#1455) 2023-09-30 13:10:23 -05:00
Jason Dove
bc845b1327 schedule filler using ticks instead of milliseconds (#1454)
* add script to set db provider

* don't extract embedded subtitles with DEBUG_NO_SYNC

* fix playout filler precision bug
2023-09-30 06:41:15 -05:00
Jason Dove
3ab8e5bc3a optimize jellyfin collection scanning (#1453) 2023-09-29 09:47:57 -05:00
Jason Dove
e8bc051f73 transcoding improvements (#1452)
* use noautoscale with vaapi encoder

* only use one input file for vaapi with radeonsi driver

* fix vaapi 8-bit to 10-bit

* fix nvidia subtitle scaling

* optimize nvidia subtitle scaling

* fix test pgs subtitle
2023-09-29 06:29:59 -05:00
Jason Dove
b008fcfd85 fix scheduling precision error (#1451)
* fix scheduling precision error

* update dependencies
2023-09-27 06:07:48 -05:00
Jason Dove
547db5fb51 add kodiprop to channels.m3u (#1448) 2023-09-26 15:47:55 -05:00
Jason Dove
58fae1b0cc add crop scaling behavior (#1443)
* add scaling behavior - crop

* fix ffmpeg version check on windows (snapshot)

* update dependencies
2023-09-22 08:23:49 -05:00
Jason Dove
694b6bbd91 scaling behavior and normalize loudness (#1439)
* update changelog [no ci]

* add ffmpeg profile scaling behavior

* update dependencies

* add normalize loudness mode

* update changelog
2023-09-21 02:46:43 -05:00
Jason Dove
e0f8b7d7ae use ffmpeg 6.1 snapshot for windows (#1435) 2023-09-14 19:33:40 -05:00
Jason Dove
b16215fcd6 improve hls throttle (#1434)
* throttle using ffmpeg option

* update ffmpeg version
2023-09-14 19:28:15 -05:00
Jason Dove
85f2c658aa update changelog for release v0.8.2-beta [no ci] 2023-09-14 09:19:21 -05:00
Jason Dove
78356314e6 update dependencies (#1433) 2023-09-14 08:46:59 -05:00
Jason Dove
b00a25bbee fix parsing show title from nfo (#1426) 2023-09-10 19:46:51 -05:00
Jason Dove
4d77576be2 update dependencies (#1425)
Co-authored-by: Jason <jason@mbp-touch.local>
2023-09-10 09:22:35 -05:00
Jason Dove
a90348740d fix subsequent hls session work ahead (#1419) 2023-09-06 20:01:58 -05:00
Jason Dove
8081845ef1 fix adding alternate schedule (#1418) 2023-09-04 14:06:39 -05:00
Jason Dove
d014eb4274 mysql ui fixes (#1417) 2023-09-04 13:12:00 -05:00
Jason Dove
8c9cf7b6f2 fix mid roll pad; fix mysql queries (#1416)
* fix mysql queries

* fix mid roll pad with hls segmenter
2023-09-04 10:01:39 -05:00
Jason Dove
5d9c8d4f7d update checkout actions (#1415) 2023-09-04 08:38:10 -05:00
Jason Dove
82de3136cd fix hls session worker lifetime (#1414) 2023-09-04 08:30:01 -05:00
Jason Dove
b1cd324f9c fix docker builds (#1413) 2023-09-03 08:54:48 -05:00
Jason Dove
5caf8f7f98 fix builds (#1412) 2023-09-03 08:52:00 -05:00
Jason Dove
245c4ec359 code analysis and cleanup (#1411)
* cleanup scanner project

* cleanup infrastructure projects

* cleanup ffmpeg project

* cleanup core project

* cleanup app project

* cleanup main project

* update dependencies

* code cleanup
2023-09-03 06:23:42 -05:00
Jason Dove
6414471ace fix emby movie libraries (#1410) 2023-09-02 13:03:48 -05:00
Jason Dove
8b0b927a5c use d3d11va for qsv accel on windows (#1408) 2023-09-01 11:50:56 -05:00
Jason Dove
e5962699a4 schedule item editor updates (#1407) 2023-09-01 06:44:31 -05:00
Jason Dove
27504e42bc fix mysql show queries (#1406)
* ignore artwork when sync is disabled

* fix delete playout

* fix some mysql queries
2023-09-01 06:05:36 -05:00
Jason Dove
deb0ac49b5 show plex server names in libraries page (#1402)
* cleanup plex libraries query

* show plex server names in libraries page
2023-08-29 08:46:36 -05:00
Jason Dove
225b95449c rework hls session state (#1401) 2023-08-29 05:59:35 -05:00
Jason Dove
cb43c28d00 fix hls session when starting with very short content (#1400) 2023-08-29 05:01:13 -05:00
Jason Dove
0a75136223 fix transcoding short content (#1399) 2023-08-28 22:01:38 -05:00
Jason Dove
efc710749e fix test 2023-08-28 20:44:35 -05:00
Jason Dove
8f241f49fc optimize transcoding speed (#1398)
* fix "empty trash" button blinking when loading trash page

* clean channel guide cache on startup

* only work-ahead in hls session for 2 minutes
2023-08-28 20:42:02 -05:00
Jason Dove
20d224fcfd more mysql fixes (#1397)
* fix channels and movie page crashes with mysql

* update dependencies
2023-08-26 10:39:33 -05:00
Jason Dove
b3fda4e88d allow shared plex servers (#1391)
* allow shared plex servers

* update dependencies
2023-08-22 08:49:26 -05:00
Jason Dove
560cb826b3 fix local subtitles display (#1388)
* show external subtitles in media info

* fix mysql saved page size
2023-08-19 11:26:52 -05:00
Jason Dove
b038a58fa2 fix saving smart collection (#1384) 2023-08-15 15:53:56 -05:00
Jason Dove
c28e201e47 fix adding shows directly to schedule (#1383) 2023-08-15 15:34:53 -05:00
Jason Dove
b84bb6b437 fix ui crashes (#1382)
* fix ffmpeg editor crash

* fix watermark editor

* fix multi collection editor

* fix filler preset editor crash
2023-08-15 06:39:29 -05:00
Jason Dove
641b8bcd10 fix windows dependency (#1380) 2023-08-14 19:44:18 -05:00
Jason Dove
4b08ed5381 fix mysql migration (initial data) (#1379) 2023-08-14 15:21:42 -05:00
Jason Dove
5486dcdcab remove docs files and workflow [no ci] 2023-08-13 20:16:49 -05:00
Jason Dove
77b32b0f09 fix github repo links (#1378) 2023-08-13 09:59:48 -05:00
Jason Dove
2c6c08becf update submodule [no ci] 2023-08-13 09:33:33 -05:00
Jason Dove
99bc19cf26 fix docker builds (#1376) 2023-08-12 22:02:45 -05:00
Jason Dove
a7661c8498 add mysql database provider (#1375)
* refactor sqlite into separate library

* support mysql

* fixes

* sql fixes

* cleanup

* update changelog
2023-08-12 21:44:14 -05:00
Jason Dove
d951035183 fix bulk removing items from elasticsearch index (#1374) 2023-08-12 08:51:12 -05:00
Jason Dove
097c60169c elasticsearch relative queries (#1373)
* remove unused code

* fix relative queries with elasticsearch

* fix some double page loads

* simplify language model
2023-08-12 06:36:28 -05:00
Jason Dove
d64d8b0454 don't always rebuild elasticsearch index on startup (#1372) 2023-08-11 15:47:17 -05:00
Jason Dove
7486304ed9 fix elasticsearch smart collection playouts (#1371) 2023-08-11 15:28:57 -05:00
Jason Dove
c62cc98c9f add elasticsearch search index provider (#1370)
* wip

* first pass at elasticsearch; movies kind of work

* use field name constants

* properly sort search results

* fix some crashes

* fix page map/jump letters

* optimize page map using terms aggregation

* index all item types

* optionally use elastic search

* code cleanup

* automatically rebuild lucene index after improper shutdown

* update changelog
2023-08-11 13:57:50 -05:00
Jason Dove
22a13cb1b3 Revert "add debug logs for other video folder scanning (#1369)"
This reverts commit 5e573461f3.
2023-08-10 12:51:47 -05:00
Jason Dove
5e573461f3 add debug logs for other video folder scanning (#1369) 2023-08-10 11:26:48 -05:00
Jason Dove
76c596a7d8 fix logs page (#1368)
* fix log viewer crash

* update dependencies
2023-08-10 10:45:43 -05:00
Jason Dove
f945f16d97 fix qsv subtitle scaling (#1367) 2023-08-10 10:16:10 -05:00
Jason Dove
797d4005e2 replace moq with nsubstitute (#1365) 2023-08-09 20:14:18 -05:00
Jason Dove
55903430ae update changelog for release v0.8.1-beta [no ci] 2023-08-07 13:32:07 -05:00
Jason Dove
f929dc92d1 update dependencies; code cleanup (#1357)
* update dependencies

* code cleanup
2023-08-07 09:34:25 -05:00
Jason Dove
2ad27c2be0 update dependencies (#1348)
* update dependencies

* silence mudblazor debug logs
2023-07-24 20:40:32 -05:00
Jason Dove
df2db5caf7 add plex file name logging (#1342) 2023-07-12 19:27:16 -05:00
Jason Dove
5978e8ecb1 fix vaapi rate control mode (#1340) 2023-07-08 12:36:07 -05:00
Jason Dove
a540efc2e1 add community to readme [no ci] 2023-07-03 13:07:42 -05:00
Jason Dove
1938cef6ae add community link to docs (#1339) 2023-07-03 13:01:54 -05:00
Jason Dove
b23d798aff update dependencies (#1329) 2023-06-26 11:11:40 -05:00
Jason Dove
ebad7664b0 force hw accel to use one thread (#1327) 2023-06-25 09:56:58 -05:00
Jason Dove
a9c93ff498 add custom resolution management (#1326)
* update some dependencies

* add custom resolution management
2023-06-25 09:14:19 -05:00
Jason Dove
8277894f7b show database and search index initialization in ui (#1325)
* unblock startup, show database initialization message

* wait on search index to be ready (rebuild)

* clean logging and fake delay
2023-06-24 09:12:46 -05:00
Jason Dove
0d66f752b6 add global mutex to ensure single instance (#1324) 2023-06-24 06:30:55 -05:00
Jason Dove
c128f72a54 update changelog for release v0.8.0 [no ci] 2023-06-23 22:16:26 -05:00
Jason Dove
4af2d7aa61 don't trust emby's anamorphic flag (#1321) 2023-06-22 20:07:58 -05:00
Jason Dove
20a6727158 fix vaapi hw decoding (#1320) 2023-06-22 15:05:02 -05:00
Jason Dove
52e1874426 vaapi cqp rate control mode (#1319) 2023-06-22 11:42:11 -05:00
Jason Dove
015f5e9798 fix playout build loop that was recently introduced (#1318) 2023-06-22 09:40:20 -05:00
Jason Dove
1fc461e476 update dapper (#1316) 2023-06-21 15:51:35 -05:00
Jason Dove
85792f0811 fix nvidia color normalization (#1314) 2023-06-20 09:23:41 -05:00
Jason Dove
0f91a43e3f fix scaling subtitles with nvidia accel (#1313) 2023-06-20 06:25:15 -05:00
Jason Dove
7a25996ab4 scale subtitles with all accels (#1311)
* properly scale subtitles with qsv and vaapi

* fixes
2023-06-19 15:55:23 -05:00
Jason Dove
6985826072 add mpeg-ts output format for hls direct (#1310) 2023-06-19 11:19:19 -05:00
Jason Dove
52482ef2fb only discard items with random or shuffle playback order (#1309) 2023-06-19 09:17:10 -05:00
Jason Dove
c148f2eb11 fix discard to fill calculation (#1308) 2023-06-17 05:11:08 -05:00
Jason Dove
d490cc6f4b dont give up on scheduling filler while some should fit (#1306) 2023-06-14 16:58:37 -05:00
Jason Dove
99bd827bd9 fix multi episode shuffle (#1305) 2023-06-14 16:40:18 -05:00
Jason Dove
e8cbcc935f rework pad and duration filler (#1304) 2023-06-14 15:54:41 -05:00
Jason Dove
a2acfe4d80 add finish column to playout detail table (#1302) 2023-06-13 19:09:19 -05:00
Jason Dove
5da2bdbab4 add duration discard to fill attempts (#1301) 2023-06-13 17:02:31 -05:00
Jason Dove
66607b95bb update dependencies (#1300) 2023-06-13 13:58:44 -05:00
Jason Dove
81a6251f65 properly lock playout before build (#1299) 2023-06-13 13:45:00 -05:00
Jason Dove
c554d83d60 playout management ui improvements (#1298) 2023-06-13 13:26:34 -05:00
Jason Dove
875010bbf4 update changelog for release v0.7.9-beta [no ci] 2023-06-10 10:40:05 -05:00
Jason Dove
c5692ef5f1 update dependencies (#1296) 2023-06-08 09:20:06 -05:00
Jason Dove
147ab6143d hls direct mkv container (#1292)
* use mkv container for hls direct

* add setting for mp4/mkv container with hls direct

* cleanup

* update changelog
2023-06-06 10:21:09 -05:00
Jason Dove
aca441074e subtitle improvements with hls direct (#1290)
* wip: hls direct subtitles

* convert picture subtitles with hls direct

* use mp4 for hls direct to support more codecs

* disable subtitle conversion in hls direct

* fix tests

* update changelog
2023-06-04 12:29:47 -05:00
Jason Dove
ef6adf9cbb update dependencies (#1289) 2023-06-02 06:35:31 -05:00
Jason Dove
ddb7e1887f fix nvidia h264 decoder (#1281) 2023-05-22 21:26:48 -05:00
Jason Dove
4997699b4d sync jf and emby episode actors (#1280) 2023-05-22 15:58:08 -05:00
Jason Dove
c27b906cd5 update docs (#1277)
* tweak mkdocs config; update install

* path replacement doc updates
2023-05-21 10:43:48 -05:00
Jason Dove
bec3cb864d update dependencies (#1276)
* update dependencies

* fix ide warnings

* tweak ef config
2023-05-21 10:13:44 -05:00
Jason Dove
03df2a6c8a overdue code cleanup (#1271) 2023-05-10 13:18:18 -05:00
dependabot[bot]
6142dcf153 Bump jetbrains.resharper.globaltools from 2022.1.0 to 2023.1.1 (#1264)
Bumps jetbrains.resharper.globaltools from 2022.1.0 to 2023.1.1.

---
updated-dependencies:
- dependency-name: jetbrains.resharper.globaltools
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-10 08:56:08 -05:00
Jason Dove
b287f791e6 fix pgs subtitle burn in from media servers (#1270) 2023-05-09 22:43:25 -05:00
Jason Dove
2ccba9e476 timeout playout builds after 2 minutes (#1269)
* add cancellation token support to playout builds and collection enumerators

* fix playout bug with shuffle in order

* update changelog
2023-05-08 11:53:02 -05:00
Jason Dove
e215807e56 add worker service debug logs (#1267)
* add worker service debug logs

* update mudblazor
2023-05-05 08:42:33 -05:00
Jason Dove
b0333e89cd fix fallback filler (#1265) 2023-05-03 12:08:14 -05:00
Jason Dove
bc240a40e0 fix extracting text subtitles (#1262) 2023-04-29 21:46:20 -05:00
Jason Dove
ed816e4b06 update changelog for release [no ci] 2023-04-29 20:48:24 -05:00
Jason Dove
7c0f26ed3e update dependencies (#1261) 2023-04-29 09:42:06 -05:00
Jason Dove
a54e37a648 proper fix 2023-04-26 19:35:40 -05:00
Jason Dove
c0656114b8 ignore dot underscore files (#1259) 2023-04-26 11:46:38 -05:00
Jason Dove
7628ec7921 fix vobsub subtitle burn in from media server libraries (#1258) 2023-04-25 15:18:53 -05:00
Jason Dove
30850329f3 fix external subtitle playback on windows (#1256) 2023-04-23 09:53:57 -05:00
Jason Dove
6bb1c4299f fix colorspace filter for some files with invalid color metadata (#1254) 2023-04-20 11:59:31 -05:00
Jason Dove
73c6758537 add show media info button to movie and episode detail pages (#1253) 2023-04-20 10:45:32 -05:00
Ministorm3
ef1400d3f8 Corrected issue with channel delete (#1247)
* Channel delete now updates the guide cache.

* update changelog

---------

Co-authored-by: Jason Dove <jason@jasondove.me>
2023-04-14 19:37:46 -05:00
Jason Dove
494142f026 fix media server text subtitle extraction (#1246) 2023-04-14 15:09:12 -05:00
Jason Dove
b89deffda3 cleanup delete channel handler syntax (#1245) 2023-04-14 12:53:33 -05:00
Jason Dove
ab55978732 add season, episode playback order for shows (#1243) 2023-04-13 11:06:48 -05:00
Jason Dove
b8dcd26e3a fix hls direct regression (#1242) 2023-04-12 15:47:25 -05:00
Jason Dove
24f7544c9f improve schedule editor performance (#1240)
* rename

* async cleanup

* use autocomplete fields in schedule items editor
2023-04-11 14:16:39 -05:00
Jason Dove
afb2caa95d fix qsv watermark alpha (#1239) 2023-04-11 10:30:19 -05:00
Jason Dove
a684dcced9 scheduling bug fixes (#1238) 2023-04-11 09:22:51 -05:00
Jason Dove
cf1552910a limit hls direct streams to realtime speed (#1237) 2023-04-09 20:21:03 -05:00
Jason Dove
e53e2b36cf update copyright in docs 2023-04-07 21:42:49 -05:00
Jason Dove
793e85f889 update changelog for release v0.7.7-beta [no ci] 2023-04-07 21:41:50 -05:00
Jason Dove
126304bb8a fix subtitles from media server libraries (#1233)
* fix embedded subtitles from media servers

* fix plex external subtitles

* fix artwork bug, delete orphaned subtitles

* jellyfin subtitles work again

* emby subtitles work

* rescan all media server libraries
2023-04-07 13:22:45 -05:00
Jason Dove
7b3b9b4aad fix search index bug (#1231) 2023-04-05 21:52:31 -05:00
Jason Dove
cf3b8d90e3 fix bt470bg color normalization using qsv (#1230) 2023-04-05 10:02:46 -05:00
Jason Dove
109b244676 use software decoding for mpeg4 part2 with nvidia accel (#1229) 2023-04-05 08:48:58 -05:00
Jason Dove
9f42333465 cache data for xmltv (#1228)
* cache channel list for xmltv

* used cached channel data for xmltv

* fixes

* update changelog
2023-04-03 23:09:54 -05:00
Jason Dove
c9141b0d86 fix colorspace filter when using vaapi (#1226) 2023-04-02 10:09:05 -05:00
Jason Dove
d2c4a58528 minor bug fixes (#1225) 2023-04-01 22:51:48 -05:00
Jason Dove
e93d678b97 add more logging (#1224)
* more logging

* update dependencies
2023-04-01 12:24:15 -05:00
Jason Dove
307940d732 add duplicate file logging (#1223) 2023-04-01 09:54:19 -05:00
Jason Dove
721f0df82a fix library scanning with non-english season folder names (#1222) 2023-03-31 13:37:54 -05:00
Jason Dove
aa87abc53d prioritize poster artwork for xmltv (#1221) 2023-03-29 08:18:03 -05:00
Jason Dove
83d4aa0cb1 use other video plot as xmltv description (#1219) 2023-03-27 19:22:44 -05:00
Jason Dove
46034aff54 fix updating trakt lists (#1218) 2023-03-25 05:58:41 -05:00
Jason Dove
3e447ac7e4 fix changelog links [no ci] 2023-03-24 14:41:10 -05:00
Jason Dove
bda27faaa3 update changelog for release v0.7.6-beta [no ci] 2023-03-24 14:40:04 -05:00
Jason Dove
80d89a2530 fix color normalization from bt470bg to bt709 (#1217) 2023-03-22 08:04:21 -05:00
Jason Dove
e849ef5dfa remove bad file 2023-03-21 22:35:09 -05:00
Jason Dove
a26ecb91b8 ignore sidecar subtitle files from media server libraries (#1216) 2023-03-21 20:44:13 -05:00
Jason Dove
2853e13edc update changelog [no ci] 2023-03-17 10:05:28 -05:00
Jason Dove
9ba0b844a1 JWT Query Parameter Auth for IPTV Links (#1215)
* JWT Auth

* Standardized url variable additions

* formatting and minor refactoring

* this isn't needed

* allow channel logos without auth

* update changelog

---------

Co-authored-by: Ministorm3 <4474921+Ministorm3@users.noreply.github.com>
2023-03-17 09:33:15 -05:00
Jason Dove
fdab54a055 limit console log output on windows (#1212) 2023-03-16 06:21:02 -05:00
Jason Dove
7e0801119e maintain collection progress across alternate schedules (#1211) 2023-03-15 20:34:25 -05:00
Jason Dove
b2f7bcaf1e add more fields to music video credit templates (#1210) 2023-03-15 20:10:24 -05:00
Jason Dove
71b8be37da restyle troubleshooting page (#1208) 2023-03-13 13:24:27 -05:00
Jason Dove
f7d19e3747 duration mode guide fixes (#1207)
* fix playout mode duration xmltv

* fix playout mode duration wrapping midnight
2023-03-13 09:00:59 -05:00
Jason Dove
17dcbfc344 add troubleshooting page (#1206) 2023-03-12 13:00:54 -05:00
Jason Dove
78745de0ca rework emby collection scanning (#1205)
* optimize emby collection scan frequency

* add button to sync emby collections

* update changelog

* fix scanning; add progress indicator
2023-03-11 22:29:10 -06:00
Jason Dove
35445e2b3d proxy external subtitle files (#1203) 2023-03-09 19:31:59 -06:00
Jason Dove
bd2f0f6236 song normalization (#1202)
* add tests to verify song normalization

* simplify song setup, include watermarks and album art

* fix song path

* update changelog
2023-03-09 10:40:59 -06:00
Jason Dove
4c67965b50 fix emby scanning (#1201) 2023-03-09 07:59:26 -06:00
Jason Dove
234e93349b rework concurrency (#1199) 2023-03-08 21:23:18 -06:00
Jason Dove
e7e20de502 include multiple display-name entries in xmltv (#1198) 2023-03-07 09:53:00 -06:00
Jason Dove
dfc36b4581 case-insensitive file extensions in local scanner (#1197) 2023-03-06 18:21:34 -06:00
Jason Dove
c56e2526c4 fix media server scanning (#1196)
* fix media server scans

* update dependencies
2023-03-06 08:28:35 -06:00
Jason Dove
8ff6bf652c fix jellyfin streaming and sar calculation (#1195) 2023-03-05 21:40:20 -06:00
Jason Dove
a386fe9ba1 update changelog for release v0.7.5-beta [no ci] 2023-03-05 10:12:21 -06:00
Jason Dove
4d84fc242b plex scanner improvement (#1193)
* fix crash with some plex multi-episode files

* comments cleanup
2023-03-03 06:08:42 -06:00
Jason Dove
40e79a3a14 fix plex scanner crash (#1192) 2023-03-02 22:49:21 -06:00
Jason Dove
c653bb32a7 plex scanner logging 2023-03-02 20:57:38 -06:00
Jason Dove
b032e70d7e support more local season folder names (#1191) 2023-03-02 20:13:34 -06:00
Jason Dove
074816be50 simplify qsv accel syntax on linux (#1189) 2023-03-02 06:00:36 -06:00
Jason Dove
3fafd5192f fix hevc_nvenc encoder on sm < 75 (#1187) 2023-03-01 20:17:58 -06:00
Jason Dove
1d63197b56 fix yuv444p10le (#1186) 2023-03-01 19:56:14 -06:00
Jason Dove
b2c57e7407 upgrade to ffmpeg 6 (#1185) 2023-03-01 19:21:53 -06:00
Jason Dove
581aa51792 fix trash display for certain episodes (#1184)
* fix trash display for certain episodes

* fix multi-episode fallback metadata
2023-02-28 09:37:30 -06:00
Jason Dove
4d57ece30d check ffmpeg for available decoders, filters, encoders (#1183)
* check ffmpeg for available decoders, filters, encoders

* revert csproj change
2023-02-27 19:28:42 -06:00
Jason Dove
eddbf07b11 vaapi: decode vp9 and av1 (#1181) 2023-02-27 05:57:13 -06:00
Jason Dove
450ea063b4 update vaapi docker bundled ffmpeg version 2023-02-26 21:39:22 -06:00
Jason Dove
f320d84874 fix ffmpeg version health check for vaapi docker (#1179) 2023-02-25 08:18:49 -06:00
Jason Dove
c832c8e860 prioritize default audio tracks (#1178) 2023-02-24 15:45:30 -06:00
Jason Dove
e5ef8eaf72 fix some cases where vaapi hwdownload would fail; use libvpl in docker (#1177)
* fix some cases where vaapi hwdownload would fail

* update changelog
2023-02-24 09:10:42 -06:00
Jason Dove
6db71f525d remove duplicate filter from search index (#1172) 2023-02-21 22:15:57 -06:00
Jason Dove
3ab66ef12a update intel media driver in vaapi docker image 2023-02-21 19:02:54 -06:00
Jason Dove
018f759fa4 improve vaapi capability detection (#1171) 2023-02-21 09:53:23 -06:00
Jason Dove
1afff11063 software decoder fixes (#1169)
* fix software decoder pipeline bugs

* tweak nvidia scaling logic

* update changelog

* update dependencies
2023-02-20 19:45:25 -06:00
Jason Dove
7e3436e68f direct stream content from emby as needed (#1168) 2023-02-19 20:29:09 -06:00
Jason Dove
b751f1054b direct stream content from jellyfin if needed (#1167)
* redirect to jellyfin stream as needed

* get jellyfin playback info

* sync chapters from jellyfin

* update changelog

* cleanup
2023-02-19 10:37:48 -06:00
Jason Dove
900e9e75f3 sync chapter markers from plex (#1166) 2023-02-18 14:51:51 -06:00
Jason Dove
62c28d9f51 direct stream content from plex if needed (#1165)
* start to stream directly from plex

* update metadata and statistics with one plex api call

* stream movies from plex

* scanning bug fix; update changelog
2023-02-18 10:40:05 -06:00
Jason Dove
132ca99f94 fix default dockerfile (#1156) 2023-02-13 05:38:11 -06:00
Jason Dove
c309ab430e update changelog for release v0.7.4-beta [no ci] 2023-02-12 18:21:11 -06:00
Jason Dove
13e21bbcce sync episode tags and genres (#1155)
* sync episode tags and genres

* update dependencies

* property update local episode genres and tags

* fix test
2023-02-12 09:53:20 -06:00
Jason Dove
0eb36f0ce1 prioritize default audio streams (#1154) 2023-02-10 09:31:55 -06:00
Jason Dove
6429f0f064 fix filler padding (#1153)
* fix filler padding

* update dependencies
2023-02-07 19:55:30 -06:00
Jason Dove
7412ac6fc9 fix mid and post roll filler ordering (#1152) 2023-02-07 12:25:22 -06:00
Jason Dove
e58e3c786d fix last scan check (#1150) 2023-02-06 05:38:08 -06:00
Jason Dove
93fc1e4eb4 fix fallback filler looping (#1146) 2023-02-04 08:49:52 -06:00
Jason Dove
cacde26796 merge other video folder tags with nfo tags (#1144) 2023-02-01 05:58:26 -06:00
Jason Dove
0a3db92c60 fix schedule copy (#1142) 2023-01-30 10:23:18 -06:00
Jason Dove
8bb0cd5ab5 add copy schedule feature (#1141) 2023-01-30 06:38:34 -06:00
Jason Dove
e497dc4e36 fix nvidia vp9 color normalization (#1140) 2023-01-29 16:02:29 -06:00
Jason Dove
2689a67eb8 qsv and vaapi fixes (#1139)
* lots of qsv fixes

* update changelog

* fix qsv mpeg2

* vaapi fixes

* update changelog

* upgrade mudblazor

* fix bug with undefined input colorspace
2023-01-29 10:00:52 -06:00
Jason Dove
3d821043bb update changelog for v0.7.3-beta [no ci] 2023-01-25 12:01:38 -06:00
Jason Dove
e69c58e615 conditionally disable v2 apis (#1135)
* conditionally disable v2 apis

* update changelog
2023-01-25 11:37:43 -06:00
Jason Dove
a21b6f9f4e add oidc logout url to support auth0 (#1134) 2023-01-25 09:30:36 -06:00
Jason Dove
99b8038852 add oidc support (#1133) 2023-01-25 08:37:59 -06:00
Jason Dove
ef8ca9f8c6 build mac artifacts on macos 11 (#1132) 2023-01-24 15:04:55 -06:00
Jason Dove
d9186df157 minor logging and doc updates (#1130) 2023-01-23 05:28:17 -06:00
Jason Dove
aca6bfb0bb fix multiple gcs after extracting subtitles (#1129) 2023-01-22 13:10:13 -06:00
Jason Dove
587fc3a98f release memory after extracting embedded subtitles (#1128) 2023-01-22 12:34:42 -06:00
Jason Dove
ab1c67e60e memory improvements (#1127)
* regularly release memory

* don't aggressively GC while legacy streaming

* update changelog
2023-01-22 09:16:24 -06:00
Jason Dove
e271f43066 more scan check fixes (#1126) 2023-01-21 08:22:56 -06:00
Jason Dove
6bf8feb26e fix local library scan check with new install (#1125) 2023-01-21 08:10:42 -06:00
Jason Dove
ffd66f6a21 fix removing media server libraries (#1124) 2023-01-20 09:31:18 -06:00
Jason Dove
3b135df4c1 scan with below-normal priority when unforced (#1123) 2023-01-20 06:05:39 -06:00
Jason Dove
4369d04940 scanner improvements (#1122)
* optimize periodic scanning

* set scanner process priority

* update dependencies
2023-01-20 05:37:39 -06:00
Jason Dove
faaa78fed7 update changelog [no ci] 2023-01-18 15:40:00 -06:00
Jason Dove
6bea1660ea disable mac compression; this is needed until dotnet 7.0.3 (#1120) 2023-01-18 15:13:07 -06:00
Jason Dove
8d46676c25 try to fix mac scanning (#1119) 2023-01-18 14:43:26 -06:00
Jason Dove
4c75e638a2 fix bug with smart collection progress (#1118) 2023-01-18 14:09:54 -06:00
Jason Dove
dd73a3803a fix schedule editor crash (#1115)
* fix schedule editor crash due to bad music video artist data

* update dependencies
2023-01-15 06:35:51 -06:00
Jason Dove
f6c345d7cf fix build 2023-01-10 15:13:42 -06:00
Jason Dove
585b56a668 bug fixes (#1107)
* don't search an empty search index

* fix bug with flood filler prediction check

* extract subtitles on primary worker thread
2023-01-10 14:45:04 -06:00
Jason Dove
f18f3b4f35 try to fix develop artifacts 2023-01-09 08:46:55 -06:00
Jason Dove
eb7871a048 fix alternate schedule playout update check (#1106)
* fix alternate schedule playout update check

* Revert "use mknejp/delete-release-assets again"

This reverts commit 07ac833067.
2023-01-09 05:36:15 -06:00
Jason Dove
000fc78fd3 add alternate schedule system (#1105)
* start to add program schedule alternates

* edit days of the week

* editor improvements

* save changes

* build playouts using alternate schedules

* reset playout as needed

* add priority message
2023-01-08 23:22:17 -06:00
Jason Dove
ba676ef956 add jellyfin admin error logging (#1102) 2023-01-07 09:55:02 -06:00
Jason Dove
36ea88e2d6 fix error display (#1099)
* fix error display by ignoring hw accel setting

* update changelog

* revert background change
2023-01-05 20:02:48 -06:00
Jason Dove
5237e6fa50 update changelog for release v0.7.2-beta [no ci] 2023-01-05 11:51:57 -06:00
Jason Dove
99bde1819c use mknejp/delete-release-assets again (#1098) 2023-01-05 10:26:42 -06:00
Jason Dove
f5d7ec2890 update workflow [no ci] 2023-01-05 10:06:32 -06:00
Jason Dove
13c65435d3 update dependencies (#1097) 2023-01-05 09:27:12 -06:00
Jason Dove
315420f1a5 fix log viewer on windows (#1095)
* fix log viewer on windows

* catch cancellation on trakt page

* update changelog
2023-01-04 22:26:35 -06:00
Jason Dove
ab7051f075 reimplement log viewer (#1094) 2023-01-04 10:09:11 -06:00
Jason Dove
a43e5bbe9d update changelog for release v0.7.1-beta [no ci] 2023-01-03 09:40:59 -06:00
Jason Dove
b7bd4541b1 hide windows on windows (#1091)
* hide windows on windows

* update dependencies
2023-01-03 09:14:50 -06:00
Jason Dove
648f25e9cc fix terminating server process 2023-01-01 14:20:52 -06:00
Jason Dove
ccbe85a46a also hide the main server window 2023-01-01 14:12:41 -06:00
Jason Dove
d168d79fe0 hide windows wrapper console (#1088) 2023-01-01 13:42:39 -06:00
Jason Dove
d37dde2477 try to fix windows build 2023-01-01 13:19:12 -06:00
Jason Dove
8e13b07c84 convert windows project from dotnet to rust (#1087)
* convert windows project from dotnet to rust

* update pr jobs

* pr job fixes

* don't bother building mac app in prs for now

* build windows wrapper with rust
2023-01-01 13:01:58 -06:00
Jason Dove
927e7724f0 fix search bug (#1086)
* fix removing media items from search index

* update changelog
2023-01-01 08:49:15 -06:00
Jason Dove
6558c5bd69 fix subtitle update bug (#1085)
* fix saving some subtitles to database

* fix ffprobe regression
2022-12-31 19:57:14 -06:00
Jason Dove
5f7efbb69c properly fall back to software pipeline (#1084) 2022-12-31 14:06:00 -06:00
Jason Dove
b79795af50 add debug logging to local subtitle provider (#1083) 2022-12-31 11:36:08 -06:00
Jason Dove
9479806cb0 scanner refactoring and other cleanup (#1082)
* move subtitles provider into scanner

* move more stuff into scanner

* move nfo into scanner

* add scan subcommand

* fix a bunch of nfo build warnings

* more subcommands

* fix warnings

* cleanup logging

* remove unused code

* cleanup old ffmpeg stuff

* rename complex filter

* refactor wrapped segmenter
2022-12-31 10:57:20 -06:00
Jason Dove
6e49ea78ec music video template contrib (#1081)
* add another music video template

* add more music video credit templates
2022-12-30 13:26:07 -06:00
Jason Dove
7b1edd9c54 add new scanner process (#1080)
* start moving local scans to separate process

* send progress updates to main process

* move scanners and tests

* simplify dependencies; sync search index

* commit search index more often when scanning

* support forced scan and cancellation

* use scanner process for plex libraries

* update changelog

* update dockerfiles

* fix search index for local folder scanning

* rework plex scanners

* rework scanner handlers

* emby works again

* sync jellyfin

* cleanup

* update build

* update changelog

* remove scanner dependency in pr and artifacts workflows

* fix mac sed syntax

* fix pr build
2022-12-30 12:53:05 -06:00
Jason Dove
aeaafd2964 add scanner subtitle logging (#1079) 2022-12-29 06:00:00 -06:00
Jason Dove
622fa01602 update dependencies and fix some types (#1077) 2022-12-28 14:21:25 -06:00
Jason Dove
e2b3c1ce8e properly unflag local movies that are now present on disk (#1076) 2022-12-28 13:41:01 -06:00
Jason Dove
6c5db650e7 nvidia pixel format and song fixes (#1075)
* fix nvidia pixel format edge case

* fix nvidia song playback
2022-12-24 20:39:22 -06:00
Jason Dove
731072425b fix nvidia pipeline that only requires setparams (#1074) 2022-12-24 13:19:27 -06:00
Jason Dove
0f817308a8 limit library scan interval (#1073)
* limit library scan interval

* fix condition
2022-12-24 12:58:38 -06:00
Jason Dove
0fc1e15cac colorspace fixes; song playback fixes (#1072)
* fix colorspace bug, vaapi song playback

* more colorspace fixes, nvidia fixes

* nvidia colorspace fixes

* fix some qsv output color metadata

* update changelog

* update changelog
2022-12-23 15:11:05 -06:00
Jason Dove
acf30384b7 update changelog [no ci] 2022-12-20 20:14:31 -06:00
Jason Dove
d2040eaac9 pipeline fixes when colorspace filter is used (#1068)
* fix colorspace filter with missing input transfer or input primaries

* properly download before applying colorspace filter

* fix extra hwupload/hwdownload with nvidia pipeline

* colorspace tests

* update dependencies
2022-12-20 20:12:27 -06:00
Jason Dove
93673fce03 add more logging to vaapi capabilities detection (#1059) 2022-12-15 19:32:48 -06:00
Jason Dove
d7a432068b fix arm docker builds 2022-12-15 14:26:00 -06:00
Jason Dove
cb9215980a fix dockerfiles, focal to jammy 2022-12-15 14:14:07 -06:00
Jason Dove
a4fc1f1c6f upgrade to dotnet 7, ffmpeg 5.1.2 (#1058)
* wip

* update dockerfiles

* more net6 to net7

* update dependencies

* update builds
2022-12-15 14:08:21 -06:00
Jason Dove
cbbdb11938 update changelog for release v0.7.0-beta [no ci] 2022-12-11 06:53:05 -06:00
Jason Dove
a2274bca7b detect vaapi capabilities (#1051)
* remove unused pipeline

* spike vaapi hardware capabilities

* more vaapi capabilities

* use proper vaapi driver

* update readme

* update dependencies
2022-12-10 14:10:19 -06:00
Jason Dove
f84496b09d extract attached fonts (#1050) 2022-12-09 22:22:15 -06:00
Jason Dove
3abf310a3b add amf pipeline (#1048) 2022-12-09 15:23:00 -06:00
Jason Dove
f12e361c2e fix videotoolbox color normalization (#1047) 2022-12-08 13:11:46 -06:00
Jason Dove
cd0f1e98cc fix qsv color normalization (#1046) 2022-12-08 08:17:59 -06:00
Jason Dove
325ef80951 normalize bit depth via new pipeline (#1045)
* fix subtitles test and nvidia subtitles

* new ffmpeg pipelines; software and nvidia

* partial qsv

* fix qsv

* fix software pipeline

* add vaapi pipeline

* fix qsv 10-bit h264 output

* nvidia fixes

* properly disable 10-bit h264 hardware encoders

* more nvidia fixes

* add video toolbox pipeline
2022-12-07 21:25:55 -06:00
Jason Dove
9a30d7c7da error report bug fixes (#1042)
* fix some potential null reference exceptions

* searching isn't actually async

* add search query breadcrumb
2022-12-03 05:47:04 -06:00
Jason Dove
25ea75b761 more color fixes (#1040) 2022-11-25 21:25:04 -06:00
Jason Dove
32edf77d35 fix bt709 check (#1039) 2022-11-25 10:09:58 -06:00
Jason Dove
47fbb2b1b7 properly unlock trakt (#1035) 2022-11-23 18:34:55 -06:00
Jason Dove
e388f81e1f re-enable bugsnag auto notification (#1034) 2022-11-22 20:09:25 -06:00
Jason Dove
f0bea295c4 add video stats to search index (#1033) 2022-11-22 09:35:28 -06:00
Jason Dove
7439ded43d normalize bit depth (#1031)
* normalize bit depth and color for nvenc

* fix hls direct

* update changelog

* add bit depth option to ffmpeg profile
2022-11-21 20:20:07 -06:00
Jason Dove
6a640d3708 fix ogg song metadata (#1030) 2022-11-20 12:44:08 -06:00
Jason Dove
776bce9087 use base path in channel playlist and channel guide (#1028) 2022-11-20 08:28:14 -06:00
Jason Dove
3c499f9e97 proper fix 2022-11-19 10:41:16 -06:00
Jason Dove
114ff7a3e3 fix develop build cleanup (#1027) 2022-11-19 10:16:12 -06:00
Jason Dove
527cdf523c fix work-ahead limit setting (#1023) 2022-11-16 21:17:23 -06:00
Jason Dove
91eb8ab824 try to fix develop release 2022-11-04 11:26:05 -05:00
Jason Dove
7a87fb1c2e fix removing emby and jellyfin libraries (#1011)
* fix removing jellyfin and emby libraries

* remove unneeded change
2022-11-04 06:25:51 -05:00
Jason Dove
d8cc6b4c22 fix audio stream selection (#1010) 2022-11-02 14:55:43 -05:00
Jason Dove
c9bd94d9f8 use javascript instead of lua for external scripts; add audio stream selector scripts (#1005)
* use js instead of lua

* update dependencies

* add audio stream selector script for episodes

* add audio stream selector script for movies

* update changelog
2022-10-28 17:05:07 -05:00
Jason Dove
93bf818882 fix syntax [no ci] 2022-10-22 11:20:42 -05:00
Jason Dove
723fb3848d try to fix release by skipping unnecessary step 2022-10-22 11:19:39 -05:00
Jason Dove
6a213e2249 update changelog for release v0.6.9-beta [no ci] 2022-10-21 21:15:43 -05:00
Jason Dove
a6c5c3a317 bump search index version 2022-10-21 15:21:33 -05:00
Jason Dove
9313d2c8eb fix guide mode filler in xmltv (#1000) 2022-10-16 13:23:26 -05:00
Jason Dove
485a874ab5 fix automatic playout reset (#999) 2022-10-16 10:30:54 -05:00
Jason Dove
f2bc884632 fix x-forwarded-proto (#998) 2022-10-13 13:16:51 -05:00
Jason Dove
39d6653f8e temporarily enable http logging (#997) 2022-10-13 12:58:15 -05:00
Jason Dove
2ce0fcb264 proxy server improvements (#996) 2022-10-13 12:17:13 -05:00
Jason Dove
8bf5e18ae5 fix nfo reader (#995)
* fix nfo reader

* fix template fade

* update dependencies
2022-10-13 05:08:41 -05:00
Jason Dove
88f4d8074a fix stream_seek type (#988)
* fix stream seek type

* cleanup
2022-10-09 21:20:34 -05:00
Jason Dove
f5aa2fcac8 add multi-episode shuffle playout order (#987) 2022-10-09 10:49:07 -05:00
Jason Dove
6f892bea6b optionally place watermark within source content (#986) 2022-10-09 08:16:59 -05:00
Jason Dove
cbf0c9c988 fix transcoding tests 2022-10-08 21:41:49 -05:00
Jason Dove
393c67213d add stream_seek to music video credits template (#985) 2022-10-08 19:45:24 -05:00
Jason Dove
f69de9f071 fix all_artists in music video credits template (#984) 2022-10-08 12:40:46 -05:00
Jason Dove
2e400c0d22 simplify music video credits config (#983) 2022-10-08 07:52:57 -05:00
Jason Dove
6035c10550 add music video credits template system (#982)
* add music video credits template system

* fix search index bug

* cleanup csproj
2022-10-07 21:02:29 -05:00
Jason Dove
555b156154 fix tail and fallback filler scheduling (#981) 2022-10-07 09:21:19 -05:00
Jason Dove
a0ea2e8910 update changelog for release v0.6.8-beta [no ci] 2022-10-05 11:09:03 -05:00
Jason Dove
734ca39cbd add guids to search index (#980) 2022-10-04 19:52:19 -05:00
Jason Dove
e0e5cfada5 fix numeric range search queries (#979) 2022-10-04 18:49:35 -05:00
Jason Dove
7e0c43bc46 update dependencies (#977) 2022-10-01 07:56:14 -05:00
Jason Dove
be1125a9ab properly sync updated file paths from plex (#976) 2022-09-30 20:41:32 -05:00
Jason Dove
d21c985a77 fix emby tag sync for movies and shows (#975) 2022-09-30 19:56:19 -05:00
Jason Dove
28f2b9b27e disable anamorphic edge case in scaling calculations (#971) 2022-09-26 15:11:05 -05:00
Jason Dove
9b185e19e9 fix other video search results when nfo metadata is used (#970)
* add debug no sync build config

* fix other video search results

* update dependencies
2022-09-25 22:27:34 -05:00
Jason Dove
27b923b462 qsv and vaapi scaling fixes (#966)
* add qsv device option to ffmpeg profile

* fix vaapi scaling

* cleanup
2022-09-18 21:02:09 -05:00
Jason Dove
357dfee050 nvidia and software mode scaling improvements (#965)
* convert to square pixels before software scaling

* convert to square pixels in nvidia scale filter

* more scaling fixes; position watermark within padded content

* fix image subtitle scaling

* fix qsv scaling

* update dependencies
2022-09-18 11:04:02 -05:00
Jason Dove
7f4004c228 fix qsv hevc encoder (#956)
* update dependencies

* fix typo in qsv hevc encoder param

* update changelog
2022-09-10 15:44:59 -05:00
Jason Dove
9b8dc0ed80 update changelog for release v0.6.7-beta [no ci] 2022-09-05 13:15:04 -05:00
Jason Dove
3cc1286271 include other videos (ungrouped) in shuffle in order (#953)
* include other videos (ungrouped) in shuffle in order

* fix id conflict
2022-09-05 09:20:11 -05:00
Jason Dove
df281758b7 properly fix infinite playout build loop (#952) 2022-09-05 08:41:39 -05:00
Jason Dove
25273c18c8 stop infinite playout building loop (#951) 2022-09-04 20:28:28 -05:00
Jason Dove
f1be945423 add qsv extra hardware frames setting (#950)
* wip add qsv extra_hw_frames setting

* fix ffmpeg profile editor

* update changelog
2022-09-04 18:07:03 -05:00
Jason Dove
9a4f772f53 fix image subtitle scaling (#949)
* properly scale image-based subtitles for nvidia and software

* fix vaapi image subtitle scaling

* fix qsv image subtitle scaling

* update changelog
2022-09-04 14:25:05 -05:00
Jason Dove
d669e8114b more scaling fixes (#948)
* remove force_original_aspect_ratio from scale_cuda

* remove force_original_aspect_ratio from scale_cuda

* fix qsv scaling

* fix qsv scaling on linux

* fix vaapi scaling edge cases

* update changelog
2022-09-03 20:28:18 -05:00
Jason Dove
3972e3603b add amf acceleration (#947) 2022-09-03 10:39:54 -05:00
dependabot[bot]
acc22fcb62 Bump MudBlazor from 6.0.14 to 6.0.15 (#945)
Bumps [MudBlazor](https://github.com/MudBlazor/MudBlazor) from 6.0.14 to 6.0.15.
- [Release notes](https://github.com/MudBlazor/MudBlazor/releases)
- [Changelog](https://github.com/MudBlazor/MudBlazor/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/MudBlazor/MudBlazor/compare/v6.0.14...v6.0.15)

---
updated-dependencies:
- dependency-name: MudBlazor
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-01 19:41:34 -05:00
Jason Dove
2df360d7fb fix xmltv filler bug (#944) 2022-08-31 20:15:25 -05:00
Jason Dove
46331ed2c6 add preferred audio title feature (#943)
* use consistent edit/delete icons

* add preferred audio title feature

* update dependencies
2022-08-30 17:04:41 -05:00
Jason Dove
3aee3b0515 fix windows build 2022-08-26 09:07:46 -05:00
Jason Dove
72c45692b2 update dependencies (#937) 2022-08-26 08:52:59 -05:00
Jason Dove
8edf71ca55 downgrade libva, include vainfo in docker (#936) 2022-08-25 16:29:20 -05:00
Jason Dove
612b9e6524 fix scanner crash caused by invalid mtime (#934) 2022-08-20 19:56:37 -05:00
Jason Dove
7aff65f07b explicitly copy all audio streams with hls direct (#933)
* ensure audio streams are always copied with hls direct

* update changelog
2022-08-18 14:23:51 -05:00
Jason Dove
5d350fcfad update changelog for release v0.6.6-beta [no ci] 2022-08-17 20:40:50 -05:00
Jason Dove
5546ad204c upgrade to ffmpeg 5.1 (#931)
* use ffmpeg 5.1 on windows

* remove some debug logs

* use latest ffmpeg on arm

* use ffmpeg 5.1 base images

* update ffmpeg health check for 5.1

* update changelog
2022-08-17 14:57:23 -05:00
Jason Dove
d66efa0a1d prioritize container aspect ratio over stream aspect ratio (#930)
* prioritize container aspect ratio over stream aspect ratio

* use setdar filter
2022-08-16 19:57:38 -05:00
Jason Dove
36d3d38530 remove all use of setsar filter (#928) 2022-08-16 12:25:59 -05:00
Jason Dove
8e79141860 use multi-variant playlists for hls segmenter (#926)
* use multi-variant playlists for hls segmenter

* use lowercase mime type
2022-08-13 19:58:08 -05:00
Jason Dove
9b3545f7ca add some temporary debug logging (#925) 2022-08-13 19:19:47 -05:00
Jason Dove
56db20faa0 limit segmenter delay to 8s (#924)
* always return initial hls playlist after 8 seconds

* update dependencies

* make fluentvalidation happy
2022-08-12 19:48:24 -05:00
Jason Dove
b0bd4c9fed add ogg file formats to local song library scanner (#914)
* add ogg file formats to local song library scanner

* update dependencies
2022-08-04 16:01:17 -05:00
Jason Dove
ba079452e2 add dff and dsf to local song library scanner (#911) 2022-08-03 11:01:13 -05:00
Jason Dove
f0f2b3da4b update changelog for release v0.6.5-beta [no ci] 2022-08-02 07:36:45 -05:00
Jason Dove
866049543c fix db initializer (#907) 2022-07-31 12:30:33 -05:00
Jason Dove
40ed4b8b0e update changelog for release v0.6.4-beta [no ci] 2022-07-28 12:23:33 -05:00
Jason Dove
b43d08ca67 fix repeating schedules (#901) 2022-07-26 13:04:05 -05:00
Jason Dove
5e7e386108 fix search result filtering for episodes and other videos (#900) 2022-07-25 20:02:07 -05:00
Jason Dove
4176df9940 fix nvidia capabilities for second-gen maxwell (#899) 2022-07-24 12:23:30 -05:00
Jason Dove
de2ef959fe add 640x480 resolution (#898)
* update dependencies

* add 640x480 resolution
2022-07-24 08:17:27 -05:00
Jason Dove
b53cfebac1 fix bug with unsupported aac channel layouts (#893)
* fix bug with unsupported aac channel layouts

* update dependencies
2022-07-14 10:52:25 -05:00
Jason Dove
6895b9cc6b fix search repo caching bug (#886)
* add failing test

* fix search repo bug

* update dependencies
2022-07-10 15:32:06 -05:00
Jason Dove
c60d6e46f1 fix changelog [no ci] 2022-07-04 15:23:26 -05:00
Jason Dove
c66d190174 update changelog for release v0.6.3-beta [no ci] 2022-07-04 15:20:53 -05:00
Jason Dove
5e8da591be update dependencies (#883)
* fix database initialization

* update dependencies
2022-07-02 20:42:07 -05:00
Jason Dove
9c02a6738b fix missing trashed episodes (#881)
* fix episodes missing from trash

* cleanup
2022-06-29 15:01:49 -05:00
Jason Dove
5ed0184bca add minimum log level setting (#877) 2022-06-27 10:29:04 -05:00
Jason Dove
ae64ca4a93 fix arm images by using ls55 (#876) 2022-06-26 17:41:39 -05:00
Jason Dove
c47099895e include item state in search index duplicate filter (#875) 2022-06-26 13:34:54 -05:00
Jason Dove
a2529febba use brew for gon 2022-06-26 08:30:32 -05:00
Jason Dove
521e0ba8b3 get a new build 2022-06-26 06:46:30 -05:00
Jason Dove
ee0efac9be only publish docs when docs are updated 2022-06-26 06:21:27 -05:00
Jason Dove
bfe7635489 work around github actions issue on mac (#874) 2022-06-25 19:30:21 -05:00
Jason Dove
aa1735f024 fix song and other video search index (#873) 2022-06-25 18:13:39 -05:00
Jason Dove
8deae983c7 add some startup log messages (#872) 2022-06-25 13:03:37 -05:00
Jason Dove
f349646703 apply plex episode metadata updates (#871)
* update more plex episode metadata

* update dependencies
2022-06-22 19:41:05 -05:00
Jason Dove
5003e80500 maintain stream continuity after playout reset (#868)
* maintain stream continuity after playout reset

* maintain continuity after error streams
2022-06-18 21:38:25 -05:00
Jason Dove
940d9cd6b5 update changelog for release v0.6.2-beta [no ci] 2022-06-18 13:46:45 -05:00
Jason Dove
197c166789 fix jellyfin admin id selection (#867) 2022-06-17 18:25:22 -05:00
Jason Dove
d114db091e use proper nvidia accel output format for 10-bit content (#865) 2022-06-17 11:33:10 -05:00
Jason Dove
3204da8e43 adjust nvidia capabilities (#864)
* adjust nvidia capabilities logic

* fallback to software encoding for 10-bit h264

* cleanup

* more tweaks
2022-06-17 10:50:36 -05:00
Jason Dove
100eb14408 fix epg sorting (#863)
* fix epg sorting

* update dependencies
2022-06-17 08:44:26 -05:00
Jason Dove
025017ace5 regularly delete old segments (#856)
* regularly delete old segments

* cleanup
2022-06-15 21:12:07 -05:00
Jason Dove
6a690c7c10 add more filler logging (#854) 2022-06-15 10:21:05 -05:00
Jason Dove
dd7f77751c detect nvidia capabilities (#853)
* fallback to software codecs for old nvidia cards

* update dependencies
2022-06-14 19:44:34 -05:00
Jason Dove
0c13b8ef1a force amd64 for arm32v7 sdk build layer (#843) 2022-06-12 13:54:55 -05:00
Jason Dove
c6ca58ab97 build arm32v7 docker image (#842)
* build arm32v7 docker image

* fix
2022-06-12 13:42:27 -05:00
Jason Dove
0846fc1d96 update workflow dependencies (#841) 2022-06-11 13:40:47 -05:00
Jason Dove
e41dd68ee0 fix automatic playout building (#840) 2022-06-11 13:11:04 -05:00
Jason Dove
0a92996da8 fix repeating content (#838)
* fix repeating content

* update dependencies
2022-06-08 10:37:56 -05:00
Jason Dove
082bc6145c update changelog for release v0.6.1-beta [no ci] 2022-06-03 15:05:06 -05:00
Jason Dove
bf3f16451b music video credits tweaks (#834)
* fix song subtitles

* always use generated subtitles

* file not found/unavailable fixes
2022-06-03 14:44:52 -05:00
Jake
3cb37003cb UI rewrite - ffmpeg profiles (#823)
* ffmpeg profile functionality, sweetalert2

* add new files

* cleanup controller; remove unused classes

* apply formatting

* cleanup core project

* don't use bom

* whitespace

* remove generated css

* remove generated js/map

* Remove attempted linter fix, channels button, watermarks page. Fixed handlerror.

* Changed deleted confirmation to toast.

* Localized strings for language change. Modified Action icons to buttons and left default sizes. Changed Cancel to No where Yes is an option

* lint

Co-authored-by: Jason Dove <jason@jasondove.me>
2022-06-03 06:28:32 -05:00
Jason Dove
9acfd2cd06 fix plex server identification (#833) 2022-06-03 05:53:41 -05:00
dependabot[bot]
3242e7ebb8 Bump HtmlSanitizer from 7.1.488 to 7.1.509 (#830)
Bumps [HtmlSanitizer](https://github.com/mganss/HtmlSanitizer) from 7.1.488 to 7.1.509.
- [Release notes](https://github.com/mganss/HtmlSanitizer/releases)
- [Commits](https://github.com/mganss/HtmlSanitizer/compare/v7.1.488...v7.1.509)

---
updated-dependencies:
- dependency-name: HtmlSanitizer
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-02 21:21:17 -05:00
Jason Dove
7644d628e7 generate music video credits (#832) 2022-06-02 20:50:55 -05:00
Jason Dove
b4f19e6de4 fix jellyfin tv paging (#831) 2022-06-02 12:16:59 -05:00
Jason Dove
0388425763 update changelog for release v0.6.0-beta [no ci] 2022-06-01 18:01:07 -05:00
Jason Dove
ca5d303ac7 fix qsv encoder regression and memory errors (#828)
* fix qsv encoders; only use 64 extra hw frames

* update changelog
2022-05-31 06:07:50 -05:00
Jason Dove
18e66a92ad add paging to media server show and collection calls (#827)
* add paging to media server show library calls

* add paging to media server season and episode library calls

* formatting

* add paging to media server collection calls

* add paging to media server collection item calls

* update changelog
2022-05-31 05:56:48 -05:00
Jason Dove
7d0a56ab98 disable lower-power mode for qsv encoders (#826) 2022-05-29 20:44:27 -05:00
Jason Dove
5069792d12 update dependencies 2022-05-28 20:41:54 -05:00
Jason Dove
c9789458b9 page media server movie libraries 2022-05-28 20:41:22 -05:00
Jason Dove
777a0d09ed hls segmenter fixes (#824)
* fix pts warning when channel first starts streaming

* rework playlist filtering
2022-05-25 21:05:55 -05:00
Jason Dove
4e2ebcc48a fix watermark opacity filter (#820) 2022-05-23 10:29:04 -05:00
Jason Dove
90fe1d7709 fix hw accel health check for qsv in vaapi docker (#818) 2022-05-22 19:42:14 -05:00
Jason Dove
1576dd026e enable qsv accel for vaapi docker images (#817) 2022-05-22 18:43:24 -05:00
Jason Dove
ee7a64eea9 fix other video libraries (#816)
* update depdendencies

* reset other video libraries
2022-05-22 12:29:35 -05:00
Jason Dove
9742e1eef7 update changelog for release v0.5.8-beta [no ci] 2022-05-20 09:11:16 -05:00
Jason Dove
a61c4b3472 fix a handful of scheduling edge cases (#814) 2022-05-18 06:00:58 -05:00
Jason Dove
ea0d43cf99 use hardware acceleration for error messages (#813)
* logging fixes

* use hardware acceleration for error messages
2022-05-18 05:44:01 -05:00
Jason Dove
fd36ea51a7 unlock ffmpeg thread count (#812)
* revert logging changes

* unlock ffmpeg thread count
2022-05-17 21:37:44 -05:00
Jason Dove
5213b71d62 add debug logging to track down playlist filtering issue (#811)
* add debug logging to track down playlist filtering issue

* revert work-ahead change
2022-05-17 15:18:12 -05:00
Jason Dove
0ba3ac7f50 fix more error stream settings (#810) 2022-05-17 11:44:12 -05:00
Jason Dove
d960fec734 error stream needs video track timescale (#809) 2022-05-17 10:26:46 -05:00
Jason Dove
f272036c6f reduce hls disk use (#808)
* reduce hls segmenter disk use

* logging improvements

* update dependencies
2022-05-17 08:43:28 -05:00
Jason Dove
9fe03b6ef3 reduce hls segmenter disk use (#806) 2022-05-16 21:45:13 -05:00
Jason Dove
f895ab5304 fix nuget versions 2022-05-14 06:37:22 -05:00
Jason Dove
07c54ff45f update changelog for release v0.5.7-beta [no ci] 2022-05-14 05:54:27 -05:00
Jason Dove
6a29ce2049 update dependencies (#805) 2022-05-13 21:16:43 -05:00
Jason Dove
d19e95fb38 add random start point option (#804) 2022-05-13 20:36:03 -05:00
Jason Dove
d78daf8735 fix flood checkpoints (#803) 2022-05-13 15:31:04 -05:00
Jason Dove
4f6522379d fix custom title scheduling (#802) 2022-05-13 13:06:05 -05:00
Jason Dove
9e0972fec0 properly ignore plex other videos libraries (#801) 2022-05-13 12:31:34 -05:00
Jason Dove
6d564233ed filler scheduling fix (#800) 2022-05-12 14:02:06 -05:00
Jason Dove
47252b1243 read track from music video nfo metadata (#799) 2022-05-12 12:31:40 -05:00
Jason Dove
bd5b52922d add option to allow watermarks over filler (#796) 2022-05-09 17:51:11 -05:00
Jason Dove
59c793b9be add option to skip missing items in playouts (#795) 2022-05-09 09:21:51 -05:00
Jason Dove
3ad1ba01f8 add autocomplete to search bar (#791) 2022-05-08 19:58:15 -05:00
Jason Dove
ab10f0ed81 add metadata_kind to search index (#790)
* more nfo cleanup

* add metadata_kind to search index
2022-05-07 21:24:50 -05:00
Jason Dove
44dd68fe59 nfo and memory fixes (#789)
* partial episode nfo metadata

* nfo metadata reliability fixes

* use recyclable memory streams
2022-05-07 20:32:57 -05:00
Jason Dove
6326189444 update changelog for release v0.5.6-beta [no ci] 2022-05-06 12:42:57 -05:00
Jason Dove
198c693208 fix other video fallback metadata 2022-05-05 20:51:24 -05:00
Jason Dove
1431b33a98 support movie nfo metadata in other video libraries (#788)
* add other video nfo metadata

* update docs
2022-05-05 20:38:23 -05:00
Jason Dove
e81a8e58ea fix error continuity (#787)
* fix fallback filler playback

* use new transcoder logic for errors

* use realtime option for error streams
2022-05-05 13:31:09 -05:00
Jason Dove
daf7114ce2 bug fixes and logging (#786) 2022-05-05 10:04:24 -05:00
Jason Dove
8542bc20b1 update dependencies (#785) 2022-05-04 20:45:19 -05:00
Jason Dove
9decb91bf7 use aired for music video release date (#784) 2022-05-04 11:36:00 -05:00
Jason Dove
fcfd579b37 fix search index validation (#782) 2022-05-03 22:26:44 -05:00
Jason Dove
e9be182bed bug fixes and search tweaks (#781)
* fix movie nfo processing

* fix local movie fallback metadata

* use imagesharp again

* fix search edge case

* add show_genre and show_tag to search index
2022-05-03 21:58:39 -05:00
Jason Dove
610e261cd7 update changelog again [no ci] 2022-05-03 10:23:57 -05:00
Jason Dove
f65818c838 update changelog for release v0.5.5-beta [no ci] 2022-05-03 10:22:10 -05:00
Jason Dove
1651d2895e update dependencies 2022-05-03 09:45:25 -05:00
Jason Dove
b90c536dcb try to fix quemu condition 2022-05-03 09:33:02 -05:00
Jason Dove
5c98eb3df5 more conditions 2022-05-02 22:46:22 -05:00
Jason Dove
bdff5eba75 fix conditions 2022-05-02 22:41:11 -05:00
Jason Dove
7d112eda05 fix tag 2022-05-02 22:28:54 -05:00
Jason Dove
4f16431ca0 use specific arm64v8 tags 2022-05-02 22:14:49 -05:00
Jason Dove
69b39c6940 try building arm64 docker image 2022-05-02 22:10:50 -05:00
Jason Dove
fe7181ea1d workflow fixes 2022-05-02 21:47:37 -05:00
Jason Dove
88b287a094 use matrix for docker build workflow 2022-05-02 21:44:35 -05:00
Jason Dove
7953e3ad85 actually fix windows tests [no ci] 2022-05-02 13:41:05 -05:00
Jason Dove
8ba6374165 music video nfo multiple artists (#780)
* support multiple artist entries in music video nfo metadata

* clean up other video and song etags
2022-05-02 12:32:15 -05:00
Jason Dove
973dd4b53d try to fix tests on windows again [no ci] 2022-05-02 05:54:56 -05:00
Jason Dove
6facd745ec fix extracting embedded mov_text subtitles (#777)
* fix extracting embedded mov_text subtitles

* changelog

* cleanup
2022-05-01 21:24:14 -05:00
Jason Dove
32c4c4ec8b fix failing tests on windows [no ci] 2022-05-01 14:11:55 -05:00
Jason Dove
ecb6ed37f0 more local metadata parsing improvements (#776)
* extract remaining nfo xml serializers

* add artist nfo tests

* add music video nfo tests

* add tv show nfo reader tests

* custom artist nfo reader

* custom music video nfo reader

* custom tv show nfo reader

* local metadata parsing cleanup

* update changelog
2022-05-01 14:00:10 -05:00
Jason Dove
2a8bf57930 ignore emby and jellyfin path infos with unset network path (#775) 2022-04-30 21:48:37 -05:00
Jason Dove
1ebc4b62e3 bug fixes (#774)
* add custom movie metadata parsing

* refactor episode nfo reader

* fix emby and jellyfin bugs
2022-04-30 17:39:47 -05:00
Jason Dove
4ae671b633 fix trashing episodes with no title (#773) 2022-04-29 21:49:23 -05:00
Jason Dove
87aa69f4cc update changelog for release v0.5.4-beta [no ci] 2022-04-29 17:59:12 -05:00
Jason Dove
404ea49e35 jellyfin and emby path infos (#771)
* start adding jellyfin path info; fix some scanning bugs

* sync jellyfin libraries before scanning to ensure latest path infos

* code cleanup

* support emby path infos

* fix periodic scanning of emby and jellyfin libraries

* bug fixes
2022-04-29 15:07:17 -05:00
Jason Dove
4ed40acfbe rebuild corrupt search index (#770) 2022-04-28 13:49:06 -05:00
Jason Dove
17f540dc99 add more search fields (#769) 2022-04-28 10:40:27 -05:00
Jason Dove
780ebc01ee add v2 ffmpeg profile page (#768)
* wip

* remove transcode property; use i18n

* add api

* use computed table headers for i18n
2022-04-28 06:56:01 -05:00
Jason Dove
0a0fb71b94 refactor plex, emby and jellyfin television scanners (#767)
* refactor plex television scanner

* refactor emby television scanner

* refactor jellyfin television scanner

* update changelog
2022-04-27 22:34:25 -05:00
Jason Dove
53d6ecae8d fix windows build 2022-04-27 14:20:14 -05:00
Jason Dove
837f311ec0 add more search fields (#766)
* properly index show and season state

* add height, width, season_number, episode_number to search index

* update docs
2022-04-27 13:58:33 -05:00
Jason Dove
a9a89d04ea optimize search-index rebuilding (#765)
* update dependencies

* optimize search-index rebuilding

* cleanup logging
2022-04-27 12:23:37 -05:00
Rafael Vieira
2e1073eb53 Add support to internationalization (#764)
* client-app: Improve development documentation

* client-app: add basic support to translation

* client-app: fix i18n and create lang state

* client-app: add language selector

* client-app: add translation EN and PT-BR
2022-04-27 10:58:27 -05:00
Jason Dove
7687278b80 health check fixes (#763) 2022-04-26 09:38:03 -05:00
Jason Dove
392aebd46f refactor movie library scanners (#761)
* catch health check cancellation

* local library scanner cleanup

* emby and jf library scanner cleanup

* rework emby movie library scanner

* refactor emby movie library scanner

* refactor jellyfin movie library scanner

* clear etag until after new media has been processed

* refactor plex movie library scanner

* update changelog
2022-04-25 20:31:12 -05:00
Jason Dove
0a4f6d9b62 update changelog for release v0.5.3-beta [no ci] 2022-04-24 13:45:29 -05:00
Jason Dove
d879ce0d0d bug fixes (#757)
* fix docker blur hash generation

* scanner async cleanup

* catch and log some unauthorized exception errors
2022-04-24 13:43:06 -05:00
Jason Dove
558e8acf5f unavailable improvements (#756)
* add unavailable health check

* improve file not found health check
2022-04-24 11:59:41 -05:00
Jason Dove
89a2ac9455 add unavailable media state for plex media (#754)
* rework plex movie library scanner; add unavailable media item state

* plex television scanner improvements

* reset plex etags as needed

* update changelog
2022-04-23 22:19:10 -05:00
Jason Dove
39c05a24d8 update changelog for release v0.5.2-beta [no ci] 2022-04-22 19:33:42 -05:00
Jason Dove
78383bd5fa override languages and subtitles on schedule items (#753) 2022-04-22 15:45:54 -05:00
Jason Dove
d67251bfa0 jellyfin and emby collection sync (#752)
* sync jellyfin and emby collections

* update changelog
2022-04-22 13:33:35 -05:00
Jason Dove
e91ec98007 fix season sync from jellyfin and emby (#751) 2022-04-21 21:36:09 -05:00
Jason Dove
097b8c3d1f subtitle fixes (#750)
* fix crash with missing metadata

* fix subtitles in docker

* fix software overlay bug
2022-04-21 20:17:50 -05:00
Jason Dove
7284ee9fb7 fix updating local season metadata 2022-04-21 15:42:10 -05:00
Jason Dove
fccb9003a0 add plex deep scan mode and sync labels (#749) 2022-04-21 14:02:37 -05:00
Jason Dove
cc9c2f6ae3 fix external subtitles with brackets in the filename (#748) 2022-04-21 10:25:21 -05:00
Jason Dove
ec6eab97b2 plex scanner improvements (#747)
* plex api cleanup

* improve plex movie scanner

* sync plex collections as tags

* improve plex tv library scanner

* update dependencies

* fix plex season and episode collection tags
2022-04-21 09:54:38 -05:00
Jason Dove
3ede136ff3 fix windows build 2022-04-20 16:10:13 -05:00
Jason Dove
7c27241ab6 properly reset emby and jellyfin libraries 2022-04-20 15:56:48 -05:00
Jason Dove
3713711864 support external subtitles (#745)
* support external subtitles in local movie libraries

* code cleanup

* simplify subtitle updating

* skip external subtitles from media servers

* fix plex subtitles
2022-04-20 15:54:53 -05:00
Jason Dove
d755d0ae29 sync subtitles from media server scanners (#744) 2022-04-19 21:24:36 -05:00
Jason Dove
c02b83d0d6 code cleanup (#743)
* update tools

* run code cleanup

* update dependencies
2022-04-19 17:47:18 -05:00
Jason Dove
e250e93a8e add support for embedded text subtitles (#742)
* first pass at text subtitle support

* support text subtitles from movies, music videos and other videos

* fixes

* qsv fixes

* vaapi fixes

* update changelog
2022-04-19 12:57:24 -05:00
Jason Dove
60965d0961 update changelog for release v0.5.1-beta [no ci] 2022-04-17 17:36:32 -05:00
Jason Dove
ff1a7b376f add empty trash button (#739) 2022-04-17 14:45:49 -05:00
Jason Dove
741b00fd52 fix multiple filler scheduling bugs (#738) 2022-04-17 13:30:47 -05:00
Jason Dove
7e55681916 fix cliwrap usage (#737) 2022-04-16 20:12:18 -05:00
Jason Dove
210630d299 subtitle fixes for software, videotoolbox, vaapi (#736)
* fix subtitles using software encoders

* videotoolbox fixes

* fix some vaapi subtitle edge cases
2022-04-16 16:06:49 -05:00
Jason Dove
0ddbb898d6 fix subtitle stream selection (#735) 2022-04-15 19:40:08 -05:00
Jason Dove
d6bf579436 fix alpha => beta versioning 2022-04-15 09:08:30 -05:00
Jason Dove
765df64555 add picture subtitle transcoding tests, and make them all pass with nvenc (#734) 2022-04-14 22:30:26 -05:00
Jason Dove
8764fb93fa update for release v0.5.0-beta [no ci] 2022-04-13 11:01:54 -05:00
Jason Dove
7d5c3e2384 update docs 2022-04-13 11:01:49 -05:00
Jason Dove
1ee3446589 add schedule item watermark setting (#733) 2022-04-12 21:01:20 -05:00
Jason Dove
af39d93442 more scheduling fixes (#732)
* fix skipping days with fixed start times

* fix playouts getting "stuck" on the same items

* rebuild all playouts

* update dependencies
2022-04-12 09:19:13 -05:00
Jason Dove
5d6a6d3a76 fix schedule anchors (#726) 2022-04-10 11:29:50 -05:00
Jason Dove
1f27aef11d allow two decimals in channel numbers (#724) 2022-04-05 20:44:50 -05:00
Jason Dove
ddb6d99cf9 remove sqlite startup messages (#723) 2022-04-03 23:37:38 -05:00
Jason Dove
d54766866e optimize image manipulation (#722)
* update dependencies

* use ffmpeg to resize images

* use ffprobe to check for animated logos and watermarks

* remove last use of imagesharp
2022-04-03 22:43:11 -05:00
Jason Dove
25bc500a2b ensure HDHR clients always get an MPEG-TS stream (#721) 2022-04-03 18:03:34 -05:00
Jason Dove
c2eec2fc2d playout rework to maintain collection progress (#720)
* initial work on maintaining playout state

* debugging wip

* fix refresh playout logic

* fix failing test

* more fixes

* update changelog

* comment out some debug logs

* comment out more logs
2022-04-02 21:19:59 -05:00
Jason Dove
f9781a4c05 detect and handle nonzero hls segmenter exit code (#719) 2022-04-01 20:27:40 -05:00
Jason Dove
df45b93819 burn in picture-based subtitles (#718)
* add subtitle mode setting

* start to add subtitle support

* cuda test

* move subtitle settings from ffmpeg profile to channel

* fix image-based subtitles

* experimental wip

* subtitle fixes
2022-03-31 18:15:57 -05:00
Jason Dove
e697fd36e9 remove legacy transcoder logic option (#717) 2022-03-31 16:00:50 -05:00
Jason Dove
0308106c1b update changelog for release v0.4.5-alpha [no ci] 2022-03-29 20:12:01 -05:00
Jason Dove
ba93e3eeea always check for plex on the localhost (#716) 2022-03-29 19:39:55 -05:00
Jason Dove
aa2c914d8a always transcode and normalize, except with HLS Direct (#715)
* remove transcode, normalize video, normalize audio settings

* cleanup

* update changelog
2022-03-28 18:25:33 -05:00
Jason Dove
caa9bf82d5 update changelog [no ci] 2022-03-28 13:10:33 -05:00
Jason Dove
e397035c5a update changelog [no ci] 2022-03-18 14:07:15 -05:00
Jason Dove
d32f881c4e use cliwrap for windows wrapper (#710) 2022-03-18 13:36:38 -05:00
Jason Dove
9b3c24559d add deinterlace option to ffmpeg profile (#709)
* update dependencies

* add option to deinterlace video
2022-03-18 10:30:56 -05:00
Jason Dove
7c75b169ec try gon again 2022-03-16 11:39:44 -05:00
Jason Dove
4f1952340f fix gon since brew is not working 2022-03-16 11:24:52 -05:00
Jason Dove
ac2de24f6e fix build 2022-03-16 10:50:38 -05:00
Jason Dove
4b9781dad4 add v2 channels table (#708)
* change mock api port; fix cors

* fix version request

* accept base url env var

* tweak colors

* fix version service

* add basic channels list

* fix auto page title for ts classes

* add GET /api/channels
2022-03-16 10:28:54 -05:00
Jason Dove
d88c179b63 axios test (#705)
* add version controller

* use axios to get version

* allow typescript

* use version api service
2022-03-15 17:55:05 -05:00
Jason Dove
809a623a95 vue formatting tweaks (#704)
* add .prettierrc

* apply formatting
2022-03-14 10:59:04 -05:00
Jason Dove
b453dce57e try npm ci with cache 2022-03-13 20:38:04 -05:00
Jason Dove
edd31755c0 try npm install again 2022-03-13 20:21:16 -05:00
Jason Dove
7de1a87bbf bug fixes (#703)
* catch expected shutdown error in scheduler service

* fix streaming mode inconsistencies
2022-03-13 18:45:21 -05:00
Jason Dove
5731edc82e v2 ui tweaks (#702)
* fix m3u and xml urls (kind of)

* use svg logos

* tweak theme colors
2022-03-13 12:44:35 -05:00
Jason Dove
2f668e53dd fix npm build (#701) 2022-03-13 11:11:08 -05:00
Jason Dove
abd223acd2 fix docker builds (#700) 2022-03-13 10:52:03 -05:00
Jason Dove
6a9075dc11 add vue ui at /v2 (#698)
* add vue ui

* add channels mock api

* Initial Vue framework with Vuetify UI (#688)

* fix hls direct streaming mode (#682)

* duration analysis on files with missing duration metadata (#683)

* first pass

* analyze zero-duration files

* add readme note for WIP

* add vuetify and basic sidebar layout - responsive

* add vue-router and initial home page

* setup composition-api for vue2

* install pinia ie... vuex4

* mixing for automatic page title

* add logo files

* tweak theme colors

* install store

* use store for menu toggle

* replicate old menu

* implement menu and children menus

* rename state to application state

* update vue files and add version to sidebar

* lock logo and make expandable list remove minified menu

* remove todo, will add to PR

* top bar links and attempt at snackbar with state

* fix snackbar

* add search basic component

* fix search bar placement

* remove un-used footer

* Revert "Merge branch 'jasongdove:main' into intitial-vuetify-ui"

This reverts commit 43016d502b.

Co-authored-by: Jason Dove <jason@jasondove.me>

* Add ESLint and Prettier for VueJS (#691)

* add prettier to config

* run npm run lint over project to clean up files

* replace hr tag with v-dividers

* add vue-lint github action

* fix the dodo in me

* Hu

* Fix path

* convert to multi-run step

* forgot the name

* add vue-lint github action

fix the dodo in me

Hu

Fix path

convert to multi-run step

forgot the name

* Fix new line at end of file

* WIP

* dockerfile consistency

* use npm ci and node v14

* force prettier indenting and end of line (#695)

* disable filename hashing

* don't build tests in docker

* update dependencies

* fix running both uis

Co-authored-by: James Mackay <info@notexpectedyet.com>
2022-03-12 14:15:31 -06:00
Jason Dove
d5a03963c0 use video and audio format instead of video and audio codec (#696) 2022-03-11 19:58:05 -06:00
Jason Dove
f3e5ff198b update changelog for release v0.4.4-alpha [no ci] 2022-03-10 17:54:39 -06:00
Jason Dove
6be5111195 fix errors; add nouveau vaapi driver option (#692)
* fix service shutdown errors

* add nouveau vaapi driver option
2022-03-10 12:19:30 -06:00
Jason Dove
f0670b345f use wrapped processes; fix hls pts bug (#690) 2022-03-09 14:38:09 -06:00
Jason Dove
6a1c2b7659 read ffprobe pts output from stdout and stderr (#689) 2022-03-09 08:54:51 -06:00
Jason Dove
7cd2f9a56f update dependencies (#687) 2022-03-08 20:21:10 -06:00
Jason Dove
f66bc783a7 fix hls segmenter on windows (#686) 2022-03-08 19:58:41 -06:00
Jason Dove
bc225d35fa add troubleshooting code to hls segmenter (#685) 2022-03-08 12:52:29 -06:00
Jason Dove
52a8b7db81 duration analysis on files with missing duration metadata (#683)
* first pass

* analyze zero-duration files
2022-03-07 21:42:34 -06:00
Jason Dove
dcd792a354 fix hls direct streaming mode (#682) 2022-03-07 20:04:21 -06:00
Jason Dove
f69c58c6bf update changelog for release v0.4.3-alpha [no ci] 2022-03-05 19:49:31 -06:00
Jason Dove
44e90b0ecc more bug reporting (#679) 2022-03-05 18:21:53 -06:00
Jason Dove
dcc8f19a6b remove transient IDbConnection (#678) 2022-03-05 14:06:27 -06:00
Jason Dove
fc1a051df5 fix path replacement bug (#677) 2022-03-05 12:21:26 -06:00
Jason Dove
a2e7e6df1e fix thread sync bug in hls segmenter (#676) 2022-03-05 11:26:29 -06:00
Jason Dove
6c06fbe621 fix mid-roll filler scheduling bug (#675) 2022-03-04 21:40:08 -06:00
Jason Dove
a3260b2316 fix album_artist metadata (#674) 2022-03-04 21:10:55 -06:00
Jason Dove
ea339a1622 add song album_artist metadata (#673) 2022-03-04 18:44:54 -06:00
Jason Dove
58697496fa metadata stack trace improvements (#672)
* improve stack traces from local metadata provider

* more metadata line number fixes
2022-03-04 15:44:51 -06:00
Jason Dove
ec1b2502f1 rework bugsnag integration (#671) 2022-03-03 21:39:46 -06:00
Jason Dove
1ab98578ab refactor namespaces and imports (#670)
* re-namespace

* optimize usings

* more usings

* more of the same

* more implicit/global usings

* cleanup all usings

* minor fixes
2022-03-03 15:36:07 -06:00
Jason Dove
748581bf5a update dependencies (#669) 2022-03-03 08:46:08 -06:00
Jason Dove
2058c44949 minor ui fixes (#668)
* remove unused package

* fix controller name

* catch and ignore jsruntime exceptions

* separate debug stage from public stage
2022-03-02 20:45:07 -06:00
Jason Dove
24ef5e68eb add error reporting health check (#667) 2022-03-02 14:51:15 -06:00
Jason Dove
b1c905233f add thank you page to docs [no build] 2022-03-02 09:19:54 -06:00
Jason Dove
452f361384 use cancellation tokens in ui (#666)
* use cancellation tokens in pages

* use cancellation token in shared ui

* use cancellation tokens in artwork controller
2022-03-01 21:31:48 -06:00
Jason Dove
9e2f445785 add bugsnag error reporting (#665) 2022-03-01 18:41:24 -06:00
Jason Dove
ea72e7b689 use new transcoder logic by default (#664) 2022-03-01 14:29:47 -06:00
Jason Dove
19a7f90d52 ffmpeg lib hardware accel fixes (#663)
* more scaling fixes

* qsv fixes

* cleanup

* nvidia fixes

* vaapi fixes

* test nvidia by default
2022-03-01 14:03:36 -06:00
Jason Dove
572a3be33e limit framerate normalization to 24fps and above (#662) 2022-02-28 19:22:11 -06:00
Jason Dove
f8412c4f5c more nvidia fixes (#661)
* dont use mpeg2_cuvid with interlaced content

* fix nvidia scaling when padding is not needed
2022-02-28 18:35:49 -06:00
Jason Dove
6b0ced6be9 fix nvidia watermark (#660)
* add watermark transcoding tests

* nvidia fixes

* update changelog
2022-02-28 14:21:42 -06:00
Jason Dove
19161b12ea fix chronological and shuffle-in-order song sorting (#659) 2022-02-28 13:41:22 -06:00
Jason Dove
fd3ef90880 update changelog for release v0.4.2-alpha [no ci] 2022-02-26 19:23:18 -06:00
Jason Dove
696b29c9e9 fix videotoolbox acceleration with new transcoder (#658)
* fix videotoolbox acceleration with new transcoder

* cleanup
2022-02-26 18:45:05 -06:00
Jason Dove
70c37df596 fix vaapi watermarks with new transcoder (#657) 2022-02-26 14:00:23 -06:00
Jason Dove
040785b0d7 fix qsv scaling and watermarks with new transcoder (#656)
* fix qsv scaling

* fix qsv watermarks
2022-02-26 11:40:16 -06:00
Jason Dove
b25f783343 hide unused local libraries (#655) 2022-02-25 21:16:38 -06:00
Jason Dove
a21f62ff8c add watermark support to experimental transcoder logic (#654)
* wip

* fix songs again

* don't use lists of video and audio input files

* test concat command output

* move concat pipeline

* start to use ffmpeg state

* add ffmpeg state and audio state

* audio state is required

* attach input options directly to input files

* move filters to input files

* add watermark support
2022-02-25 21:06:17 -06:00
Jason Dove
78fdc9c57a add option to shuffle schedule items (#652)
* add schedule setting

* it works

* fix tests

* update readme

* rebuild all playouts
2022-02-22 21:20:40 -06:00
Jason Dove
f6c42f3ff5 add configurable channel group and categories (#651) 2022-02-21 21:04:12 -06:00
Jason Dove
c92b6cb909 fix song playback (#644) 2022-02-17 21:52:28 -06:00
Jason Dove
a2e1dc8bfb don't deinterlace using nvidia decoders (#643) 2022-02-17 13:28:03 -06:00
Jason Dove
8a6093ce8d properly specify audio codec even when source has correct format (#641) 2022-02-16 11:29:54 -06:00
Jason Dove
1d6279cee8 log problematic playlists (#640) 2022-02-16 08:18:22 -06:00
Jason Dove
66ab0b3990 use single thread and disable framerate normalization (#639)
* try one thread for everything

* add (unused) framerate filter

* disable framerate normalization by default

* update dependencies
2022-02-16 06:01:28 -06:00
Jason Dove
a7922beaed qsv and logging fixes (#637)
* improve pipeline logging

* fix qsv acceleration

* fix qsv parameter order
2022-02-15 12:41:06 -06:00
Jason Dove
a1d9d6790e fix copy codec when transcoding is disabled (#636) 2022-02-15 09:22:40 -06:00
Jason Dove
2f2d7952dd use vaapi driver settings with new transcoder logic (#635)
* add LIBVA_DRIVER_NAME env var

* add vaapi device name

* add FFREPORT env var

* fixes
2022-02-15 08:44:49 -06:00
Jason Dove
c96b800b52 ffmpeg lib fixes (#633)
* try to fix vaapi inconsistencies

* log unexpected data

* vaapi fixes

* disable 444 test

* add qsv deinterlace filter; qsv fixes

* add videotoolbox acceleration
2022-02-14 22:01:26 -06:00
Jason Dove
c05882f4a6 fix docker builds 2022-02-14 14:36:35 -06:00
Jason Dove
5a442a06a0 start to use new ffmpeg library (#632)
* start to add ffmpeg library

* start to hook ffmpeg lib into main app

* improvements

* more progress

* make pipeline builder configurable

* more options

* move more logic down into ffmpeg lib

* ffmpeg lib desired state refactoring

* add software scaling and padding

* add loudness normalization and software deinterlace

* add metadata output options

* add setsar filter

* use built-in scaling logic

* fixes

* initial nvidia support

* nvidia improvements

* support hls mode

* print old arguments at debug level

* fix package reference

* start to add qsv support

* formatting

* fix tests

* add timeout to transcode tests

* show successful ffmpeg arguments

* add vaapi support

* add more software decoders

* add experimental transcoder option

* call existing ffmpeg process service for unimplemented features

* fix nvidia mpeg2video bug

* update changelog

* ignore some neglected unit tests
2022-02-14 14:34:00 -06:00
Jason Dove
640fed0a43 fix hls segmenter bug with unknown packet duration 2022-02-11 18:37:02 -06:00
Jason Dove
ab1f294c1f update changelog for release v0.4.1-alpha 2022-02-10 20:49:26 -06:00
Jason Dove
ea08453913 vaapi improvements (#629)
* fix interlaced video with vaapi

* downgrade imagesharp to fix blurhash generation

* fix ui crash loading collection editor
2022-02-10 20:19:59 -06:00
Jason Dove
87deaa6f3a nvidia improvements (#628) 2022-02-10 15:39:45 -06:00
Jason Dove
9d99c19ea4 fix playback with unknown pixel format (#627) 2022-02-10 08:37:25 -06:00
Jason Dove
49d14b05f6 update more dependencies (#626) 2022-02-09 11:08:49 -06:00
Jason Dove
a8ba9edf2b update dependencies (#624)
* update dependencies

* include refit xml serializer
2022-02-09 10:10:12 -06:00
Jason Dove
89811a1203 wait for one segment by default (#617) 2022-02-07 12:44:12 -06:00
Jason Dove
534e2c4512 add hls segmenter initial segment count (#616) 2022-02-07 12:18:58 -06:00
dependabot[bot]
c1e148633d Bump Blazored.LocalStorage from 4.1.5 to 4.2.0 (#614)
Bumps [Blazored.LocalStorage](https://github.com/Blazored/LocalStorage) from 4.1.5 to 4.2.0.
- [Release notes](https://github.com/Blazored/LocalStorage/releases)
- [Commits](https://github.com/Blazored/LocalStorage/compare/v4.1.5...v4.2.0)

---
updated-dependencies:
- dependency-name: Blazored.LocalStorage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-07 03:10:34 -06:00
Jason Dove
a9dff5eff7 properly flag local missing folders (#615) 2022-02-07 02:39:24 -06:00
Jason Dove
a2da043f4b try to fix mac permission issues 2022-02-06 17:45:28 -06:00
dependabot[bot]
252c185562 Bump MudBlazor from 6.0.5 to 6.0.6 (#609)
Bumps [MudBlazor](https://github.com/MudBlazor/MudBlazor) from 6.0.5 to 6.0.6.
- [Release notes](https://github.com/MudBlazor/MudBlazor/releases)
- [Changelog](https://github.com/MudBlazor/MudBlazor/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/MudBlazor/MudBlazor/compare/v6.0.5...v6.0.6)

---
updated-dependencies:
- dependency-name: MudBlazor
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-05 18:20:45 -06:00
Jason Dove
a47987a9d7 revert windows trimming (#613)
* Revert "disable trimming in docker"

This reverts commit 5937211bb8.

* Revert "try to reduce windows artifact size"

This reverts commit e32dbd0474.
2022-02-05 18:09:02 -06:00
Jason Dove
5937211bb8 disable trimming in docker 2022-02-05 13:41:47 -06:00
Jason Dove
e32dbd0474 try to reduce windows artifact size 2022-02-05 13:34:21 -06:00
Jason Dove
6bcc1ede2b try again 2022-02-05 11:25:14 -06:00
Jason Dove
6c9764a51e try a different method for downloading ffmpeg 2022-02-05 11:19:56 -06:00
Jason Dove
ff5438459c try to bundle ffmpeg with windows artifacts 2022-02-05 11:09:01 -06:00
Jason Dove
0c53a4509c show collection name in some error messages (#612) 2022-02-04 20:17:17 -06:00
Jason Dove
5fd315ead8 change framerate normalization method (#611) 2022-02-04 14:39:27 -06:00
Jason Dove
f02b0ac345 re-introduce framerate normalization (#610) 2022-02-04 12:57:40 -06:00
Jason Dove
fd83007296 try to fix watermark on vaapi 2022-02-01 17:50:47 -06:00
Jason Dove
70ca5bf050 fix bug with watermark and short content (#608) 2022-01-31 14:07:12 -06:00
Jason Dove
eed9f60273 fade in and fade out intermittent watermarks (#607)
* first pass at fading in/out overlay

* fix tests

* update changelog
2022-01-31 12:31:56 -06:00
Jason Dove
0e2e6cd52e build linux-arm64 artifacts 2022-01-31 01:07:03 -06:00
Jason Dove
c9b557f2e6 more xmltv category improvements (#606) 2022-01-30 17:58:45 -06:00
Jason Dove
cde869f3eb enable docker dependency scanning [no build] 2022-01-30 11:50:16 -06:00
Jason Dove
90d6a59d3f normalize smart quotes in search queries (#605) 2022-01-30 11:09:32 -06:00
Jason Dove
b972947747 xmltv category improvements (#604) 2022-01-30 10:56:53 -06:00
Jason Dove
17bc988b49 update changelog for release v0.4.0-alpha [no ci] 2022-01-29 18:22:07 -06:00
Jason Dove
749eea836b update install docs for tray apps (win, mac) [no build] 2022-01-29 18:18:58 -06:00
Jason Dove
37c52c4cb4 update docs and dependencies (#603) 2022-01-29 18:08:05 -06:00
Jason Dove
33ba58aa68 add windows launcher (#602) 2022-01-29 17:58:11 -06:00
Jason Dove
5f6043e593 index added date (#601) 2022-01-29 14:47:58 -06:00
Jason Dove
96e95a21fb update changelog [no ci] 2022-01-29 12:34:10 -06:00
Jason Dove
9168fd6bf2 write text file logs (#600) 2022-01-29 12:31:22 -06:00
Jason Dove
14413f62a7 properly sent content root on macos 2022-01-29 11:49:38 -06:00
Jason Dove
34c71a0c12 try to fix static resource loading 2022-01-29 10:20:03 -06:00
Jason Dove
a487e7fe15 use absolute paths in bundle script 2022-01-28 22:11:50 -06:00
Jason Dove
cd4ea42597 fix bundle script 2022-01-28 22:05:20 -06:00
Jason Dove
a3d42145f7 update macos submodule 2022-01-28 21:57:16 -06:00
Jason Dove
261cf5052a fetch submodules for mac build 2022-01-28 21:48:29 -06:00
Jason Dove
de9af2f0f6 first pass at native macos app 2022-01-28 21:41:26 -06:00
Jason Dove
8d4e18ed2f update mac app icon (#599) 2022-01-28 19:46:34 -06:00
Jason Dove
1ee01c1d78 fix hls timestamps (#598) 2022-01-27 23:51:18 -06:00
Jason Dove
7de50dd916 minor hls segmenter improvements (#593) 2022-01-26 20:12:29 -06:00
Jason Dove
744fd3beaa link file not found health check to trash (#592)
* update dependencies

* fix file not found health check
2022-01-26 08:37:40 -06:00
Jason Dove
861c95e1bd fix m3u mode override (#590) 2022-01-25 18:36:54 -06:00
Jason Dove
bb5b9f9be4 update changelog for release v0.3.8-alpha [no ci] 2022-01-23 21:46:00 -06:00
Jason Dove
135628441a re-add mac launcher script 2022-01-23 21:09:04 -06:00
Jason Dove
4aa7204984 fix ts mode with hdhr clients (#588) 2022-01-23 18:58:15 -06:00
Jason Dove
1af59a0337 don't use macos launcher script 2022-01-23 18:47:00 -06:00
Jason Dove
c4c97fcc8c customize mac dmg 2022-01-23 18:36:31 -06:00
Jason Dove
9c46e42792 fix gon variables 2022-01-23 14:21:13 -06:00
Jason Dove
efa803aab6 split mac artifacts job 2022-01-23 14:10:57 -06:00
Jason Dove
6ea02a2d77 use proper version number in ci artifacts [no docs] [no build] 2022-01-23 14:04:13 -06:00
Jason Dove
631f7d2d5e don't use reserved secret name 2022-01-23 13:54:37 -06:00
Jason Dove
e44a4cb2e1 properly pass secrets between workflows 2022-01-23 13:53:31 -06:00
Jason Dove
f4b95419a6 properly pass data between jobs 2022-01-23 13:46:47 -06:00
Jason Dove
1a5cf49563 refactor reusable docker workflow (#587)
* refactor reusable docker workflow

* refactor reusable artifacts workflow

* fix name

* try to fix

* fix
2022-01-23 13:42:01 -06:00
Jason Dove
efef0b0fee don't use single file for mac bundles 2022-01-22 17:29:35 -06:00
Jason Dove
ee7b8a71ab fix docker builds [no build] 2022-01-22 14:19:49 -06:00
Jason Dove
e7c9a51e96 macos app bundle (#585)
* test signed app bundle

* fix vars

* fix condition

* typo

* fix quoting

* use recursive signing script

* fix release cleanup

* restore proper ci action
2022-01-22 14:03:42 -06:00
Jason Dove
78a954f365 link to development builds in install docs 2022-01-21 20:55:38 -06:00
Jason Dove
355c0b7be9 try to fix deleting old assets 2022-01-21 20:29:50 -06:00
Jason Dove
3bcb2d36f9 another attempt at publishing artifacts 2022-01-21 20:21:26 -06:00
Jason Dove
b240de9d4a publish develop artifacts to stable release url 2022-01-21 18:44:25 -06:00
Jason Dove
f5001837cb properly separate build artifacts 2022-01-21 18:20:51 -06:00
Jason Dove
6ea916b1f0 fix fetch depth 2022-01-21 15:30:40 -06:00
Jason Dove
db6fd22215 try to fix build 2022-01-21 15:25:03 -06:00
Jason Dove
691842008d upload develop binaries for every merge to main (#584)
* upload develop binaries for every merge to main

* rename step
2022-01-21 15:18:08 -06:00
Jason Dove
685f78bef8 fix search results bug (#583) 2022-01-21 14:05:09 -06:00
Jason Dove
3ce267863b fix hls segmenter in some cultures (#582) 2022-01-21 10:42:33 -06:00
Jason Dove
e4231cb57d upgrade from ffmpeg 4.4 to 5.0 (#581) 2022-01-20 20:57:38 -06:00
Jason Dove
03946b13ca always use a single ffmpeg thread with realtime (#580) 2022-01-20 14:53:13 -06:00
Jason Dove
f1a81bf086 clarify library kind/media kind support (#579) [no docker] 2022-01-19 09:11:23 -06:00
Jason Dove
7a88374362 clarify flood scheduling calc [no ci] 2022-01-18 18:22:46 -06:00
Jason Dove
663a62431b properly fix startup paths (#576) 2022-01-17 16:31:22 -06:00
Jason Dove
1d4acc284d Update changelog for release v0.3.7-alpha [no ci] 2022-01-17 15:23:39 -06:00
Jason Dove
0440f7643b add videotoolbox acceleration (#575) 2022-01-17 15:05:23 -06:00
Jason Dove
0f4219f731 properly unlock libraries after failed scans (#574) 2022-01-14 13:03:15 -06:00
Jason Dove
cbe5d47611 fix trakt list sync when show does not contain a year (#572) 2022-01-12 21:09:26 -06:00
Jason Dove
afa52ccc89 add trash system for local libraries (#571)
* flag local movies as file not found

* show warning icon on cards

* unflag movie that is found during scan

* skip missing files when building playouts

* add state to search index

* add file not found health check

* link to search from file not found health check

* support flagging other media kinds as file not found

* continue to schedule missing items

* support episode files not found

* wip trash page

* fix trash url

* trash page is functional

* update changelog

* fix changelog merge
2022-01-12 20:27:53 -06:00
Jason Dove
7d1163c68f fix double-click startup on mac (#570) 2022-01-11 15:36:12 -06:00
Jason Dove
883492bd33 update changelog for release v0.3.6-alpha [no ci] 2022-01-10 19:51:01 -06:00
Jason Dove
a4eac4feea properly overwrite environment variables (#567) 2022-01-08 10:01:22 -06:00
Jason Dove
dab58f5840 fix tests 2022-01-07 19:18:31 -06:00
Jason Dove
176f136c23 fix some nvenc edge cases where only padding is needed for normalization (#565) 2022-01-07 18:53:28 -06:00
Jason Dove
816d77e15b update changelog [no ci] 2022-01-06 12:01:25 -06:00
Jason Dove
7c4d47a211 update changelog [no ci] 2022-01-06 10:31:18 -06:00
Jason Dove
d9d2cfa8be search index fixes (#559)
* add music video artist to search index

* properly index minutes field when adding from scan

* bump search index version
2022-01-06 10:28:53 -06:00
Jason Dove
8036e46966 update streaming mode docs (#558) [no docker] 2022-01-06 09:10:12 -06:00
Jason Dove
594ce437fb rework mpeg-ts mode (#557) 2022-01-05 21:27:28 -06:00
Jason Dove
004c43f895 update changelog for release v0.3.5-alpha [no ci] 2022-01-05 09:26:58 -06:00
Jason Dove
257384ea9b fix health checks (#556)
* update bundled ffmpeg version in health check

* recognize qsv acceleration on linux

* update changelog
2022-01-05 08:29:52 -06:00
Jason Dove
637f3a0c8b update docs [no docker] 2022-01-04 22:38:52 -06:00
Jason Dove
7346808059 update dependencies (#555) 2022-01-04 22:35:14 -06:00
Jason Dove
4210d97ee2 optimize setsar filter (#553) 2022-01-02 23:47:07 -06:00
Jason Dove
6a8ecd2532 use software decoding for mpeg4 with vaapi (#550) 2022-01-02 10:59:08 -06:00
Jason Dove
9b834f7cbe update changelog for release v0.3.4-alpha [no ci] 2021-12-21 09:46:43 -06:00
Jason Dove
7b73677bad allow ffmpeg reports on windows (#547)
* enable troubleshooting reports on windows

* update changelog

* tweak changelog
2021-12-21 09:27:49 -06:00
Jason Dove
85b2a46353 update dependencies (#546) 2021-12-21 08:52:51 -06:00
Jason Dove
6f40f2cbd6 fix songs docs [no docker] 2021-12-17 08:48:40 -06:00
Jason Dove
b62ee4dee9 add files from top-level folder (#541) 2021-12-14 14:27:12 -06:00
Jason Dove
a6e7f192cc add jellyfin path replacement tests [no ci] 2021-12-13 06:25:37 -06:00
Jason Dove
59a1a4a8dc update changelog for release v0.3.3-alpha [no ci] 2021-12-12 23:53:12 -06:00
Jason Dove
85a9afb51c update dependencies (#538) 2021-12-12 23:51:57 -06:00
Jason Dove
246b4d7591 properly sort channels in m3u (#537) 2021-12-10 20:22:52 -06:00
Jason Dove
ae2c6350e1 sync virtual shows and season from jellyfin (#536) 2021-12-10 14:41:47 -06:00
Jason Dove
ce228604e8 use select controls instead of autocomplete (#532)
* use select instead of autocomplete for playout editor

* use select instead of autocomplete for filler preset editor

* reset selected collection when changing collection type

* use select instead of autocomplete for multi collection editor

* more select

* more select controls
2021-12-06 12:49:48 -06:00
Jason Dove
3656e932d3 more song fixes (#529)
* use blurhash for default etv song backgrounds

* fix saving artwork blurhash

* fix song detail alignment

* rename song background files

* watermark path is always none here
2021-12-04 13:30:25 -06:00
Jason Dove
73887706ed update changelog for release v0.3.2-alpha [no ci] 2021-12-03 14:57:19 -06:00
Jason Dove
abc103308b optimize song artwork scanning (#527) 2021-12-03 13:40:55 -06:00
Jason Dove
3773bbec19 use blurhash for song backgrounds (#526)
* generate blurhash for all local artwork

* use blurhash song background if available

* only write blur hash to disk once

* use multiple blur hashes

* update changelog

* fix song detail outline

* reset song metadata (artwork)
2021-12-03 12:30:47 -06:00
Jason Dove
e223d6a43f remove unused cli project (#525) [no ci] 2021-12-02 09:01:47 -06:00
Jason Dove
8369111e31 update dependencies (#524) 2021-12-02 08:45:43 -06:00
Jason Dove
35ba2bab2c fix unicode song metadata on windows (#523)
* test setting utf8 encoding with ffprobe

* use utf8 encoding for console (logging) output

* use proper sink package

* reset song metadata on windows

* fix nfo processing with missing year

* update changelog
2021-12-01 13:43:09 -06:00
Jason Dove
094ed71ad0 fix docker builds with custom (local) nuget package (#520) 2021-11-30 20:49:02 -06:00
Jason Dove
89e24b2b78 use custom log database backend that is more portable (#519) 2021-11-30 20:34:14 -06:00
Jason Dove
848795af32 fix artwork upload on windows (#518)
* update changelog for release v0.3.1-alpha [no ci]

* fix artwork upload on windows
2021-11-30 12:23:24 -06:00
Jason Dove
56f94f489a fix filler playout crash (#517) 2021-11-30 10:38:42 -06:00
Jason Dove
475dc7660b fix artwork uploads (#516) 2021-11-29 14:34:18 -06:00
Jason Dove
db3dfbd446 disambiguate song search results (#515) 2021-11-27 21:37:55 -06:00
Jason Dove
b4c9cdbbfa use embedded song cover art (#514) 2021-11-27 21:08:18 -06:00
Jason Dove
7f84933c0b index song genres (#513)
* add song genres to search index

* reset all song genre metadata

* update changelog and docs
2021-11-27 18:08:55 -06:00
Jason Dove
1e35e9a5b0 use subtitles to display errors (#512)
* use subtitles to display errors

* fix margin calculation
2021-11-27 12:25:30 -06:00
Jason Dove
7edf6f5d13 song cleanup (#511)
* refactor song background logic

* move song video generation

* move subtitle generation

* build ASS subtitles

* randomize song detail layout

* update changelog
2021-11-27 11:15:53 -06:00
Jason Dove
919325033d use subtitles instead of drawtext for songs (#510) 2021-11-26 21:39:10 -06:00
Jason Dove
2cb5252320 fix song banding (#509)
* increase spacing in song details; uniformly darken to eliminate banding

* this isn't needed anymore
2021-11-26 15:20:41 -06:00
Jason Dove
015232fad6 song improvements (#508)
* fix song details margin and use dynamic font size

* sometimes use cover art color for song background
2021-11-26 13:23:28 -06:00
Jason Dove
af51b790b6 randomize cover art placement (#507) 2021-11-26 09:21:00 -06:00
Jason Dove
9195ef7878 song fixes (#506)
* fix song page links

* show song artist in playout detail

* show more song details in channel guide
2021-11-26 08:49:04 -06:00
Jason Dove
dfc4c7a284 update changelog for release v0.3.0-alpha [no ci] 2021-11-25 20:49:23 -06:00
Jason Dove
a6b15f68c9 randomize default backgrounds (#504)
* randomize default song backgrounds

* update docs
2021-11-25 20:19:26 -06:00
Jason Dove
0edfb71f8d limit disk use and keep cover art aspect ratio (#502)
* use temp file pool to limit disk use

* keep aspect ratio and crop when scaling cover art for blurred background

* fix typo
2021-11-25 18:47:22 -06:00
Jason Dove
21b90a1b6c fix songs with white backgrounds (#501) 2021-11-25 15:36:40 -06:00
Jason Dove
1582f5dd15 update changelog [no ci] 2021-11-25 13:37:33 -06:00
Jason Dove
fd3b72525d fix vaapi songs (#500) 2021-11-25 13:35:57 -06:00
Jason Dove
55d1871d94 re-enable hardware acceleration for songs (#499) 2021-11-25 13:04:13 -06:00
Jason Dove
a90eb2d4de optimize generated video (#498)
* use different framerate flags

* pre-generate song image and always use software encoders

* fix tests
2021-11-25 12:31:57 -06:00
Jason Dove
ed3f1b1dad generate song video (#497)
* use blurred cover art as song background

* use channel watermark when cover art is unavailable

* add drawtext to song filter

* cleanup

* force song cover art as png

* fix songs on windows and qsv
2021-11-25 06:22:38 -06:00
Jason Dove
8e08ff059f load embedded song metadata (#495)
* load embedded song metadata

* index song artist and song album

* reset all song metadata
2021-11-24 07:31:34 -06:00
Jason Dove
fb8c3a0453 disable autoscale when looping with vaapi or qsv (#494) 2021-11-23 13:25:23 -06:00
Jason Dove
e45fb67769 bug fixes (#493)
* don't align audio when playing songs

* fix grouping duration items in epg
2021-11-23 11:44:39 -06:00
Jason Dove
3a40d6ce77 fix local library locking when adding paths (#492) 2021-11-23 10:54:34 -06:00
Jason Dove
ac048b72ae add cover art watermark source (#491)
* add cover art watermark source

* update changelog
2021-11-23 10:02:36 -06:00
Jason Dove
852728c816 add songs libraries (#490)
* first pass at adding song libraries

* start handling optional video

* fix song playback

* fix song transitions

* add songs page to UI
2021-11-22 22:26:06 -06:00
Jason Dove
096f2d42e8 properly fix database upgrade (#489) 2021-11-22 17:56:29 -06:00
Jason Dove
1b29e252ff update changelog for release v0.2.5-alpha [no ci] 2021-11-21 07:24:20 -06:00
Jason Dove
a4dc9bfb31 Ignore local plex guids (#488)
* ignore local plex guids

* update dependencies
2021-11-21 06:25:56 -06:00
Jason Dove
184c21a91b optimize trakt matching (#487) 2021-11-21 06:13:28 -06:00
Jason Dove
6ea3191cf8 fix playout building (#486) 2021-11-20 22:36:15 -06:00
Jason Dove
d487bbca08 include other video title in channel guide (#483) 2021-11-16 08:46:07 -06:00
Jason Dove
05034b47e2 update changelog for release v0.2.4-alpha [no ci] 2021-11-13 12:54:41 -06:00
Jason Dove
b0c85b6478 use scale_cuda instead of scale_npp (#481) 2021-11-13 09:06:02 -06:00
Jason Dove
f1356563da fix ef shared table warnings (#480) 2021-11-10 18:03:28 -06:00
Jason Dove
c0aad028a8 more dotnet 6 updates (#479) 2021-11-09 13:09:57 -06:00
Jason Dove
dae06ec0ef upgrade to dotnet 6 (#475) 2021-11-09 07:44:34 -06:00
Jason Dove
72f452fd36 update dependencies (#474) 2021-11-09 06:16:26 -06:00
Jason Dove
aaf832c0b6 update changelog for release v0.2.3-alpha [no ci] 2021-11-03 13:53:06 -05:00
Jason Dove
08a18daf23 movie scanner should respect .etvignore files (#468) 2021-11-03 05:47:29 -05:00
Jason Dove
90c1c61a09 fix bug with flood playout mode (#467) 2021-11-02 21:47:46 -05:00
Jason Dove
053db71d44 fix decimal separator in ffmpeg apad filter syntax (#464) 2021-11-01 22:18:06 -05:00
Jason Dove
11f90f5d44 update changelog for release v0.2.2-alpha [no ci] 2021-10-30 17:49:30 -05:00
Jason Dove
bda4117655 allow per-episode folders in local show libraries (#462)
* allow per-episode folders in local show libraries

* fix subfolder etag generation
2021-10-30 12:54:07 -05:00
Jason Dove
3240703840 fix build 2021-10-30 12:24:27 -05:00
Jason Dove
53a7570ba3 fix epg for multiple playout mode (#461) 2021-10-30 12:16:39 -05:00
Jason Dove
0e789fd6d8 update dependencies and fix languageext deprecation warnings (#460) 2021-10-30 11:57:50 -05:00
Jason Dove
0136de700c add global and channel fallback filler (#459)
* configure channel and global fallback filler

* play random item from configured channel/global fallback filler as needed
2021-10-30 11:45:40 -05:00
Jason Dove
2ea0e64ac1 fix duration schedule item epg (#455) 2021-10-24 22:00:21 -05:00
Jason Dove
5993f23ec5 update changelog for release v0.2.1-alpha [no ci] 2021-10-24 19:46:33 -05:00
Jason Dove
417f35a834 fix saving dynamic start time (#453) 2021-10-24 18:18:22 -05:00
Jason Dove
a74547997d scheduling fixes (#451)
* scheduling fixes

* restore plex service

* restore plex service part 2
2021-10-24 06:49:35 -05:00
Jason Dove
a2f74dd284 update changelog for release v0.2.0-alpha [no ci] 2021-10-23 20:18:01 -05:00
Jason Dove
373daf9ce6 add basic filler docs [no docker] 2021-10-23 20:14:10 -05:00
Jason Dove
68693cffa0 use info log level for search index migration 2021-10-21 20:43:17 -05:00
Jason Dove
6d147de2f3 filler rework (#449)
* add chapter statistics and new filler options

* refactor playout builder

* more refactor prep for filler

* rewrite schedulers

* refactor collectionkey

* add tail filler kind

* migrate tail filler to filler preset

* optionally show filler

* fix playout detail row count

* remove duration tail filler options

* implement tail and fallback in flood scheduler

* implement tail and fallback in one scheduler

* implement tail and fallback in multiple scheduler

* implement looping fallback filler

* more duration tests

* start to add post-roll filler to flood

* rework playoutitem filler tagging

* rework scheduler logging

* calculate whether configured filler will fit

* implement pre-roll and post-roll duration and count filler

* improve duration filler calculation

* add minutes to search index

* update channel guide to work with new filler

* add mid-roll filler

* don't clone enumerators for filler calculations

* support pre-roll and post-roll pad filler

* implement mid-roll pad filler

* allow clearing filler selections in schedule editor

* fix tests

* filler config validation

* use consistent time zone for tests
2021-10-21 20:23:14 -05:00
Jason Dove
f4a63a1a1a fix deleting jellyfin and emby movies (#447)
* fix deleting jellyfin and emby movies

* revert jf service change
2021-10-19 14:33:48 -05:00
Jason Dove
bc9d17ca25 show path replacement logs by default (#445) 2021-10-19 06:32:00 -05:00
Jason Dove
42e13cbbaf fix generated streams with mpeg2video (#444) 2021-10-18 19:51:50 -05:00
Jason Dove
6cc61f3212 update changelog for release v0.1.5-alpha [no ci] 2021-10-18 17:55:34 -05:00
Jason Dove
4cf44616a8 Include music video thumbnail in epg (#443)
* include music video thumbnail in epg

* update changelog
2021-10-18 17:53:58 -05:00
Jason Dove
33aaadae68 multiple fixes to duration mode (#442) 2021-10-18 16:21:32 -05:00
Jason Dove
fe3f8e391e fix updating jellyfin and emby artwork (#440) 2021-10-17 05:36:00 -05:00
Jason Dove
1a68dd040a find working plex connection on startup (#438) 2021-10-16 11:55:54 -05:00
Jason Dove
67761c1a14 fix updating jellyfin and emby tv seasons (#437)
* fix updating jellyfin and emby tv seasons

* update changelog
2021-10-16 09:05:08 -05:00
Jason Dove
1802f9d797 fix database migration (#436) 2021-10-15 11:31:40 -05:00
Jason Dove
69354c9296 fix double scheduling (#435) 2021-10-15 09:14:53 -05:00
Jason Dove
0021e21b50 fix other video playback 2021-10-14 22:53:32 -05:00
Jason Dove
cdf7765059 update changelog for release v0.1.4-alpha [no ci] 2021-10-14 15:00:24 -05:00
Jason Dove
71658c448f update docs (#431) 2021-10-14 14:41:12 -05:00
Jason Dove
3ecdd741a5 add guide mode to schedule items (#430) 2021-10-14 13:24:54 -05:00
Jason Dove
0daeb844b9 add other videos library kind (#429) 2021-10-14 12:58:37 -05:00
Jason Dove
22da19845b add filler option to duration playout mode (#428)
* add duration tail options to schedule items editor

* add naive filler scheduling

* fix duration item length in xmltv

* show offline image for unfilled duration tail

* fix tests

* update changelog

* update dependencies
2021-10-13 21:15:16 -05:00
Jason Dove
3a6d9e9f39 update changelog for release v0.1.3-alpha [no ci] 2021-10-13 15:17:23 -05:00
Jason Dove
7ed4b8ae3c fix startup bug (#426) 2021-10-13 13:30:26 -05:00
Jason Dove
be7311e620 update changelog for release v0.1.2-alpha [no ci] 2021-10-12 19:00:30 -05:00
Jason Dove
03be372070 update changelog [no ci] 2021-10-12 18:57:02 -05:00
Jason Dove
d196308ee9 fix ffmpeg profile editing (#421) 2021-10-12 18:39:51 -05:00
Jason Dove
3d68b0f055 fix vaapi migration 2021-10-12 18:22:09 -05:00
Jason Dove
37e32f06ad update changelog [no ci] 2021-10-12 17:56:56 -05:00
Jason Dove
c43ca2837d support radeon vaapi acceleration (#420) 2021-10-12 17:51:55 -05:00
Jason Dove
992121f308 add more watermark locations (#419) 2021-10-12 07:19:52 -05:00
Jason Dove
04adbfeffa add hls segmenter settings to optimize performance (#418)
* add hls segmenter settings to optimize performance

* use consistent setting defaults
2021-10-12 06:31:11 -05:00
Jason Dove
1fc905c6ad upgrade vaapi to ffmpeg 4.4 (#417) 2021-10-11 22:26:32 -05:00
Jason Dove
4b5dff2159 ffnvcodec fixes (#416) 2021-10-11 22:14:43 -05:00
Jason Dove
2a5edf8214 ffmpeg 4.4 llvm nvidia fixes (#415) 2021-10-11 21:31:59 -05:00
Jason Dove
69912c8cae support ffmpeg 4.4 (#414)
* support ffmpeg 4.4

* update changelog
2021-10-11 20:16:15 -05:00
Jason Dove
fd3de2d82a nvidia 10 bit fixes (#413) 2021-10-11 16:00:35 -05:00
Jason Dove
6ba9404752 nvidia transcoding improvements (#412)
* nvidia transcoding fixes

* use yadif_cuda to deinterlace
2021-10-10 22:40:43 -05:00
Jason Dove
db080375c5 update changelog for release v0.1.1-alpha [no ci] 2021-10-10 12:54:46 -05:00
Jason Dove
9abc7ad8b7 try to fix tests on windows 2021-10-10 12:39:08 -05:00
Jason Dove
9e531a82d7 add some hls playlist filter tests (#411) 2021-10-10 12:33:02 -05:00
Jason Dove
d84bd2b948 upgrade nvidia docker image (#410) 2021-10-10 11:45:02 -05:00
Jason Dove
d7d3ec1235 add music video album to search index (#409)
* add music video album to search index

* update search docs
2021-10-10 10:28:35 -05:00
Jason Dove
742ac21ad7 update collection docs [no docker] 2021-10-10 07:53:29 -05:00
Jason Dove
819b55e21f increase max hls segments (#408) 2021-10-10 06:47:24 -05:00
Jason Dove
cf5718c288 rework hls segmenter (#407)
* rework hls segmenter to start more quickly

* don't use realtime encoding for hls until we're at least a minute ahead

* ugly but functional playlist filtering
2021-10-09 22:46:38 -05:00
Jason Dove
adc7982955 reduce initial hls segmenter delay (#406) 2021-10-09 10:26:57 -05:00
Jason Dove
67a6f554d0 rename v0.0.63-alpha v0.1.0-alpha [no ci] 2021-10-08 18:44:49 -05:00
Jason Dove
609df217ae update changelog for release 63 [no ci] 2021-10-08 18:39:03 -05:00
Jason Dove
d3086264c7 unraid doc fixes (#405) 2021-10-08 18:31:22 -05:00
Jason Dove
8cd9b23787 fix transcode folder preparation (#404) 2021-10-08 15:29:19 -05:00
dependabot[bot]
dc5c9e42ff Bump Serilog.Settings.Configuration from 3.2.0 to 3.3.0 (#403)
Bumps [Serilog.Settings.Configuration](https://github.com/serilog/serilog-settings-configuration) from 3.2.0 to 3.3.0.
- [Release notes](https://github.com/serilog/serilog-settings-configuration/releases)
- [Changelog](https://github.com/serilog/serilog-settings-configuration/blob/dev/CHANGES.md)
- [Commits](https://github.com/serilog/serilog-settings-configuration/commits)

---
updated-dependencies:
- dependency-name: Serilog.Settings.Configuration
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-08 09:09:57 -05:00
Jason Dove
2dd267e4db fix xmltv generation with missing episode metadata (#402) 2021-10-07 22:31:46 -05:00
Jason Dove
b069a21473 allow hls segmenter to run before framerate is known (#401) 2021-10-07 22:07:54 -05:00
Jason Dove
6c8813ce22 add hls segmenter streaming mode (#400)
* hls segmenter wip

* log message

* close unused transcode sessions after 2 minutes

* use frame rate for 2s keyframes in hls segmenter

* add frame rate to media version

* fix segmenter framerate calculation

* automatically restart hls segmenter with next scheduled item

* cleanup

* update changelog

* decrease segmenter start delay
2021-10-07 21:42:29 -05:00
Jason Dove
b5de5e2b7f fix statistic updates (#399) 2021-10-07 19:56:41 -05:00
Jason Dove
4b7da4e468 speed up builds by using base images (#398) 2021-10-06 06:06:13 -05:00
Jason Dove
ae8e795228 vaapi downsample 10bit hevc 8bit h264 (#397)
* vaapi downsample 10bit hevc to 8bit h264

* update changelog
2021-10-05 22:16:57 -05:00
Jason Dove
334781485d use latest intel driver in vaapi docker images (#396)
* compile latest iHD driver

* cleanup to reduce image size

* update changelog
2021-10-05 20:24:26 -05:00
Jason Dove
27fefa1b38 update changelog for release 62 [no ci] 2021-10-05 15:28:45 -05:00
Jason Dove
fc3175591e use libx264 for all errors (#395) 2021-10-05 15:13:35 -05:00
Jason Dove
3363d2c9d7 update plex paths when they are changed (#394) 2021-10-05 06:27:05 -05:00
Jason Dove
1d5217fa84 support imdb ids from plex (#393) 2021-10-05 06:01:53 -05:00
Jason Dove
904cdb8780 vaapi improvements (#392)
* add transcoding tests

* dont use full paths for transcoding tests

* add error details

* use 1-second videos for transcoding tests

* vaapi fixes

* include format in scale_vaapi

* more vaapi fixes

* unsupported errors

* fix unsupported checks

* maybe not failure?

* fix formatting

* ignore nvdec warnings

* update changelog

* fix tests
2021-10-02 13:42:44 -05:00
Jason Dove
85fee64565 update changelog [no ci] 2021-10-01 13:44:04 -05:00
Jason Dove
13cfb9728f include season zero episode-num in xmltv (#391) 2021-10-01 13:42:46 -05:00
Jason Dove
60b82876ea mudblazor updates (#390) 2021-09-30 17:40:26 -05:00
Jason Dove
a99249c375 revert nvenc changes (#389) 2021-09-30 17:35:44 -05:00
Jason Dove
36e6ef4c18 update changelog for release 60 2021-09-25 15:12:47 -05:00
Jason Dove
21e53532c1 trakt season bug fixes (#386) 2021-09-25 14:55:42 -05:00
Jason Dove
a864d53327 add seasons to search index (#385)
* update trakt list items when re-adding existing list

* add seasons to search index
2021-09-25 14:01:35 -05:00
Jason Dove
e6446f9983 better trakt lists (#384)
* better trakt list support

* update dependencies

* revert unneeded brackets
2021-09-25 09:12:25 -05:00
Jason Dove
ad40213f90 fix synchronizing trakt lists that contain unreleased movies (#382) 2021-09-21 21:14:27 -05:00
Jason Dove
45c6d20fd0 sync trakt list to collection (#381)
* sync trakt list to collection

* move trakt client id
2021-09-20 18:46:03 -05:00
Jason Dove
5439db89a7 nvidia fixes (#380)
* nvidia fixes

* fix tests
2021-09-19 21:39:36 -05:00
Jason Dove
a39231bb5a fix local episode metadata update (#379) 2021-09-19 20:57:12 -05:00
Jason Dove
4c8584b517 try to fix develop versioning 2021-09-18 18:08:19 -05:00
Jason Dove
ca8bcacbd3 update changelog for release 59 [no ci] 2021-09-18 14:35:01 -05:00
Jason Dove
f27286d1dd properly disable transcoding when unchecked in mpeg-ts mode (#378)
* properly disable transcoding in MPEG-TS mode

* update changelog
2021-09-18 14:21:49 -05:00
Jason Dove
23870b75f7 update changelog [no ci] 2021-09-18 14:02:49 -05:00
Jason Dove
7f5a91c643 include libva-x11-2 in vaapi docker image 2021-09-18 13:25:01 -05:00
Jason Dove
f1f50e883c add vaapi driver setting and health check (#377)
* add vaapi driver option

* add vaapi driver setting and health check
2021-09-18 13:00:36 -05:00
Jason Dove
7506f49f5b remove codeql [no docker] 2021-09-18 11:30:16 -05:00
Jason Dove
944f1e4307 add scheduled playout rebuild (#376)
* configure scheduled playout rebuild

* implement scheduled playout rebuild

* remove variable
2021-09-18 11:23:58 -05:00
Jason Dove
f7de9ac5ea include intel-media-va-driver-non-free in vaapi image (#375)
* include intel-media-va-driver-non-free in vaapi image

* tweak changelog
2021-09-17 21:13:27 -05:00
Jason Dove
1eb51ad2f4 add some health checks to home page (#374) 2021-09-17 17:59:59 -05:00
Jason Dove
c3e0aaf0b7 missing metadata fixes (#373) 2021-09-17 08:53:41 -05:00
Jason Dove
b9912b47df update changelog for release 58 [no ci] 2021-09-15 21:53:34 -05:00
Jason Dove
55fb2624e7 add multi-part grouping tooltip (#371) 2021-09-15 21:18:41 -05:00
Jason Dove
8ced20dc39 dont offset collections during shuffle in order (#370) 2021-09-15 20:54:32 -05:00
Jason Dove
e718cb0faf fix building playouts in timezones with positive offsets (#368) 2021-09-15 09:07:35 -05:00
Jason Dove
e218ff9a6d fix watermark when no video filters are required (#367) 2021-09-15 05:12:23 -05:00
Jason Dove
c2a49cbaea update dependencies (#365) 2021-09-14 18:10:59 -05:00
Jason Dove
17e74f7314 add more release date search options (#362) 2021-09-12 18:32:38 -05:00
Long-Man
2032bb4777 Update search.md (#361)
Add release_date and released_nointhelast to music video search
2021-09-12 12:18:07 -05:00
Jason Dove
7877ec641e update changelog for release 57 [no ci] 2021-09-11 10:37:23 -05:00
Jason Dove
767a9779bb more kodi artwork fixes (#360) 2021-09-11 10:08:33 -05:00
Jason Dove
bb9127e546 fix artwork in kodi (#359) 2021-09-11 09:45:09 -05:00
Jason Dove
c932577cb8 allow adding smart collections to multi collections (#358) 2021-09-11 09:29:20 -05:00
Jason Dove
ad2685fb2e add released_inthelast queries (#357) 2021-09-10 21:11:14 -05:00
Jason Dove
96bc2c28f2 update changelog for release 56 [no ci] 2021-09-10 13:59:14 -05:00
Jason Dove
a076b3eb30 add shuffle-in-order support to all collections (#356) 2021-09-10 13:33:04 -05:00
Jason Dove
fc360602ad add smart collections (#355)
* start to add smart collections

* add smart collection table; delete smart collection

* overwrite smart collections

* support scheduling smart collections

* update changelog
2021-09-10 11:58:24 -05:00
Jason Dove
d8b4d00a73 clarify changelog [no ci] 2021-09-09 08:22:46 -05:00
Jason Dove
0638ac8a5e more missing metadata fixes (#354)
* more missing metadata fixes

* update mudblazor
2021-09-09 06:38:46 -05:00
Jason Dove
f1f09bd4cb fix sorting episodes without metadata (#353) 2021-09-08 22:12:47 -05:00
Jason Dove
f6680f29e7 try to fix doc formatting [no docker] 2021-09-07 13:36:25 -05:00
Jason Dove
1c0413452b fix m3u xmltv mapping 2021-09-07 06:34:17 -05:00
Jason Dove
77308a9ac5 generate valid xmltv (#351) 2021-09-07 06:12:13 -05:00
Jason Dove
3ea8193bb3 update changelog for release 55 [no ci] 2021-09-03 08:56:25 -05:00
Jason Dove
8ad8680027 update dependencies; fix unnecessary table scrolling (#347) 2021-09-03 06:22:50 -05:00
Jason Dove
640044814c ignore dot-underscore files (#346) 2021-09-03 06:22:33 -05:00
Jason Dove
18b5313a53 update docs [no docker] 2021-08-22 20:17:39 -05:00
Jason Dove
8417c3f6cd update changelog for release 54 [no ci] 2021-08-21 13:19:13 -05:00
Jason Dove
32fdb414fa add "shuffle in order" playback order for multi-collections (#338)
* add "shuffle in order" option for multi-collections

* use balanced shuffle instead of random
2021-08-21 12:47:22 -05:00
Jason Dove
d3fc820aef update dependencies (#336)
* update dependencies

* fix fluent assertions
2021-08-21 06:23:43 -05:00
Jason Dove
9d07627781 fix ffprobe parsing in some cultures (#337) 2021-08-21 05:57:39 -05:00
Jason Dove
d3c8914758 update dependencies (#331) 2021-08-14 07:20:09 -05:00
Jason Dove
3d7ec59088 update changelog for release 53 [no ci] 2021-08-01 12:37:10 -05:00
Jason Dove
d78976f80a update changelog [no ci] 2021-08-01 12:22:32 -05:00
Jason Dove
0f5fee99c6 always proxy jellyfin and emby artwork (#323) 2021-08-01 12:19:50 -05:00
dependabot[bot]
d5bfd1a254 Bump MudBlazor from 5.0.15 to 5.1.0 (#321)
Bumps [MudBlazor](https://github.com/Garderoben/MudBlazor) from 5.0.15 to 5.1.0.
- [Release notes](https://github.com/Garderoben/MudBlazor/releases)
- [Changelog](https://github.com/Garderoben/MudBlazor/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/Garderoben/MudBlazor/compare/v5.0.15...v5.1.0)

---
updated-dependencies:
- dependency-name: MudBlazor
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-28 05:37:38 -05:00
Jason Dove
cd2558e3e6 fix jellyfin and emby links (#320) 2021-07-27 18:26:12 -05:00
Jason Dove
c39654ca40 update changelog for release 52 [no ci] 2021-07-22 11:26:05 -05:00
Jason Dove
f17151bd20 fix multi-collection bug (#318) 2021-07-22 11:12:14 -05:00
Jason Dove
6aeaf65a13 update docs [no docker] 2021-07-20 20:13:21 -05:00
Jason Dove
9fbe950e6e support multiple local libraries (#317)
* allow multiple local libraries

* add "move library path" function
2021-07-20 07:47:12 -05:00
Jason Dove
c9baff2cd5 add codeql workflow [no docker] 2021-07-18 07:36:41 -05:00
3933 changed files with 2499814 additions and 45080 deletions

View File

@@ -0,0 +1,167 @@
---
name: ersatztv
description: ErsatzTV custom IPTV channel management — REST API, SQLite DB, Jellyfin integration, FFmpeg profiles. Use when managing custom TV channels.
---
# ErsatzTV Channel Management
Container: `ersatztv` | Port: `8409` | IP: `172.16.238.11` (may change on restart)
Web UI: internal only (`http://localhost:8409` via SSH)
SQLite DB: `~/downloadswarm/ersatztv/ersatztv.sqlite3` on jazz (owned by root — use `sudo sqlite3`)
Image: `ghcr.io/ersatztv/ersatztv:latest` (v26.3.0, repo archived Feb 2026)
## Architecture
ErsatzTV uses **MediatR + Blazor** (not REST for mutations). The REST API is limited:
- **GET endpoints**: channels, collections, schedules, playouts, shows, movies, artists, ffmpeg profiles, health, search, watermarks
- **POST endpoints**: library scan, playout reset, show scan
- **No REST CRUD for channels/collections/schedules** — must use SQLite DB directly
## REST API
```bash
# Via docker exec
docker exec ersatztv curl -s http://localhost:8409/api/ENDPOINT
```
### Read Endpoints (GET)
```
/api/channels # List channels
/api/collections # List collections
/api/schedules # List schedules
/api/playouts # List playouts
/api/shows # List shows
/api/movies # List movies
/api/artists # List artists
/api/search # Search items
/api/ffmpeg/profiles # FFmpeg profiles
/api/watermarks # Watermarks
/iptv/channels.m3u # M3U playlist (for Jellyfin)
/iptv/xmltv.xml # XMLTV guide data
```
### Mutation Endpoints (POST)
```bash
# Library scan
POST /api/libraries/{id}/scan
# Scan single show
POST /api/libraries/{id}/scan-show \
-H "Content-Type: application/json" -d '{"ShowTitle":"Name","DeepScan":false}'
# Reset channel playout (rebuilds schedule)
POST /api/channels/{channelNumber}/playout/reset
```
## SQLite DB Operations
```bash
# Read queries (safe while running, WAL mode)
sudo sqlite3 ~/downloadswarm/ersatztv/ersatztv.sqlite3 "QUERY"
# Write queries — stop container first
docker stop ersatztv
sudo sqlite3 ~/downloadswarm/ersatztv/ersatztv.sqlite3 "QUERY"
docker start ersatztv
```
### Key Queries
```sql
-- List channels
SELECT Id, Number, Name FROM Channel ORDER BY CAST(Number AS INTEGER);
-- List collections with item counts
SELECT c.Id, c.Name, COUNT(ci.Id) as items FROM Collection c LEFT JOIN CollectionItem ci ON ci.CollectionId = c.Id GROUP BY c.Id;
-- List schedules
SELECT Id, Name FROM ProgramSchedule;
-- Playout (channel-schedule links)
SELECT p.Id, c.Number, c.Name, ps.Name as Schedule FROM Playout p JOIN Channel c ON p.ChannelId = c.Id LEFT JOIN ProgramSchedule ps ON p.ProgramScheduleId = ps.Id;
-- Media counts
SELECT 'Shows' as type, COUNT(*) FROM Show UNION ALL SELECT 'Movies', COUNT(*) FROM Movie UNION ALL SELECT 'Episodes', COUNT(*) FROM Episode UNION ALL SELECT 'MusicVideos', COUNT(*) FROM MusicVideo;
-- Jellyfin source
SELECT jms.Id, jc.Address, jms.ServerName FROM JellyfinMediaSource jms JOIN JellyfinConnection jc ON jc.JellyfinMediaSourceId = jms.Id;
-- Library sync status
SELECT l.Id, l.Name, l.MediaKind, jl.ShouldSyncItems FROM Library l JOIN JellyfinLibrary jl ON jl.Id = l.Id;
```
### Channel Setup Workflow (DB)
**Show-specific channel** (single TV show, shuffled):
```sql
-- 1. Schedule
INSERT INTO ProgramSchedule (Id, FixedStartTimeBehavior, KeepMultiPartEpisodesTogether, Name, RandomStartPoint, ShuffleScheduleItems, TreatCollectionsAsShows)
VALUES (<id>, 0, 0, '<name>', 1, 0, 1);
-- 2. Schedule item (CollectionType=1 for Show, PlaybackOrder=3 for Shuffle)
INSERT INTO ProgramScheduleItem (Id, CollectionType, FillWithGroupMode, GuideMode, "Index", MarathonGroupBy, MarathonShuffleGroups, MarathonShuffleItems, MediaItemId, PlaybackOrder, ProgramScheduleId)
VALUES (<id>, 1, 0, 0, 0, 0, 0, 0, <show_id>, 3, <schedule_id>);
INSERT INTO ProgramScheduleOneItem (Id) VALUES (<item_id>);
-- 3. Channel
INSERT INTO Channel (Id, Categories, FFmpegProfileId, FallbackFillerId, "Group", IdleBehavior, IsEnabled, MirrorSourceChannelId, MusicVideoCreditsMode, MusicVideoCreditsTemplate, Name, Number, PlayoutMode, PlayoutOffset, PlayoutSource, PreferredAudioLanguageCode, PreferredAudioTitle, PreferredSubtitleLanguageCode, ShowInEpg, SongVideoMode, SortNumber, StreamSelector, StreamSelectorMode, StreamingMode, SubtitleMode, TranscodeMode, UniqueId, WatermarkId)
VALUES (<id>, '', 1, NULL, '<category>', 0, 1, NULL, 0, NULL, '<name>', '<number>', 0, NULL, 0, NULL, NULL, 'eng', 1, 0, <number>.0, NULL, 0, 4, 2, 0, lower(hex(randomblob(4)))||'-'||lower(hex(randomblob(2)))||'-4'||substr(lower(hex(randomblob(2))),2)||'-'||lower(hex(randomblob(2)))||'-'||lower(hex(randomblob(6))), 1);
-- 4. Playout
INSERT INTO Playout (Id, ChannelId, ProgramScheduleId, ScheduleKind, Seed)
VALUES (<id>, <channel_id>, <schedule_id>, 0, abs(random()) % 1000000);
```
**Collection-based channel** (multiple shows, shuffled):
```sql
-- 1. Collection + items (MediaItemId = Show.Id)
INSERT INTO Collection (Id, Name, UseCustomPlaybackOrder) VALUES (<id>, '<name>', 0);
INSERT INTO CollectionItem (CollectionId, MediaItemId) VALUES (<coll_id>, <show_id>);
-- 2. Schedule (same as above but CollectionType=0, CollectionId set instead of MediaItemId)
INSERT INTO ProgramScheduleItem (Id, CollectionId, CollectionType, ..., PlaybackOrder, ProgramScheduleId)
VALUES (<id>, <coll_id>, 0, ..., 3, <schedule_id>);
-- 3-4. Channel + Playout same as show-specific
```
After creating: `POST /api/channels/{number}/playout/reset`
## Volume Mounts (matches Jellyfin)
| Host Path | Container Path |
|-----------|---------------|
| `~/downloadswarm/ersatztv` | `/config` |
| `/mnt/teramind/episodes` | `/data/tvshows` (ro) |
| `/mnt/episodes` | `/data/episodes` (ro) |
| `/mnt/media/movies` | `/data/movies` (ro) |
| `/mnt/media/standup` | `/data/standup` (ro) |
| `/mnt/media/music_videos` | `/data/music` (ro) |
## FFmpeg & Hardware
- QSV (Intel Quick Sync) hardware acceleration
- Resolution: 1920x1080, H264, AAC stereo
- Device: `/dev/dri` passed through
- HardwareAccelerationKind: 0=None, 1=Qsv, 2=Nvenc, 3=Vaapi, 4=VideoToolbox, 5=Amf
## Jellyfin Integration
- Secrets: `/config/jellyfin-secrets.json` (`{"Address":"http://jellyfin:8096","ApiKey":"978033be716d46678a5d3c54ae0e0ff9"}`)
- Libraries: Movies(10), TV Shows(11), Music Videos(8), Standup(9)
- `JellyfinLibrary.ShouldSyncItems` must be `1` for scans to work
## Gotchas
- DB owned by root — always use `sudo sqlite3`
- WAL mode: reads OK while running, stop container for writes
- No REST API for channel/collection/schedule CRUD — DB scripting only
- Secrets file uses PascalCase JSON (`Address`, `ApiKey`)
- Scanner is separate binary (`ErsatzTV.Scanner`) — check with `docker top ersatztv | grep Scanner`
- EF TPT inheritance: `ProgramScheduleItem` has subtype tables (`ProgramScheduleOneItem`, etc.) — MUST insert into subtype table
- External URL logos work for M3U but NOT for watermark burn-in (code checks `File.Exists()`)
- `/api/health` returns Blazor HTML, not JSON — use `/api/channels` to verify API
- PlaybackOrder enum: 3=Shuffle, 6=SeasonEpisode (use 3 for all channels)
- CollectionType enum: 0=Collection, 1=Show (direct show reference via MediaItemId)
- SubtitleMode: 0=None, 2=Burn-in. Set to 2 with PreferredSubtitleLanguageCode='eng' for non-music channels
- MediaItem.State: 0=Normal, 1=FileNotFound — clean up state=1 items by deleting cascading deps
- ProgramSchedule required NOT NULL columns: FixedStartTimeBehavior, KeepMultiPartEpisodesTogether, RandomStartPoint, ShuffleScheduleItems, TreatCollectionsAsShows
- Channel required NOT NULL columns: SongVideoMode (set 0), plus all standard columns (see Channel table schema)
- After schedule changes, rebuild playout: `POST /api/channels/{number}/playout/reset`
- Playout `ScheduleKind` must be `1` (not `0`/None) — `0` causes "Cannot build playout type None" error
- M3U `tvg-logo` URLs hardcode `http://localhost:8409` — Jellyfin can't fetch these from inside its container. Fix by downloading logos from ETV and base64-uploading to Jellyfin (see `docs/Docker/ErsatzTV.md` for script). Tracked in issue #171
- Repo archived Feb 2026, v26.3.0 is final stable version. Maintainer welcomes forks

View File

@@ -0,0 +1,105 @@
---
name: jellyfin
description: Jellyfin media server management — API for libraries, items, streaming, users. Use when managing media library or checking Jellyfin status.
---
# Jellyfin Management
Container: `jellyfin` | Port: `8096` | IP: `172.16.238.20` (may change on restart)
API Token: `978033be716d46678a5d3c54ae0e0ff9`
Web UI: `https://jellyfin.tblindustries.be` (NO Authelia — native login, password: `coup1802`)
Config: `/home/timothy/downloadswarm/jellyfin/` on jazz
## Access Pattern
```bash
docker exec jellyfin curl -s 'http://localhost:8096/ENDPOINT' \
-H 'X-Emby-Token: 978033be716d46678a5d3c54ae0e0ff9'
```
## Volume Mounts
| Host Path | Container Path | Content |
|-----------|---------------|---------|
| `/mnt/teramind/episodes` | `/data/tvshows` | TV shows |
| `/mnt/episodes` | `/data/episodes` | More episodes |
| `/mnt/media/movies` | `/data/movies` | Movies |
| `/mnt/media/standup` | `/data/standup` | Standup |
| `/mnt/media/music_videos` | `/data/music` | Music videos |
| `/mnt/media/audio/music` | `/data/audio` | Music audio (ro) |
## API Endpoints
### System
```
GET /System/Info # Server info, version
GET /System/Info/Public # Public info (no auth needed)
POST /System/Restart # Restart server
```
### Items (Search & Browse)
```bash
# Search items
GET /Items?includeItemTypes=Movie,Episode,Series&recursive=true&searchTerm=QUERY&fields=Path&limit=20
# Get item details
GET /Items?ids=ITEM_ID&fields=Path,MediaStreams,Overview
# Get all movies
GET /Items?includeItemTypes=Movie&recursive=true&fields=Path&limit=1000
# Get series
GET /Items?includeItemTypes=Series&recursive=true&fields=Path
# Get episodes for a series
GET /Shows/{seriesId}/Episodes?fields=Path,MediaStreams
# Filter by library (parentId)
GET /Items?parentId=LIBRARY_ID&recursive=true&fields=Path
```
### Libraries
```
GET /Library/VirtualFolders # List all libraries
POST /Library/Refresh # Trigger full library scan
POST /Items/{id}/Refresh # Refresh single item metadata
```
### Streaming
```bash
# Test stream URL
GET /Videos/{itemId}/stream?static=true
# Get playback info
GET /Items/{itemId}/PlaybackInfo
```
### Users
```
GET /Users # List users
GET /Users/{userId} # User details
```
## Library IDs
Check with: `curl -s -H "X-Emby-Token: TOKEN" http://localhost:8096/Library/VirtualFolders`
## Live TV
- **ErsatzTV** (channels <1000): M3U `http://ersatztv:8409/iptv/channels.m3u`, XMLTV `http://ersatztv:8409/iptv/xmltv.xml`
- **Dispatcharr** (channels 1000+): IPTV stream manager on port 9191, separate tuner
- Configured in Jellyfin Admin > Live TV
- Guide refresh task ID: `bea9b218c97bbf98c5dc1303bdb9a0ca` — trigger via `POST /ScheduledTasks/Running/{id}`
- **Logo fix after guide refresh**: ErsatzTV logos break (aspect ratio=0) because M3U uses `localhost:8409`. Fix script in `docs/Docker/ErsatzTV.md` downloads from ETV and base64-uploads to `POST /Items/{id}/Images/Primary` (body = base64, Content-Type = image/png)
- **Image upload format**: Jellyfin expects base64-encoded body (NOT raw binary) for `POST /Items/{id}/Images/Primary`
## Gotchas
- **Passwords**: `coup1802` (NOT `ded89Lm4`) — Jellyfin has native auth, no Authelia
- Auth header is `X-Emby-Token` (Jellyfin is an Emby fork)
- Music videos are typed as "Movie" in Jellyfin
- Music library at `/data/music` maps to `/mnt/media/music_videos` on host (not actual music)
- Items return 404 on stream if source volume is unmounted
- Jellyfin preserves item IDs across restarts unless files are renamed
- Full library scan can take a long time — prefer targeted `/Items/{id}/Refresh`
- `ffprobe` available in container for checking media streams: `docker exec jellyfin ffprobe -v quiet -print_format json -show_streams FILE`

View File

@@ -3,16 +3,11 @@
"isRoot": true,
"tools": {
"jetbrains.resharper.globaltools": {
"version": "2021.1.3",
"version": "2025.3.0.2",
"commands": [
"jb"
]
},
"swashbuckle.aspnetcore.cli": {
"version": "5.6.2",
"commands": [
"swagger"
]
],
"rollForward": false
}
}
}
}

View File

@@ -1,9 +1,8 @@
[*]
charset=utf-8-bom
charset=utf-8
end_of_line=lf
trim_trailing_whitespace=false
insert_final_newline=false
trim_trailing_whitespace=true
insert_final_newline=true
indent_style=space
indent_size=4
@@ -15,7 +14,7 @@ csharp_style_expression_bodied_constructors=true:none
csharp_style_expression_bodied_methods=true:none
csharp_style_expression_bodied_properties=true:suggestion
csharp_style_var_elsewhere=false:suggestion
csharp_style_var_for_built_in_types=false:suggestion
csharp_style_var_for_built_in_types=false:none
csharp_style_var_when_type_is_apparent=true:suggestion
dotnet_naming_rule.local_constants_rule.severity=warning
dotnet_naming_rule.local_constants_rule.style=all_upper_style
@@ -42,6 +41,8 @@ resharper_braces_for_for=required
resharper_braces_for_foreach=required
resharper_braces_for_ifelse=required
resharper_braces_for_while=required
resharper_csharp_arguments_literal=positional
resharper_csharp_arguments_named=positional
resharper_csharp_insert_final_newline=true
resharper_csharp_max_attribute_length_for_same_line=0
resharper_csharp_place_accessorholder_attribute_on_same_line=never
@@ -66,7 +67,7 @@ resharper_built_in_type_reference_style_highlighting=hint
resharper_redundant_base_qualifier_highlighting=warning
resharper_suggest_var_or_type_built_in_types_highlighting=hint
resharper_suggest_var_or_type_elsewhere_highlighting=hint
resharper_suggest_var_or_type_simple_types_highlighting=hint
resharper_suggest_var_or_type_simple_types_highlighting=none
resharper_web_config_module_not_resolved_highlighting=warning
resharper_web_config_type_not_resolved_highlighting=warning
resharper_web_config_wrong_module_highlighting=warning
@@ -83,3 +84,23 @@ tab_width=4
[*.yml]
indent_style = space
indent_size = 2
[*.json]
ij_json_array_wrapping = normal
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_keep_trailing_comma = false
ij_json_object_wrapping = normal
ij_json_property_alignment = do_not_align
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = false
ij_json_space_before_comma = false
ij_json_spaces_within_braces = true
ij_json_spaces_within_brackets = true
ij_json_wrap_long_lines = false
[*.cs]
# disable CA1848: Use the LoggerMessage delegates`
dotnet_diagnostic.ca1848.severity = none

8
.gitattributes vendored Normal file
View File

@@ -0,0 +1,8 @@
# Auto detect text files and perform LF normalization
* text=auto
*.cs text diff=csharp
*.cshtml text diff=html
*.csx text diff=csharp
*.sln text eol=crlf
*.csproj text eol=crlf

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Feature Requests
url: https://features.ersatztv.org
about: Features
- name: Contact
url: https://ersatztv.org/contact
about: Chat Options
- name: Community
url: https://discuss.ersatztv.org
about: Forum
- name: Discussions
url: https://github.com/ErsatzTV/ErsatzTV/discussions
about: Discuss

77
.github/ISSUE_TEMPLATE/issue.yml vendored Normal file
View File

@@ -0,0 +1,77 @@
name: Issue Report
description: Report an issue
type: Bug
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this form! Please make sure to fill all fields, including the Title above.
- type: checkboxes
id: before-posting
attributes:
label: "This issue respects the following points:"
description: All conditions are **required**. Failure to comply with any of these conditions may cause your issue to be closed without comment.
options:
- label: This is a **bug**, not a question or a configuration issue; Please visit our [forum](https://discuss.ersatztv.org) or [chat](https://ersatztv.org/contact) first to troubleshoot with volunteers before creating a report.
required: true
- label: This issue is **not** already reported on [GitHub](https://github.com/ErsatzTV/ErsatzTV/issues?q=is%3Aopen+is%3Aissue) _(I've searched it)_.
required: true
- label: I'm using an up to date version of ErsatzTV (full release or develop release); We generally do not support previous older versions. If possible, please update to the latest version before opening an issue.
required: true
- label: This report addresses only a single issue; If you encounter multiple issues, please create separate reports for each one.
required: true
- type: textarea
id: description
attributes:
label: Description
description: |
Description of the problem or issue here.
validations:
required: true
- type: textarea
id: repro-steps
attributes:
label: Steps to reproduce the problem.
description: |
1. Step 1
2. Step 2
3. Step 3
If this is a playback issue, follow these steps and post the resulting zip:
1. Search for the required content using the search bar.
2. Use the overflow/three dots menu on the content and select Troubleshoot Playback.
3. Select the appropriate Playback Settings that trigger the undesired behavior.
4. Click Play to start playback.
5. Repeat steps 3 and 4 until the undesired behavior is reproduced.
6. Click Download Results to have ErsatzTV collect relevant troubleshooting logs (ffmpeg log, ffmpeg profile, hardware capabilities, media info, etc) and compress them in a zip file.
7. Attach the zip to this field.
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: What is the current _bug_ behavior?
description: Write down the incorrect behavior that currently happens after following the reproduction steps.
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: What is the expected _correct_ behavior?
description: Write down the correct expected behavior that is supposed to happen after following the reproduction steps.
validations:
required: true
- type: input
id: version
attributes:
label: Specify full version
description: Provide the full version of ErsatzTV, which can be found below the left menu.
placeholder: |
25.5.0-bd695412-docker-amd64
validations:
required: true
- type: textarea
id: additional-information
attributes:
label: Additional information
description: Any additional information that might be useful to this issue.

View File

@@ -6,3 +6,21 @@ updates:
interval: daily
assignees:
- jasongdove
- package-ecosystem: docker
directory: "/docker"
schedule:
interval: daily
assignees:
- jasongdove
- package-ecosystem: docker
directory: "/docker/nvidia"
schedule:
interval: daily
assignees:
- jasongdove
- package-ecosystem: docker
directory: "/docker/vaapi"
schedule:
interval: daily
assignees:
- jasongdove

336
.github/workflows/artifacts.yml vendored Normal file
View File

@@ -0,0 +1,336 @@
name: Build Artifacts
on:
workflow_call:
inputs:
release_tag:
description: 'Release tag'
required: true
type: string
release_version:
description: 'Release version number (e.g. v0.3.7-alpha)'
required: true
type: string
info_version:
description: 'Informational version number (e.g. 0.3.7-alpha)'
required: true
type: string
secrets:
apple_developer_certificate_p12_base64:
required: true
apple_developer_certificate_password:
required: true
ac_username:
required: true
ac_password:
required: true
gh_token:
required: true
azure_client_id:
required: true
azure_tenant_id:
required: true
azure_subscription_id:
required: true
permissions:
id-token: write
contents: write
jobs:
build_and_upload_mac:
name: Mac Build & Upload
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: macos-14
kind: macOS
target: osx-x64
- os: macos-14
kind: macOS
target: osx-arm64
steps:
- name: Get the sources
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore -r "${{ matrix.target}}"
- name: Import Code-Signing Certificates
uses: Apple-Actions/import-codesign-certs@v2
with:
p12-file-base64: ${{ secrets.apple_developer_certificate_p12_base64 }}
p12-password: ${{ secrets.apple_developer_certificate_password }}
- name: Calculate Release Name
shell: bash
run: |
release_name="ErsatzTV-${{ inputs.release_version }}-${{ matrix.target }}"
echo "RELEASE_NAME=${release_name}" >> $GITHUB_ENV
- name: Build
shell: bash
run: |
sed -i '' '/Scanner/d' ErsatzTV/ErsatzTV.csproj
dotnet publish ErsatzTV.Scanner/ErsatzTV.Scanner.csproj --framework net10.0 --runtime "${{ matrix.target }}" -c Release -o publish -p:RestoreEnablePackagePruning=true -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=false -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV/ErsatzTV.csproj --framework net10.0 --runtime "${{ matrix.target }}" -c Release -o publish -p:RestoreEnablePackagePruning=true -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=false -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
- name: Bundle
shell: bash
run: |
brew install coreutils
plutil -replace CFBundleShortVersionString -string "${{ inputs.info_version }}" ErsatzTV-macOS/ErsatzTV-macOS/Info.plist
plutil -replace CFBundleVersion -string "${{ inputs.info_version }}" ErsatzTV-macOS/ErsatzTV-macOS/Info.plist
scripts/macOS/bundle.sh
- name: Sign
shell: bash
run: scripts/macOS/sign.sh
- name: Create DMG
shell: bash
run: |
brew install create-dmg
create-dmg \
--volname "ErsatzTV" \
--volicon "artwork/ErsatzTV.icns" \
--window-pos 200 120 \
--window-size 800 400 \
--icon-size 100 \
--icon "ErsatzTV.app" 200 190 \
--hide-extension "ErsatzTV.app" \
--app-drop-link 600 185 \
--skip-jenkins \
--no-internet-enable \
"ErsatzTV.dmg" \
"ErsatzTV.app/"
- name: Notarize
shell: bash
run: |
xcrun notarytool submit ErsatzTV.dmg --apple-id "${{ secrets.ac_username }}" --password "${{ secrets.ac_password }}" --team-id 32MB98Q32R --wait
xcrun stapler staple ErsatzTV.dmg
- name: Cleanup
shell: bash
run: |
mv ErsatzTV.dmg "${{ env.RELEASE_NAME }}.dmg"
rm -r publish
rm -r ErsatzTV.app
- name: Delete old release assets
uses: mknejp/delete-release-assets@v1
if: ${{ inputs.release_tag == 'develop' }}
with:
token: ${{ secrets.gh_token }}
tag: ${{ inputs.release_tag }}
fail-if-no-assets: false
assets: "*${{ matrix.target }}.dmg"
- name: Publish
uses: softprops/action-gh-release@v1
with:
prerelease: false
tag_name: ${{ inputs.release_tag }}
files: "${{ env.RELEASE_NAME }}.dmg"
env:
GITHUB_TOKEN: ${{ secrets.gh_token }}
build_and_upload_linux:
name: Build & Upload Linux
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
kind: linux
target: linux-x64
- os: ubuntu-latest
kind: linux
target: linux-musl-x64
- os: ubuntu-latest
kind: linux
target: linux-arm
- os: ubuntu-24.04-arm
kind: linux
target: linux-arm64
steps:
- name: Get the sources
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore -r "${{ matrix.target }}"
- name: Build
shell: bash
run: |
# Define some variables for things we need
release_name="ErsatzTV-${{ inputs.release_version }}-${{ matrix.target }}"
echo "RELEASE_NAME=${release_name}" >> $GITHUB_ENV
# Build everything
sed -i '/Scanner/d' ErsatzTV/ErsatzTV.csproj
dotnet publish ErsatzTV.Scanner/ErsatzTV.Scanner.csproj --framework net10.0 --runtime "${{ matrix.target }}" -c Release -o "scanner" -p:RestoreEnablePackagePruning=true -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV/ErsatzTV.csproj --framework net10.0 --runtime "${{ matrix.target }}" -c Release -o "main" -p:RestoreEnablePackagePruning=true -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
mkdir "$release_name"
mv scanner/* "$release_name/"
mv main/* "$release_name/"
tar czvf "${release_name}.tar.gz" "$release_name"
# Delete output directory
rm -r "$release_name"
- name: Delete old release assets
uses: mknejp/delete-release-assets@v1
if: ${{ inputs.release_tag == 'develop' }}
with:
token: ${{ secrets.gh_token }}
tag: ${{ inputs.release_tag }}
fail-if-no-assets: false
assets: "*${{ matrix.target }}.tar.gz"
- name: Publish
uses: softprops/action-gh-release@v1
with:
prerelease: false
tag_name: ${{ inputs.release_tag }}
files: "${{ env.RELEASE_NAME }}.tar.gz"
env:
GITHUB_TOKEN: ${{ secrets.gh_token }}
build_dotnet_windows:
name: Build dotnet for Windows
runs-on: ubuntu-latest
steps:
- name: Get the sources
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore -r "win-x64"
- name: Build dotnet projects
shell: bash
run: |
sed -i '/Scanner/d' ErsatzTV/ErsatzTV.csproj
dotnet publish ErsatzTV.Scanner/ErsatzTV.Scanner.csproj --framework net10.0 --runtime "win-x64" -c Release -o "scanner" -p:RestoreEnablePackagePruning=true -p:InformationalVersion="${{ inputs.release_version }}-win-x64" -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV/ErsatzTV.csproj --framework net10.0 --runtime "win-x64" -c Release -o "main" -p:RestoreEnablePackagePruning=true -p:InformationalVersion="${{ inputs.release_version }}-win-x64" -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
- name: Upload .NET Artifact
uses: actions/upload-artifact@v4
with:
name: dotnet-windows-build
path: |
scanner/
main/
retention-days: 1
package_and_upload_windows:
name: Package & Upload Windows
runs-on: windows-latest
needs: build_dotnet_windows
steps:
- name: Download dotnet artifacts
uses: actions/download-artifact@v4
with:
name: dotnet-windows-build
path: dotnet-build
- name: Azure login
uses: azure/login@v2
with:
client-id: ${{ secrets.azure_client_id }}
tenant-id: ${{ secrets.azure_tenant_id }}
subscription-id: ${{ secrets.azure_subscription_id }}
enable-AzPSSession: true
- name: Sign dotnet artifacts
uses: azure/trusted-signing-action@v0
with:
endpoint: https://eus.codesigning.azure.net/
trusted-signing-account-name: ArtifactSigning
certificate-profile-name: ErsatzTV
files-folder: ${{ github.workspace }}/dotnet-build
files-folder-recurse: true
files-folder-filter: ErsatzTV.exe,ErsatzTV.Scanner.exe
file-digest: SHA256
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Download rust launcher
uses: suisei-cn/actions-download-file@v1.3.0
with:
url: "https://github.com/ErsatzTV/ErsatzTV-Windows/releases/download/v1.0.0/ErsatzTV-Windows.exe"
target: rust-build/
- name: Download ffmpeg
uses: suisei-cn/actions-download-file@v1.3.0
id: downloadffmpeg
with:
url: "https://github.com/ErsatzTV/ErsatzTV-ffmpeg/releases/download/7.1.1/ffmpeg-n7.1.1-56-gc2184b65d2-win64-gpl-7.1.zip"
target: ffmpeg/
- name: Package artifacts
shell: bash
run: |
release_name="ErsatzTV-${{ inputs.release_version }}-win-x64"
echo "RELEASE_NAME=${release_name}" >> $GITHUB_ENV
mkdir "$release_name"
mv dotnet-build/scanner/* "$release_name/"
mv dotnet-build/main/* "$release_name/"
# dotnet shouldn't copy the resources here, but it does
rm -rf "$release_name/Resources"
mv rust-build/ErsatzTV-Windows.exe "$release_name/ErsatzTV-Windows.exe"
7z e "ffmpeg/${{ steps.downloadffmpeg.outputs.filename }}" -o"$release_name" '*.exe' -r
rm -f "$release_name/ffplay.exe"
(cd "${release_name}" && 7z a "../${release_name}.zip" .)
- name: Delete old release assets
uses: mknejp/delete-release-assets@v1
if: ${{ inputs.release_tag == 'develop' }}
with:
token: ${{ secrets.gh_token }}
tag: ${{ inputs.release_tag }}
fail-if-no-assets: false
assets: "*win-x64.zip"
- name: Publish
uses: softprops/action-gh-release@v1
with:
prerelease: false
tag_name: ${{ inputs.release_tag }}
files: "${{ env.RELEASE_NAME }}.zip"
env:
GITHUB_TOKEN: ${{ secrets.gh_token }}

View File

@@ -1,110 +1,62 @@
name: Build
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
jobs:
build_and_test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ windows-latest, ubuntu-latest, macos-latest ]
calculate_version:
name: Calculate version information
runs-on: ubuntu-latest
steps:
- name: Get the sources
uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --no-restore --verbosity normal
build_and_push:
name: Build & Publish to Docker Hub
needs: build_and_test
runs-on: ubuntu-latest
if: github.event_name == 'push' && !contains(github.event.head_commit.message, '[no docker]')
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract Git Tag
- name: Extract Docker Tag
shell: bash
run: |
tag=$(git describe --tags --abbrev=0)
tag2="${tag:1}"
short=$(git rev-parse --short HEAD)
final="${tag2/prealpha/$short}"
final="${tag2}-${short}"
echo "GIT_TAG=${final}" >> $GITHUB_ENV
- name: Extract Artifacts Version
shell: bash
run: |
tag=$(git describe --tags --abbrev=0)
short=$(git rev-parse --short HEAD)
final="${tag}-${short}"
echo "ARTIFACTS_VERSION=${final}" >> $GITHUB_ENV
echo "INFO_VERSION=${tag:1}" >> $GITHUB_ENV
outputs:
git_tag: ${{ env.GIT_TAG }}
artifacts_version: ${{ env.ARTIFACTS_VERSION }}
info_version: ${{ env.INFO_VERSION }}
build_and_upload:
uses: ersatztv/ersatztv/.github/workflows/artifacts.yml@main
needs: calculate_version
with:
release_tag: develop
release_version: ${{ needs.calculate_version.outputs.artifacts_version }}
info_version: ${{ needs.calculate_version.outputs.info_version }}
secrets:
apple_developer_certificate_p12_base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
apple_developer_certificate_password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
ac_username: ${{ secrets.AC_USERNAME }}
ac_password: ${{ secrets.AC_PASSWORD }}
gh_token: ${{ secrets.GITHUB_TOKEN }}
azure_client_id: ${{ secrets.AZURE_CLIENT_ID }}
azure_tenant_id: ${{ secrets.AZURE_TENANT_ID }}
azure_subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Set up Docker Buildx Base
uses: docker/setup-buildx-action@v1
id: builder-base
- name: Set up Docker Buildx NVIDIA
uses: docker/setup-buildx-action@v1
id: builder-nvidia
- name: Set up Docker Buildx VAAPI
uses: docker/setup-buildx-action@v1
id: builder-vaapi
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Build and push base
uses: docker/build-push-action@v2
with:
builder: ${{ steps.builder-base.outputs.name }}
context: .
file: ./docker/Dockerfile
push: true
build-args: |
INFO_VERSION=${{ env.GIT_TAG }}-docker
tags: |
jasongdove/ersatztv:develop
jasongdove/ersatztv:${{ github.sha }}
- name: Build and push nvidia
uses: docker/build-push-action@v2
with:
builder: ${{ steps.builder-nvidia.outputs.name }}
context: .
file: ./docker/nvidia/Dockerfile
push: true
build-args: |
INFO_VERSION=${{ env.GIT_TAG }}-docker-nvidia
tags: |
jasongdove/ersatztv:develop-nvidia
jasongdove/ersatztv:${{ github.sha }}-nvidia
- name: Build and push vaapi
uses: docker/build-push-action@v2
with:
builder: ${{ steps.builder-vaapi.outputs.name }}
context: .
file: ./docker/vaapi/Dockerfile
push: true
build-args: |
INFO_VERSION=${{ env.GIT_TAG }}-docker-vaapi
tags: |
jasongdove/ersatztv:develop-vaapi
jasongdove/ersatztv:${{ github.sha }}-vaapi
build_images:
uses: ersatztv/ersatztv/.github/workflows/docker.yml@main
needs: calculate_version
with:
base_version: develop
info_version: ${{ needs.calculate_version.outputs.git_tag }}
tag_version: ${{ github.sha }}
secrets:
docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }}
docker_hub_access_token: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

141
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,141 @@
name: Build & Publish to Docker Hub
on:
workflow_call:
inputs:
base_version:
description: 'Base version (latest or develop)'
required: true
type: string
info_version:
description: 'Informational version number (e.g. 0.3.7-alpha)'
required: true
type: string
tag_version:
description: 'Docker tag version (e.g. v0.3.7)'
required: true
type: string
secrets:
docker_hub_username:
required: true
docker_hub_access_token:
required: true
jobs:
build_images:
name: Build ${{ matrix.name }} image
runs-on: ${{ matrix.os }}
if: contains(github.event.head_commit.message, '[no build]') == false
strategy:
matrix:
include:
- name: amd64
os: ubuntu-latest
path: ''
suffix: '-amd64'
platform: 'linux/amd64'
- name: arm32v7
os: ubuntu-latest
path: 'arm32v7/'
suffix: '-arm'
platform: 'linux/arm/v7'
- name: arm64
os: ubuntu-24.04-arm
path: 'arm64/'
suffix: '-arm64'
platform: 'linux/arm64'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up QEMU
if: ${{ matrix.name == 'arm32v7' }}
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.docker_hub_username }}
password: ${{ secrets.docker_hub_access_token }}
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/${{ matrix.path }}Dockerfile
push: true
provenance: false
platforms: ${{ matrix.platform }}
build-args: |
INFO_VERSION=${{ inputs.info_version }}-docker${{ matrix.suffix }}
outputs: |
type=image,name=jasongdove/ersatztv,name-canonical=true,push-by-digest=true
type=image,name=ghcr.io/ersatztv/ersatztv,name-canonical=true,push-by-digest=true
- name: Save digest to artifact
run: echo ${{ steps.build.outputs.digest }} > digest.txt
- name: Upload digest artifact
uses: actions/upload-artifact@v4
with:
name: digest-${{ matrix.name }}
path: digest.txt
merge_manifests:
name: Merge Manifests
runs-on: ubuntu-latest
needs: build_images
steps:
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.docker_hub_username }}
password: ${{ secrets.docker_hub_access_token }}
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Download all digest artifacts
uses: actions/download-artifact@v4
with:
path: digests/
- name: Read digests from artifacts
id: digests
run: |
AMD64_HASH=$(cat digests/digest-amd64/digest.txt)
ARM32V7_HASH=$(cat digests/digest-arm32v7/digest.txt)
ARM64_HASH=$(cat digests/digest-arm64/digest.txt)
DOCKER_HUB_DIGESTS="jasongdove/ersatztv@${AMD64_HASH} jasongdove/ersatztv@${ARM64_HASH} jasongdove/ersatztv@${ARM32V7_HASH}"
GHCR_DIGESTS="ghcr.io/ersatztv/ersatztv@${AMD64_HASH} ghcr.io/ersatztv/ersatztv@${ARM64_HASH} ghcr.io/ersatztv/ersatztv@${ARM32V7_HASH}"
echo "docker_hub_digests=${DOCKER_HUB_DIGESTS}" >> $GITHUB_OUTPUT
echo "ghcr_digests=${GHCR_DIGESTS}" >> $GITHUB_OUTPUT
- name: Create and push manifests
run: |
docker manifest create jasongdove/ersatztv:${{ inputs.base_version }} ${{ steps.digests.outputs.docker_hub_digests }}
docker manifest push jasongdove/ersatztv:${{ inputs.base_version }}
docker manifest create jasongdove/ersatztv:${{ inputs.tag_version }} ${{ steps.digests.outputs.docker_hub_digests }}
docker manifest push jasongdove/ersatztv:${{ inputs.tag_version }}
docker manifest create ghcr.io/ersatztv/ersatztv:${{ inputs.base_version }} ${{ steps.digests.outputs.ghcr_digests }}
docker manifest push ghcr.io/ersatztv/ersatztv:${{ inputs.base_version }}
docker manifest create ghcr.io/ersatztv/ersatztv:${{ inputs.tag_version }} ${{ steps.digests.outputs.ghcr_digests }}
docker manifest push ghcr.io/ersatztv/ersatztv:${{ inputs.tag_version }}

View File

@@ -1,19 +0,0 @@
name: Publish docs via GitHub Pages
on:
push:
branches:
- main
jobs:
build:
name: Deploy docs
runs-on: ubuntu-latest
steps:
- name: Checkout master
uses: actions/checkout@v1
- name: Deploy docs
uses: mhausenblas/mkdocs-deploy-gh-pages@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CUSTOM_DOMAIN: ersatztv.org

27
.github/workflows/issue-stale.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: 'Close stale issues'
on:
schedule:
- cron: '30 1 * * *'
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
ascending: true
days-before-stale: 120
days-before-pr-stale: -1
days-before-close: 21
days-before-pr-close: -1
operations-per-run: 500
exempt-issue-labels: 'regression,security,roadmap,future,feature,enhancement,confirmed'
stale-issue-label: 'stale'
stale-issue-message: |-
This issue has gone 120 days without an update and will be closed within 21 days if there is no new activity. To prevent this issue from being closed, please confirm the issue has not already been fixed by providing updated examples or logs.
If you have any questions you can use one of several ways to [contact us](https://ersatztv.org).
close-issue-message: |-
This issue was closed due to inactivity.

118
.github/workflows/pr.yml vendored Normal file
View File

@@ -0,0 +1,118 @@
name: Pull Request
on:
pull_request:
jobs:
build_and_analyze:
runs-on: ubuntu-latest
steps:
- name: Get the sources
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore
- name: Prep project file
run: sed -i '/Scanner/d' ErsatzTV/ErsatzTV.csproj
- name: Build
run: dotnet build --configuration Release --no-restore /p:EnableThreadingAnalyzers=true
build_and_test_windows:
runs-on: windows-latest
steps:
- name: Get the sources
uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore
- name: Prep project file
run: sed -i '/Scanner/d' ErsatzTV/ErsatzTV.csproj
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --blame-hang-timeout "2m" --no-restore --verbosity normal
build_and_test_linux:
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
target: linux-x64
- os: ubuntu-latest
target: linux-musl-x64
- os: ubuntu-latest
target: linux-arm
- os: ubuntu-24.04-arm
target: linux-arm64
steps:
- name: Get the sources
uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore -p:RestoreEnablePackagePruning=true -r "${{ matrix.target }}"
- name: Prep project file
run: sed -i '/Scanner/d' ErsatzTV/ErsatzTV.csproj
- name: Build
run: dotnet build ErsatzTV/ErsatzTV.csproj --runtime "${{ matrix.target }}" --configuration Release --no-restore && dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --blame-hang-timeout "2m" --no-restore --verbosity normal
build_and_test_mac:
runs-on: macos-14
steps:
- name: Get the sources
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore
- name: Prep project file
run: sed -i '' '/Scanner/d' ErsatzTV/ErsatzTV.csproj
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --blame-hang-timeout "2m" --no-restore --verbosity normal

View File

@@ -1,142 +1,56 @@
name: Publish
name: Release
on:
release:
types: [ published ]
jobs:
release:
name: Release
strategy:
matrix:
include:
- os: ubuntu-latest
kind: linux
target: linux-x64
- os: ubuntu-latest
kind: linux
target: linux-arm
- os: windows-latest
kind: windows
target: win-x64
- os: macos-latest
kind: maxOS
target: osx-x64
runs-on: ${{ matrix.os }}
steps:
- name: Get the sources
uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
- name: Install dependencies
run: dotnet restore
- name: Build
shell: bash
run: |
# Define some variables for things we need
tag=$(git describe --tags --abbrev=0)
release_name="ErsatzTV-$tag-${{ matrix.target }}"
# Build everything
dotnet publish ErsatzTV/ErsatzTV.csproj --framework net5.0 --runtime "${{ matrix.target }}" -c Release -o "$release_name" /property:InformationalVersion="${tag:1}-${{ matrix.target }}" /property:PublishSingleFile=true --self-contained true
# Pack files
if [ "${{ matrix.target }}" == "win-x64" ]; then
7z a -tzip "${release_name}.zip" "./${release_name}/*"
elif [ "${{ matrix.target }}" == "linux-arm" ]; then
cp lib/linux-arm/* "$release_name/"
tar czvf "${release_name}.tar.gz" "$release_name"
else
tar czvf "${release_name}.tar.gz" "$release_name"
fi
# Delete output directory
rm -r "$release_name"
- name: Publish
uses: softprops/action-gh-release@v1
with:
prerelease: true
files: |
ErsatzTV*.zip
ErsatzTV*.tar.gz
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build_and_push:
name: Build & Publish to Docker Hub
calculate_version:
name: Calculate version information
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Get the sources
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract Git Tag
- name: Extract Docker Tag
shell: bash
run: |
tag=$(git describe --tags --abbrev=0)
echo "GIT_TAG=${tag:1}" >> $GITHUB_ENV
echo "DOCKER_TAG=${tag/-prealpha/}" >> $GITHUB_ENV
- name: Set up Docker Buildx Base
uses: docker/setup-buildx-action@v1
id: builder-base
- name: Set up Docker Buildx NVIDIA
uses: docker/setup-buildx-action@v1
id: builder-nvidia
- name: Set up Docker Buildx VAAPI
uses: docker/setup-buildx-action@v1
id: builder-vaapi
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Build and push base
uses: docker/build-push-action@v2
with:
builder: ${{ steps.builder-base.outputs.name }}
context: .
file: ./docker/Dockerfile
push: true
build-args: |
INFO_VERSION=${{ env.GIT_TAG }}-docker
tags: |
jasongdove/ersatztv:latest
jasongdove/ersatztv:${{ env.DOCKER_TAG }}
- name: Build and push nvidia
uses: docker/build-push-action@v2
with:
builder: ${{ steps.builder-nvidia.outputs.name }}
context: .
file: ./docker/nvidia/Dockerfile
push: true
build-args: |
INFO_VERSION=${{ env.GIT_TAG }}-docker-nvidia
tags: |
jasongdove/ersatztv:latest-nvidia
jasongdove/ersatztv:${{ env.DOCKER_TAG }}-nvidia
- name: Build and push vaapi
uses: docker/build-push-action@v2
with:
builder: ${{ steps.builder-vaapi.outputs.name }}
context: .
file: ./docker/vaapi/Dockerfile
push: true
build-args: |
INFO_VERSION=${{ env.GIT_TAG }}-docker-vaapi
tags: |
jasongdove/ersatztv:latest-vaapi
jasongdove/ersatztv:${{ env.DOCKER_TAG }}-vaapi
echo "DOCKER_TAG=${tag}" >> $GITHUB_ENV
- name: Extract Artifacts Version
shell: bash
run: |
tag=$(git describe --tags --abbrev=0)
echo "ARTIFACTS_VERSION=${tag}" >> $GITHUB_ENV
echo "INFO_VERSION=${tag:1}" >> $GITHUB_ENV
outputs:
git_tag: ${{ env.GIT_TAG }}
docker_tag: ${{ env.DOCKER_TAG }}
artifacts_version: ${{ env.ARTIFACTS_VERSION }}
info_version: ${{ env.INFO_VERSION }}
build_and_upload:
uses: ersatztv/ersatztv/.github/workflows/artifacts.yml@main
needs: calculate_version
with:
release_tag: ${{ needs.calculate_version.outputs.artifacts_version }}
release_version: ${{ needs.calculate_version.outputs.artifacts_version }}
info_version: ${{ needs.calculate_version.outputs.info_version }}
secrets:
apple_developer_certificate_p12_base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
apple_developer_certificate_password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
ac_username: ${{ secrets.AC_USERNAME }}
ac_password: ${{ secrets.AC_PASSWORD }}
gh_token: ${{ secrets.GITHUB_TOKEN }}
azure_client_id: ${{ secrets.AZURE_CLIENT_ID }}
azure_tenant_id: ${{ secrets.AZURE_TENANT_ID }}
azure_subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
build_images:
uses: ersatztv/ersatztv/.github/workflows/docker.yml@main
needs: calculate_version
with:
base_version: latest
info_version: ${{ needs.calculate_version.outputs.git_tag }}
tag_version: ${{ needs.calculate_version.outputs.docker_tag }}
secrets:
docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }}
docker_hub_access_token: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

5
.gitignore vendored
View File

@@ -3,6 +3,9 @@
project.lock.json
.DS_Store
*.pyc
# Claude Code
.mcp/
nupkg/
# Visual Studio Code
@@ -40,6 +43,8 @@ msbuild.wrn
core
scripts/generate-api-sdk/swagger.json
scripts/download-test-content.sh
docker-compose.override.yml
ErsatzTV/wwwroot/v2/

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "ErsatzTV-macOS"]
path = ErsatzTV-macOS
url = git@github.com:ErsatzTV/ErsatzTV-macOS.git

56
.mcp.json Normal file
View File

@@ -0,0 +1,56 @@
{
"mcpServers": {
"docker-mcp": {
"command": "uvx",
"args": [
"mcp-server-docker"
],
"env": {
"DOCKER_HOST": "ssh://timothy@192.168.1.99"
}
},
"ssh-mcp": {
"command": "npx",
"args": [
"-y",
"ssh-mcp",
"--",
"--host=192.168.1.99",
"--user=timothy"
],
"env": {}
},
"gitea": {
"command": "gitea-mcp-server",
"args": [
"-t", "stdio",
"-host", "http://192.168.1.95:3000",
"-token", "8341af0733ab9ce084ea7adf38b76aa9ebc3bd67"
],
"env": {}
},
"csharp-lsp": {
"command": "/usr/local/share/dotnet/dotnet",
"args": [
"run",
"--project", "/Users/timothy/ersatztv/.mcp/csharp-lsp-mcp/csharp-lsp-mcp/src/CSharpLspMcp",
"-c", "Release"
],
"env": {
"PATH": "/usr/local/share/dotnet:/Users/timothy/.dotnet/tools:/usr/bin:/bin:/usr/sbin:/sbin"
}
},
"nuget": {
"command": "/usr/local/share/dotnet/dotnet",
"args": [
"dnx",
"NuGet.Mcp.Server",
"--source", "https://api.nuget.org/v3/index.json",
"--yes"
],
"env": {
"DOTNET_ROOT": "/usr/local/share/dotnet"
}
}
}
}

File diff suppressed because it is too large Load Diff

91
CLAUDE.md Normal file
View File

@@ -0,0 +1,91 @@
# ErsatzTV Fork
Custom IPTV channel server for Jellyfin. Forked from [ErsatzTV/ErsatzTV](https://github.com/ErsatzTV/ErsatzTV) after upstream archival (Feb 2026, v26.3.0). Our fork lives on [Gitea](http://192.168.1.95:3000/timothy/ersatztv).
## Architecture
- **Language**: C# / .NET 10, Blazor Server UI (MudBlazor)
- **Pattern**: CQRS via MediatR — queries/commands in `ErsatzTV.Application/`
- **Database**: EF Core (SQLite default, MySQL optional) — context in `ErsatzTV.Infrastructure/Data/TvContext.cs`
- **Media**: FFmpeg via CliWrap, SkiaSharp for logo generation
- **Functional C#**: Language Ext (Option, Either monads throughout)
### Project Layout
| Project | Role |
|---------|------|
| `ErsatzTV/` | ASP.NET Core host, Blazor pages, API controllers, DI setup |
| `ErsatzTV.Application/` | MediatR handlers (business logic) |
| `ErsatzTV.Core/` | Domain entities, interfaces, no infrastructure deps |
| `ErsatzTV.Infrastructure/` | EF Core repos, data access |
| `ErsatzTV.Infrastructure.Sqlite/` | SQLite-specific implementations |
| `ErsatzTV.FFmpeg/` | FFmpeg process wrapper |
| `ErsatzTV.Scanner/` | Media library scanning |
### Key Files
- **M3U generation**: `ErsatzTV.Core/Iptv/ChannelPlaylist.cs``ToM3U()`
- **XMLTV generation**: `ErsatzTV.Application/Channels/Queries/GetChannelGuideHandler.cs`
- **IPTV controller**: `ErsatzTV/Controllers/IptvController.cs``/iptv/*` routes
- **Logo generation**: `ErsatzTV.Core/Images/ChannelLogoGenerator.cs`
- **Channel entities**: `ErsatzTV.Core/Domain/Channel.cs`
- **DB context**: `ErsatzTV.Infrastructure/Data/TvContext.cs`
## Deployment
- **Docker host**: jazz (192.168.1.99), container `ersatztv`, port 8409
- **Config volume**: `~/downloadswarm/ersatztv/` on jazz → `/config` in container
- **SQLite DB**: `/config/ersatztv.sqlite3` (WAL mode, root-owned)
- **Image**: `ghcr.io/ersatztv/ersatztv:latest` (to be replaced with our fork's image)
## Development
```bash
# Build
dotnet build ErsatzTV.sln
# Run locally (needs FFmpeg in PATH)
dotnet run --project ErsatzTV
# Docker build
docker build -f docker/Dockerfile -t ersatztv:dev .
```
## Conventions
- Follow existing MediatR CQRS pattern for new features
- Domain logic in `ErsatzTV.Core`, infrastructure in `ErsatzTV.Infrastructure`
- Keep Blazor pages thin — delegate to MediatR handlers
- Test with xUnit (existing test projects)
- Backlog tracked via [Gitea Issues](http://192.168.1.95:3000/timothy/ersatztv/issues)
## Task Completion Protocol
Every task that closes a Gitea issue MUST complete ALL of these before it is considered done. Use `/done <issue>` to run through this automatically.
1. **Root cause** (bug fixes / incidents only): Document WHY the problem existed, not just what was changed. If root cause is unknown, say so explicitly and open a follow-up investigation issue. Fixing symptoms without understanding causes creates recurring problems.
2. **Comment on issues** as you work — what you found, what approach you're taking, any deviations from the suggested fix.
3. **Push changes**: `git push` all commits before closing. Use `fixes #N` in commit messages to auto-close where appropriate.
4. **Close comment**: Add a structured closing comment on the issue covering: what was done, root cause (if applicable), files changed, anything deferred, follow-up issues created, and which docs were updated.
5. **Close the issue** via API or `fixes #N` commit. Leave open with a comment only if partially addressed.
6. **Update docs**: If the change affects operational behavior, update the relevant Obsidian docs (`~/homelab-docs/`), MEMORY.md, or CLAUDE.md inline — not as a follow-up.
7. **Reply to reviewer** (if from adversarial review): Summary of done/deferred/questions. This triggers the next review cycle.
## Project Boundaries
**ersatztv OWNS**: ErsatzTV fork code (C#/.NET), channel/collection/schedule management, M3U/XMLTV generation, the ErsatzTV skill in server-management.
**ersatztv does NOT own**:
- Docker compose configs → server-management (`~/downloadswarm/stacks/ersatztv/`)
- NFS mounts, Ansible, DNS, networking → server-management
- Content sourcing (yt-dlp downloads, Sonarr/Radarr libraries) → media-management (planned)
- Jellyfin skill → server-management (symlinked)
**For infrastructure changes** (Docker, NFS, ports, Authelia): open an issue in `timothy/server-management`.
**For content/media sourcing questions** (what goes into channels, yt-dlp pipelines): open an issue in `timothy/media-management` once it exists; for now, `timothy/server-management`.
**For plan/audit reviews**: open `~/adversarial-reviewer` before significant architecture changes.
**Full cross-project rules**: `~/homelab-docs/Operations/Project Boundaries.md` (https://docs.tblindustries.be).
**ErsatzTV docs**: `~/homelab-docs/Docker/ErsatzTV.md` + project-local `docs/` (fork strategy, channels, M3U/XMLTV).

View File

@@ -1,5 +1,7 @@
<Project>
<PropertyGroup>
<InformationalVersion>develop</InformationalVersion>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<AllowMissingPrunePackageData>true</AllowMissingPrunePackageData>
</PropertyGroup>
</Project>
</Project>

15
Directory.Build.targets Normal file
View File

@@ -0,0 +1,15 @@
<Project>
<PropertyGroup>
<EnableThreadingAnalyzers Condition="'$(EnableThreadingAnalyzers)' == ''">false</EnableThreadingAnalyzers>
</PropertyGroup>
<ItemGroup>
<PackageReference
Include="Microsoft.VisualStudio.Threading.Analyzers"
Version="17.14.15"
Condition="'$(EnableThreadingAnalyzers)' == 'true'">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

1
ErsatzTV-macOS Submodule

Submodule ErsatzTV-macOS added at 8dbe1e22f2

View File

@@ -0,0 +1,5 @@
[*.cs]
# disable CA1711: Identifiers should not have incorrect suffix
dotnet_diagnostic.ca1711.severity = none
# disable CA1848: Use the LoggerMessage delegates
dotnet_diagnostic.ca1848.severity = none

View File

@@ -1,16 +1,14 @@
using System.Collections.Generic;
using System.Globalization;
using System.Globalization;
namespace ErsatzTV.Application.Artists
{
public record ArtistViewModel(
string Name,
string Disambiguation,
string Biography,
string Thumbnail,
string FanArt,
List<string> Genres,
List<string> Styles,
List<string> Moods,
List<CultureInfo> Languages);
}
namespace ErsatzTV.Application.Artists;
public record ArtistViewModel(
string Name,
string Disambiguation,
string Biography,
string Thumbnail,
string FanArt,
List<string> Genres,
List<string> Styles,
List<string> Moods,
List<CultureInfo> Languages);

View File

@@ -1,46 +1,40 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Globalization;
using ErsatzTV.Core.Domain;
using LanguageExt;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Artists
namespace ErsatzTV.Application.Artists;
internal static class Mapper
{
internal static class Mapper
internal static ArtistViewModel ProjectToViewModel(Artist artist, List<string> languages)
{
internal static ArtistViewModel ProjectToViewModel(Artist artist, List<string> languages)
{
ArtistMetadata metadata = Optional(artist.ArtistMetadata).Flatten().Head();
return new ArtistViewModel(
metadata.Title,
metadata.Disambiguation,
metadata.Biography,
Artwork(metadata, ArtworkKind.Thumbnail),
Artwork(metadata, ArtworkKind.FanArt),
metadata.Genres.Map(g => g.Name).ToList(),
metadata.Styles.Map(s => s.Name).ToList(),
metadata.Moods.Map(m => m.Name).ToList(),
LanguagesForArtist(languages));
}
ArtistMetadata metadata = Optional(artist.ArtistMetadata).Flatten().Head();
return new ArtistViewModel(
metadata.Title,
metadata.Disambiguation,
metadata.Biography,
Artwork(metadata, ArtworkKind.Thumbnail),
Artwork(metadata, ArtworkKind.FanArt),
metadata.Genres.Map(g => g.Name).ToList(),
metadata.Styles.Map(s => s.Name).ToList(),
metadata.Moods.Map(m => m.Name).ToList(),
LanguagesForArtist(languages));
}
private static string Artwork(Metadata metadata, ArtworkKind artworkKind) =>
Optional(metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == artworkKind))
.Match(a => a.Path, string.Empty);
private static string Artwork(Metadata metadata, ArtworkKind artworkKind) =>
Optional(metadata.Artwork.FirstOrDefault(a => a.ArtworkKind == artworkKind))
.Match(a => a.Path, string.Empty);
private static List<CultureInfo> LanguagesForArtist(List<string> languages)
{
CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
private static List<CultureInfo> LanguagesForArtist(List<string> languages)
{
CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
return languages
.Distinct()
.Map(
lang => allCultures.Filter(
ci => string.Equals(ci.ThreeLetterISOLanguageName, lang, StringComparison.OrdinalIgnoreCase)))
.Sequence()
.Flatten()
.ToList();
}
return languages
.Map(lang => allCultures.Filter(ci => string.Equals(
ci.ThreeLetterISOLanguageName,
lang,
StringComparison.OrdinalIgnoreCase)))
.Flatten()
.Distinct()
.ToList();
}
}

View File

@@ -1,8 +1,5 @@
using System.Collections.Generic;
using ErsatzTV.Application.MediaItems;
using MediatR;
using ErsatzTV.Application.MediaItems;
namespace ErsatzTV.Application.Artists.Queries
{
public record GetAllArtists : IRequest<List<NamedMediaItemViewModel>>;
}
namespace ErsatzTV.Application.Artists;
public record GetAllArtists : IRequest<List<NamedMediaItemViewModel>>;

View File

@@ -1,29 +1,41 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Application.MediaItems;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using ErsatzTV.Application.MediaItems;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.MediaItems.Mapper;
namespace ErsatzTV.Application.Artists.Queries
namespace ErsatzTV.Application.Artists;
public class GetAllArtistsHandler : IRequestHandler<GetAllArtists, List<NamedMediaItemViewModel>>
{
public class GetAllArtistsHandler : IRequestHandler<GetAllArtists, List<NamedMediaItemViewModel>>
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetAllArtistsHandler(IDbContextFactory<TvContext> dbContextFactory) => _dbContextFactory = dbContextFactory;
public async Task<List<NamedMediaItemViewModel>> Handle(
GetAllArtists request,
CancellationToken cancellationToken)
{
private readonly IArtistRepository _artistRepository;
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
public GetAllArtistsHandler(IArtistRepository artistRepository) => _artistRepository = artistRepository;
List<Artist> allArtists = await dbContext.Artists
.AsNoTracking()
.Include(a => a.ArtistMetadata)
.ToListAsync(cancellationToken);
public Task<List<NamedMediaItemViewModel>> Handle(
GetAllArtists request,
CancellationToken cancellationToken) =>
_artistRepository.GetAllArtists()
.Map(
list => list.Filter(
a => !string.IsNullOrWhiteSpace(
a.ArtistMetadata.HeadOrNone().Match(am => am.Title, () => string.Empty))))
.Map(list => list.Map(ProjectToViewModel).ToList());
return allArtists.Bind(a => ProjectArtist(a)).ToList();
}
private static Option<NamedMediaItemViewModel> ProjectArtist(Artist a)
{
foreach (ArtistMetadata metadata in a.ArtistMetadata.HeadOrNone())
{
if (!string.IsNullOrWhiteSpace(metadata.Title))
{
return ProjectToViewModel(a);
}
}
return None;
}
}

View File

@@ -1,7 +1,3 @@
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Artists;
namespace ErsatzTV.Application.Artists.Queries
{
public record GetArtistById(int ArtistId) : IRequest<Option<ArtistViewModel>>;
}
public record GetArtistById(int ArtistId) : IRequest<Option<ArtistViewModel>>;

View File

@@ -1,38 +1,28 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using static ErsatzTV.Application.Artists.Mapper;
namespace ErsatzTV.Application.Artists.Queries
namespace ErsatzTV.Application.Artists;
public class GetArtistByIdHandler(
IArtistRepository artistRepository,
ISearchRepository searchRepository,
ILanguageCodeService languageCodeService)
: IRequestHandler<GetArtistById, Option<ArtistViewModel>>
{
public class GetArtistByIdHandler : IRequestHandler<GetArtistById, Option<ArtistViewModel>>
public async Task<Option<ArtistViewModel>> Handle(
GetArtistById request,
CancellationToken cancellationToken)
{
private readonly IArtistRepository _artistRepository;
private readonly ISearchRepository _searchRepository;
public GetArtistByIdHandler(IArtistRepository artistRepository, ISearchRepository searchRepository)
{
_artistRepository = artistRepository;
_searchRepository = searchRepository;
}
public async Task<Option<ArtistViewModel>> Handle(
GetArtistById request,
CancellationToken cancellationToken)
{
Option<Artist> maybeArtist = await _artistRepository.GetArtist(request.ArtistId);
return await maybeArtist.Match<Task<Option<ArtistViewModel>>>(
async artist =>
{
List<string> mediaCodes = await _searchRepository.GetLanguagesForArtist(artist);
List<string> languageCodes = await _searchRepository.GetAllLanguageCodes(mediaCodes);
return ProjectToViewModel(artist, languageCodes);
},
() => Task.FromResult(Option<ArtistViewModel>.None));
}
Option<Artist> maybeArtist = await artistRepository.GetArtist(request.ArtistId);
return await maybeArtist.Match<Task<Option<ArtistViewModel>>>(
async artist =>
{
List<string> mediaCodes = await searchRepository.GetLanguagesForArtist(artist);
List<string> languageCodes = languageCodeService.GetAllLanguageCodes(mediaCodes);
return ProjectToViewModel(artist, languageCodes);
},
() => Task.FromResult(Option<ArtistViewModel>.None));
}
}

View File

@@ -0,0 +1,17 @@
using System.Net;
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Application.Artworks;
public record ArtworkContentTypeModel(string Path, string ContentType)
{
public static readonly ArtworkContentTypeModel None = new(string.Empty, string.Empty);
public bool IsExternalUrl => Artwork.IsExternalUrl(Path);
public bool HasContentType => !string.IsNullOrWhiteSpace(ContentType);
public string UrlWithContentType => string.IsNullOrWhiteSpace(ContentType)
? Path
: $"{Path}?contentType={WebUtility.UrlEncode(ContentType)}";
}

View File

@@ -0,0 +1,6 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Application.Artworks;
public record GetArtwork(int Id) : IRequest<Either<BaseError, Artwork>>;

View File

@@ -0,0 +1,42 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Artworks;
public class GetArtworkHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetArtwork, Either<BaseError, Artwork>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory = dbContextFactory;
public async Task<Either<BaseError, Artwork>> Handle(
GetArtwork request,
CancellationToken cancellationToken)
{
try
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Option<Artwork> artwork = await dbContext.Artwork
.AsNoTracking()
.SelectOneAsync(a => a.Id, a => a.Id == request.Id, cancellationToken)
.MapT(Project);
return artwork.ToEither(BaseError.New("Artwork not found"));
}
catch (Exception ex)
{
return BaseError.New(ex.ToString());
}
}
private static Artwork Project(Artwork artwork) =>
new()
{
Id = artwork.Id,
Path = artwork.Path,
ArtworkKind = artwork.ArtworkKind
};
}

View File

@@ -0,0 +1,10 @@
namespace ErsatzTV.Application.Channels;
public class ChannelSortViewModel
{
public int Id { get; set; }
public string Number { get; set; }
public string Name { get; set; }
public string OriginalNumber { get; set; }
public bool HasChanged => OriginalNumber != Number;
}

View File

@@ -0,0 +1,11 @@
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Application.Channels;
public record ChannelStreamingSpecsViewModel(
int Height,
int Width,
int Bitrate,
FFmpegProfileVideoFormat VideoFormat,
string VideoProfile,
FFmpegProfileAudioFormat AudioFormat);

View File

@@ -1,14 +1,39 @@
using ErsatzTV.Core.Domain;
using System.Net;
using ErsatzTV.Application.Artworks;
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Application.Channels
namespace ErsatzTV.Application.Channels;
public record ChannelViewModel(
int Id,
string Number,
string Name,
string Group,
string Categories,
int FFmpegProfileId,
double? SlugSeconds,
ArtworkContentTypeModel Logo,
ChannelStreamSelectorMode StreamSelectorMode,
string StreamSelector,
string PreferredAudioLanguageCode,
string PreferredAudioTitle,
ChannelPlayoutSource PlayoutSource,
ChannelPlayoutMode PlayoutMode,
int? MirrorSourceChannelId,
TimeSpan? PlayoutOffset,
StreamingMode StreamingMode,
int? WatermarkId,
int? FallbackFillerId,
int PlayoutCount,
string PreferredSubtitleLanguageCode,
ChannelSubtitleMode SubtitleMode,
ChannelMusicVideoCreditsMode MusicVideoCreditsMode,
string MusicVideoCreditsTemplate,
ChannelSongVideoMode SongVideoMode,
ChannelTranscodeMode TranscodeMode,
ChannelIdleBehavior IdleBehavior,
bool IsEnabled,
bool ShowInEpg)
{
public record ChannelViewModel(
int Id,
string Number,
string Name,
int FFmpegProfileId,
string Logo,
string PreferredLanguageCode,
StreamingMode StreamingMode,
int? WatermarkId);
public string WebEncodedName => WebUtility.UrlEncode(Name);
}

View File

@@ -1,17 +1,34 @@
using ErsatzTV.Core;
using ErsatzTV.Application.Artworks;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Channels.Commands
{
public record CreateChannel
(
string Name,
string Number,
int FFmpegProfileId,
string Logo,
string PreferredLanguageCode,
StreamingMode StreamingMode,
int? WatermarkId) : IRequest<Either<BaseError, CreateChannelResult>>;
}
namespace ErsatzTV.Application.Channels;
public record CreateChannel(
string Name,
string Number,
string Group,
string Categories,
int FFmpegProfileId,
double? SlugSeconds,
ArtworkContentTypeModel Logo,
ChannelStreamSelectorMode StreamSelectorMode,
string StreamSelector,
string PreferredAudioLanguageCode,
string PreferredAudioTitle,
ChannelPlayoutSource PlayoutSource,
ChannelPlayoutMode PlayoutMode,
int? MirrorSourceChannelId,
TimeSpan? PlayoutOffset,
StreamingMode StreamingMode,
int? WatermarkId,
int? FallbackFillerId,
string PreferredSubtitleLanguageCode,
ChannelSubtitleMode SubtitleMode,
ChannelMusicVideoCreditsMode MusicVideoCreditsMode,
string MusicVideoCreditsTemplate,
ChannelSongVideoMode SongVideoMode,
ChannelTranscodeMode TranscodeMode,
ChannelIdleBehavior IdleBehavior,
bool IsEnabled,
bool ShowInEpg) : IRequest<Either<BaseError, CreateChannelResult>>;

View File

@@ -1,135 +1,242 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using LanguageExt;
using MediatR;
using Microsoft.EntityFrameworkCore;
using static LanguageExt.Prelude;
using Channel = ErsatzTV.Core.Domain.Channel;
namespace ErsatzTV.Application.Channels.Commands
namespace ErsatzTV.Application.Channels;
public class CreateChannelHandler(
ChannelWriter<IBackgroundServiceRequest> workerChannel,
IDbContextFactory<TvContext> dbContextFactory,
ISearchTargets searchTargets)
: IRequestHandler<CreateChannel, Either<BaseError, CreateChannelResult>>
{
public class CreateChannelHandler : IRequestHandler<CreateChannel, Either<BaseError, CreateChannelResult>>
public async Task<Either<BaseError, CreateChannelResult>> Handle(
CreateChannel request,
CancellationToken cancellationToken)
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Channel> validation = await Validate(dbContext, request, cancellationToken);
return await validation.Apply(c => PersistChannel(dbContext, c));
}
public CreateChannelHandler(IDbContextFactory<TvContext> dbContextFactory) => _dbContextFactory = dbContextFactory;
private async Task<CreateChannelResult> PersistChannel(TvContext dbContext, Channel channel)
{
await dbContext.Channels.AddAsync(channel);
await dbContext.SaveChangesAsync();
searchTargets.SearchTargetsChanged();
await workerChannel.WriteAsync(new RefreshChannelList());
return new CreateChannelResult(channel.Id);
}
public async Task<Either<BaseError, CreateChannelResult>> Handle(
CreateChannel request,
CancellationToken cancellationToken)
private static async Task<Validation<BaseError, Channel>> Validate(TvContext dbContext, CreateChannel request, CancellationToken cancellationToken) =>
(ValidateName(request), await ValidateNumber(dbContext, request, cancellationToken),
await FFmpegProfileMustExist(dbContext, request, cancellationToken),
await WatermarkMustExist(dbContext, request, cancellationToken),
await FillerPresetMustExist(dbContext, request, cancellationToken),
await MirrorSourceMustBeValid(dbContext, request, cancellationToken))
.Apply((
name,
number,
ffmpegProfileId,
watermarkId,
fillerPresetId,
_) =>
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, Channel> validation = await Validate(dbContext, request);
return await validation.Apply(c => PersistChannel(dbContext, c));
}
private static async Task<CreateChannelResult> PersistChannel(TvContext dbContext, Channel channel)
{
await dbContext.Channels.AddAsync(channel);
await dbContext.SaveChangesAsync();
return new CreateChannelResult(channel.Id);
}
private static async Task<Validation<BaseError, Channel>> Validate(TvContext dbContext, CreateChannel request) =>
(ValidateName(request), await ValidateNumber(dbContext, request),
await FFmpegProfileMustExist(dbContext, request),
ValidatePreferredLanguage(request),
await WatermarkMustExist(dbContext, request))
.Apply(
(name, number, ffmpegProfileId, preferredLanguageCode, watermarkId) =>
{
var artwork = new List<Artwork>();
if (!string.IsNullOrWhiteSpace(request.Logo))
{
artwork.Add(
new Artwork
{
Path = request.Logo,
ArtworkKind = ArtworkKind.Logo,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow
});
}
var channel = new Channel(Guid.NewGuid())
{
Name = name,
Number = number,
FFmpegProfileId = ffmpegProfileId,
StreamingMode = request.StreamingMode,
Artwork = artwork,
PreferredLanguageCode = preferredLanguageCode
};
foreach (int id in watermarkId)
{
channel.WatermarkId = id;
}
return channel;
});
private static Validation<BaseError, string> ValidateName(CreateChannel createChannel) =>
createChannel.NotEmpty(c => c.Name)
.Bind(_ => createChannel.NotLongerThan(50)(c => c.Name));
private static Validation<BaseError, string> ValidatePreferredLanguage(CreateChannel createChannel) =>
Optional(createChannel.PreferredLanguageCode ?? string.Empty)
.Filter(
lc => string.IsNullOrWhiteSpace(lc) || CultureInfo.GetCultures(CultureTypes.NeutralCultures).Any(
ci => string.Equals(ci.ThreeLetterISOLanguageName, lc, StringComparison.OrdinalIgnoreCase)))
.ToValidation<BaseError>("Preferred language code is invalid");
private static async Task<Validation<BaseError, string>> ValidateNumber(TvContext dbContext, CreateChannel createChannel)
{
Option<Channel> maybeExistingChannel = await dbContext.Channels
.SelectOneAsync(c => c.Number, c => c.Number == createChannel.Number);
return maybeExistingChannel.Match<Validation<BaseError, string>>(
_ => BaseError.New("Channel number must be unique"),
() =>
{
if (Regex.IsMatch(createChannel.Number, Channel.NumberValidator))
{
return createChannel.Number;
}
return BaseError.New("Invalid channel number; one decimal is allowed for subchannels");
});
}
private static Task<Validation<BaseError, int>> FFmpegProfileMustExist(
TvContext dbContext,
CreateChannel createChannel) =>
dbContext.FFmpegProfiles
.CountAsync(p => p.Id == createChannel.FFmpegProfileId)
.Map(Optional)
.Filter(c => c > 0)
.MapT(_ => createChannel.FFmpegProfileId)
.Map(o => o.ToValidation<BaseError>($"FFmpegProfile {createChannel.FFmpegProfileId} does not exist."));
private static async Task<Validation<BaseError, Option<int>>> WatermarkMustExist(
TvContext dbContext,
CreateChannel createChannel)
{
if (createChannel.WatermarkId is null)
var artwork = new List<Artwork>();
if (!string.IsNullOrWhiteSpace(request.Logo?.Path))
{
return Option<int>.None;
string logo = request.Logo.Path;
if (logo.StartsWith("iptv/logos/", StringComparison.Ordinal))
{
logo = logo.Replace("iptv/logos/", string.Empty);
}
artwork.Add(
new Artwork
{
Path = logo,
ArtworkKind = ArtworkKind.Logo,
OriginalContentType = !string.IsNullOrEmpty(request.Logo.ContentType)
? request.Logo.ContentType
: null,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow
});
}
return await dbContext.ChannelWatermarks
.CountAsync(w => w.Id == createChannel.WatermarkId)
.Map(Optional)
.Filter(c => c > 0)
.MapT(_ => Optional(createChannel.WatermarkId))
.Map(o => o.ToValidation<BaseError>($"Watermark {createChannel.WatermarkId} does not exist."));
var channel = new Channel(Guid.NewGuid())
{
Name = name,
Number = number,
SortNumber = double.Parse(number, CultureInfo.InvariantCulture),
Group = request.Group,
Categories = request.Categories,
FFmpegProfileId = ffmpegProfileId,
SlugSeconds = request.SlugSeconds,
PlayoutSource = request.PlayoutSource,
PlayoutMode = request.PlayoutMode,
MirrorSourceChannelId = request.MirrorSourceChannelId,
PlayoutOffset = request.PlayoutOffset,
StreamingMode = request.StreamingMode,
Artwork = artwork,
StreamSelectorMode = request.StreamSelectorMode,
StreamSelector = request.StreamSelector,
PreferredAudioLanguageCode = request.PreferredAudioLanguageCode,
PreferredAudioTitle = request.PreferredAudioTitle,
PreferredSubtitleLanguageCode = request.PreferredSubtitleLanguageCode,
SubtitleMode = request.SubtitleMode,
MusicVideoCreditsMode = request.MusicVideoCreditsMode,
MusicVideoCreditsTemplate = request.MusicVideoCreditsTemplate,
SongVideoMode = request.SongVideoMode,
TranscodeMode = request.TranscodeMode,
IdleBehavior = request.IdleBehavior,
IsEnabled = request.IsEnabled,
ShowInEpg = request.IsEnabled && request.ShowInEpg
};
if (channel.PlayoutSource is ChannelPlayoutSource.Mirror)
{
channel.PlayoutMode = ChannelPlayoutMode.Continuous;
}
else
{
channel.MirrorSourceChannelId = null;
channel.PlayoutOffset = null;
}
foreach (int id in watermarkId)
{
channel.WatermarkId = id;
}
foreach (int id in fillerPresetId)
{
channel.FallbackFillerId = id;
}
return channel;
});
private static Validation<BaseError, string> ValidateName(CreateChannel createChannel) =>
createChannel.NotEmpty(c => c.Name)
.Bind(_ => createChannel.NotLongerThan(50)(c => c.Name));
private static async Task<Validation<BaseError, string>> ValidateNumber(
TvContext dbContext,
CreateChannel createChannel,
CancellationToken cancellationToken)
{
Option<Channel> maybeExistingChannel = await dbContext.Channels
.SelectOneAsync(c => c.Number, c => c.Number == createChannel.Number, cancellationToken);
return maybeExistingChannel.Match<Validation<BaseError, string>>(
_ => BaseError.New("Channel number must be unique"),
() =>
{
if (Regex.IsMatch(createChannel.Number, Channel.NumberValidator))
{
return createChannel.Number;
}
return BaseError.New("Invalid channel number; two decimals are allowed for subchannels");
});
}
private static Task<Validation<BaseError, int>> FFmpegProfileMustExist(
TvContext dbContext,
CreateChannel createChannel,
CancellationToken cancellationToken) =>
dbContext.FFmpegProfiles
.CountAsync(p => p.Id == createChannel.FFmpegProfileId, cancellationToken)
.Map(Optional)
.Filter(c => c > 0)
.MapT(_ => createChannel.FFmpegProfileId)
.Map(o => o.ToValidation<BaseError>($"FFmpegProfile {createChannel.FFmpegProfileId} does not exist."));
private static async Task<Validation<BaseError, Option<int>>> WatermarkMustExist(
TvContext dbContext,
CreateChannel createChannel,
CancellationToken cancellationToken)
{
if (createChannel.WatermarkId is null)
{
return Option<int>.None;
}
return await dbContext.ChannelWatermarks
.CountAsync(w => w.Id == createChannel.WatermarkId, cancellationToken)
.Map(Optional)
.Filter(c => c > 0)
.MapT(_ => Optional(createChannel.WatermarkId))
.Map(o => o.ToValidation<BaseError>($"Watermark {createChannel.WatermarkId} does not exist."));
}
private static async Task<Validation<BaseError, Option<int>>> FillerPresetMustExist(
TvContext dbContext,
CreateChannel createChannel,
CancellationToken cancellationToken)
{
if (createChannel.FallbackFillerId is null)
{
return Option<int>.None;
}
return await dbContext.FillerPresets
.Filter(fp => fp.FillerKind == FillerKind.Fallback)
.CountAsync(w => w.Id == createChannel.FallbackFillerId, cancellationToken)
.Map(Optional)
.Filter(c => c > 0)
.MapT(_ => Optional(createChannel.FallbackFillerId))
.Map(o => o.ToValidation<BaseError>(
$"Fallback filler {createChannel.FallbackFillerId} does not exist."));
}
private static async Task<Validation<BaseError, Unit>> MirrorSourceMustBeValid(
TvContext dbContext,
CreateChannel createChannel,
CancellationToken cancellationToken)
{
if (createChannel.PlayoutSource is not ChannelPlayoutSource.Mirror)
{
return Unit.Default;
}
Option<Channel> maybeMirrorSource = await dbContext.Channels
.AsNoTracking()
.SelectOneAsync(
c => c.Id == createChannel.MirrorSourceChannelId,
c => c.Id == createChannel.MirrorSourceChannelId,
cancellationToken);
if (maybeMirrorSource.IsNone)
{
return BaseError.New("Mirror source channel does not exist.");
}
foreach (var mirrorSource in maybeMirrorSource)
{
if (mirrorSource.PlayoutSource is not ChannelPlayoutSource.Generated)
{
return BaseError.New(
$"Mirror source channel {mirrorSource.Name} must use generated playout source");
}
}
foreach (TimeSpan playoutOffset in Optional(createChannel.PlayoutOffset))
{
if (playoutOffset < TimeSpan.FromHours(-12) || playoutOffset > TimeSpan.FromHours(12))
{
return BaseError.New("Playout offset must not be greater than 12 hours");
}
}
return Unit.Default;
}
}

View File

@@ -1,4 +1,3 @@
namespace ErsatzTV.Application.Channels.Commands
{
public record CreateChannelResult(int ChannelId) : EntityIdResult(ChannelId);
}
namespace ErsatzTV.Application.Channels;
public record CreateChannelResult(int ChannelId) : EntityIdResult(ChannelId);

View File

@@ -1,9 +1,5 @@
using System.Threading.Tasks;
using ErsatzTV.Core;
using LanguageExt;
using MediatR;
using ErsatzTV.Core;
namespace ErsatzTV.Application.Channels.Commands
{
public record DeleteChannel(int ChannelId) : IRequest<Either<BaseError, Task>>;
}
namespace ErsatzTV.Application.Channels;
public record DeleteChannel(int ChannelId) : IRequest<Either<BaseError, Unit>>;

View File

@@ -1,28 +1,67 @@
using System.Threading;
using System.Threading.Tasks;
using System.IO.Abstractions;
using System.Threading.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
using Channel = ErsatzTV.Core.Domain.Channel;
namespace ErsatzTV.Application.Channels.Commands
namespace ErsatzTV.Application.Channels;
public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseError, Unit>>
{
public class DeleteChannelHandler : IRequestHandler<DeleteChannel, Either<BaseError, Task>>
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IFileSystem _fileSystem;
private readonly ISearchTargets _searchTargets;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public DeleteChannelHandler(
ChannelWriter<IBackgroundServiceRequest> workerChannel,
IDbContextFactory<TvContext> dbContextFactory,
IFileSystem fileSystem,
ISearchTargets searchTargets)
{
private readonly IChannelRepository _channelRepository;
_workerChannel = workerChannel;
_dbContextFactory = dbContextFactory;
_fileSystem = fileSystem;
_searchTargets = searchTargets;
}
public DeleteChannelHandler(IChannelRepository channelRepository) => _channelRepository = channelRepository;
public async Task<Either<BaseError, Unit>> Handle(DeleteChannel request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Channel> validation = await ChannelMustExist(dbContext, request, cancellationToken);
return await validation.Apply(c => DoDeletion(dbContext, c, cancellationToken));
}
public async Task<Either<BaseError, Task>> Handle(DeleteChannel request, CancellationToken cancellationToken) =>
(await ChannelMustExist(request))
.Map(DoDeletion)
.ToEither<Task>();
private async Task<Unit> DoDeletion(TvContext dbContext, Channel channel, CancellationToken cancellationToken)
{
dbContext.Channels.Remove(channel);
await dbContext.SaveChangesAsync(cancellationToken);
private Task DoDeletion(int channelId) => _channelRepository.Delete(channelId);
_searchTargets.SearchTargetsChanged();
private async Task<Validation<BaseError, int>> ChannelMustExist(DeleteChannel deleteChannel) =>
(await _channelRepository.Get(deleteChannel.ChannelId))
.ToValidation<BaseError>($"Channel {deleteChannel.ChannelId} does not exist.")
.Map(c => c.Id);
// delete channel data from channel guide cache
string cacheFile = Path.Combine(FileSystemLayout.ChannelGuideCacheFolder, $"{channel.Number}.xml");
if (_fileSystem.File.Exists(cacheFile))
{
File.Delete(cacheFile);
}
// refresh channel list to remove channel that has no playout
await _workerChannel.WriteAsync(new RefreshChannelList(), cancellationToken);
return Unit.Default;
}
private static async Task<Validation<BaseError, Channel>> ChannelMustExist(
TvContext dbContext,
DeleteChannel deleteChannel,
CancellationToken cancellationToken)
{
Option<Channel> maybeChannel = await dbContext.Channels
.SelectOneAsync(c => c.Id, c => c.Id == deleteChannel.ChannelId, cancellationToken);
return maybeChannel.ToValidation<BaseError>($"Channel {deleteChannel.ChannelId} does not exist.");
}
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record RefreshChannelData(string ChannelNumber) : IRequest, IBackgroundServiceRequest;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record RefreshChannelList : IRequest, IBackgroundServiceRequest;

View File

@@ -0,0 +1,151 @@
using System.Data.Common;
using System.IO.Abstractions;
using System.Net;
using System.Xml;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Iptv;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.IO;
using Scriban;
using Scriban.Runtime;
using WebMarkupMin.Core;
namespace ErsatzTV.Application.Channels;
public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IFileSystem _fileSystem;
private readonly ILocalFileSystem _localFileSystem;
private readonly ILogger<RefreshChannelListHandler> _logger;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
public RefreshChannelListHandler(
RecyclableMemoryStreamManager recyclableMemoryStreamManager,
IDbContextFactory<TvContext> dbContextFactory,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem,
ILogger<RefreshChannelListHandler> logger)
{
_recyclableMemoryStreamManager = recyclableMemoryStreamManager;
_dbContextFactory = dbContextFactory;
_fileSystem = fileSystem;
_localFileSystem = localFileSystem;
_logger = logger;
}
public async Task Handle(RefreshChannelList request, CancellationToken cancellationToken)
{
_localFileSystem.EnsureFolderExists(FileSystemLayout.ChannelGuideCacheFolder);
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
string templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "channel.sbntxt");
// fall back to default template
if (!_fileSystem.File.Exists(templateFileName))
{
templateFileName = Path.Combine(FileSystemLayout.ChannelGuideTemplatesFolder, "_channel.sbntxt");
}
// fail if file doesn't exist
if (!_fileSystem.File.Exists(templateFileName))
{
_logger.LogError(
"Unable to generate channel list without template file {File}; please restart ErsatzTV",
templateFileName);
return;
}
var minifier = new XmlMinifier(
new XmlMinificationSettings
{
MinifyWhitespace = true,
RemoveXmlComments = true,
CollapseTagsWithoutContent = true
});
string text = await File.ReadAllTextAsync(templateFileName, cancellationToken);
var template = Template.Parse(text, templateFileName);
var templateContext = new XmlTemplateContext();
await using RecyclableMemoryStream ms = _recyclableMemoryStreamManager.GetStream();
await using var xml = XmlWriter.Create(
ms,
new XmlWriterSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment });
await foreach (ChannelResult channel in GetChannels(dbContext).WithCancellation(cancellationToken))
{
bool hasLogo = !string.IsNullOrWhiteSpace(channel.ArtworkPath);
bool hasExternalLogo = hasLogo && Artwork.IsExternalUrl(channel.ArtworkPath);
var data = new
{
ChannelId = ChannelIdentifier.FromNumber(channel.Number),
ChannelIdLegacy = ChannelIdentifier.LegacyFromNumber(channel.Number),
ChannelNumber = channel.Number,
ChannelName = channel.Name,
ChannelCategories = GetCategories(channel.Categories),
ChannelHasExternalArtwork = hasExternalLogo,
ChannelHasArtwork = hasLogo,
ChannelArtworkPath = channel.ArtworkPath,
ChannelNameEncoded = WebUtility.UrlEncode(channel.Name)
};
var scriptObject = new ScriptObject();
scriptObject.Import(data);
templateContext.PushGlobal(scriptObject);
string result = await template.RenderAsync(templateContext);
MarkupMinificationResult minified = minifier.Minify(result);
await xml.WriteRawAsync(minified.MinifiedContent);
}
await xml.FlushAsync();
string tempFile = Path.GetTempFileName();
await File.WriteAllBytesAsync(tempFile, ms.ToArray(), cancellationToken);
string targetFile = Path.Combine(FileSystemLayout.ChannelGuideCacheFolder, "channels.xml");
File.Move(tempFile, targetFile, true);
}
private static async IAsyncEnumerable<ChannelResult> GetChannels(TvContext dbContext)
{
const string QUERY = @"select C.Number, C.Name, C.Categories, A.Path as ArtworkPath
from Channel C
left outer join Artwork A on C.Id = A.ChannelId and A.ArtworkKind = 2
where (C.Id in (select ChannelId from Playout) or C.MirrorSourceChannelId in (select ChannelId from Playout)) and C.IsEnabled = 1 and C.ShowInEPG = 1
order by CAST(C.Number as double)";
// TODO: this needs to be fixed for sqlite/mariadb
await using var reader = (DbDataReader)await dbContext.Connection.ExecuteReaderAsync(QUERY);
Func<DbDataReader, ChannelResult> rowParser = reader.GetRowParser<ChannelResult>();
while (await reader.ReadAsync())
{
yield return rowParser(reader);
}
while (await reader.NextResultAsync())
{
}
}
private static List<string> GetCategories(string categories) =>
(categories ?? string.Empty).Split(',')
.Map(s => s.Trim())
.Filter(s => !string.IsNullOrWhiteSpace(s))
.Distinct()
.ToList();
// ReSharper disable once ClassNeverInstantiated.Local
private sealed record ChannelResult(string Number, string Name, string Categories, string ArtworkPath);
}

View File

@@ -1,18 +1,35 @@
using ErsatzTV.Core;
using ErsatzTV.Application.Artworks;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Channels.Commands
{
public record UpdateChannel
(
int ChannelId,
string Name,
string Number,
int FFmpegProfileId,
string Logo,
string PreferredLanguageCode,
StreamingMode StreamingMode,
int? WatermarkId) : IRequest<Either<BaseError, ChannelViewModel>>;
}
namespace ErsatzTV.Application.Channels;
public record UpdateChannel(
int ChannelId,
string Name,
string Number,
string Group,
string Categories,
int FFmpegProfileId,
double? SlugSeconds,
ArtworkContentTypeModel Logo,
ChannelStreamSelectorMode StreamSelectorMode,
string StreamSelector,
string PreferredAudioLanguageCode,
string PreferredAudioTitle,
ChannelPlayoutSource PlayoutSource,
ChannelPlayoutMode PlayoutMode,
int? MirrorSourceChannelId,
TimeSpan? PlayoutOffset,
StreamingMode StreamingMode,
int? WatermarkId,
int? FallbackFillerId,
string PreferredSubtitleLanguageCode,
ChannelSubtitleMode SubtitleMode,
ChannelMusicVideoCreditsMode MusicVideoCreditsMode,
string MusicVideoCreditsTemplate,
ChannelSongVideoMode SongVideoMode,
ChannelTranscodeMode TranscodeMode,
ChannelIdleBehavior IdleBehavior,
bool IsEnabled,
bool ShowInEpg) : IRequest<Either<BaseError, ChannelViewModel>>;

View File

@@ -1,121 +1,250 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Channels;
using ErsatzTV.Application.Subtitles;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using LanguageExt;
using MediatR;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.Channels.Mapper;
using static LanguageExt.Prelude;
using Channel = ErsatzTV.Core.Domain.Channel;
namespace ErsatzTV.Application.Channels.Commands
namespace ErsatzTV.Application.Channels;
public class UpdateChannelHandler(
ChannelWriter<IBackgroundServiceRequest> workerChannel,
IDbContextFactory<TvContext> dbContextFactory,
ISearchTargets searchTargets)
: IRequestHandler<UpdateChannel, Either<BaseError, ChannelViewModel>>
{
public class UpdateChannelHandler : IRequestHandler<UpdateChannel, Either<BaseError, ChannelViewModel>>
public async Task<Either<BaseError, ChannelViewModel>> Handle(
UpdateChannel request,
CancellationToken cancellationToken)
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Channel> validation = await Validate(dbContext, request, cancellationToken);
return await validation.Apply(c => ApplyUpdateRequest(dbContext, c, request, cancellationToken));
}
public UpdateChannelHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<Either<BaseError, ChannelViewModel>> Handle(
UpdateChannel request,
CancellationToken cancellationToken)
private async Task<ChannelViewModel> ApplyUpdateRequest(
TvContext dbContext,
Channel c,
UpdateChannel update,
CancellationToken cancellationToken)
{
// don't save mirror when playout exists
if (c.Playouts.Count > 0)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, Channel> validation = await Validate(dbContext, request);
return await validation.Apply(c => ApplyUpdateRequest(dbContext, c, request));
update = update with
{
PlayoutSource = ChannelPlayoutSource.Generated,
MirrorSourceChannelId = null
};
}
private async Task<ChannelViewModel> ApplyUpdateRequest(TvContext dbContext, Channel c, UpdateChannel update)
bool hasEpgChange = c.PlayoutSource != update.PlayoutSource || c.ShowInEpg != update.ShowInEpg;
c.Name = update.Name;
c.Number = update.Number;
c.SortNumber = double.Parse(update.Number, CultureInfo.InvariantCulture);
c.Group = update.Group;
c.Categories = update.Categories;
c.FFmpegProfileId = update.FFmpegProfileId;
c.SlugSeconds = update.SlugSeconds;
c.StreamSelectorMode = update.StreamSelectorMode;
c.StreamSelector = update.StreamSelector;
c.PreferredAudioLanguageCode = update.PreferredAudioLanguageCode;
c.PreferredAudioTitle = update.PreferredAudioTitle;
c.PreferredSubtitleLanguageCode = update.PreferredSubtitleLanguageCode;
c.SubtitleMode = update.SubtitleMode;
c.MusicVideoCreditsMode = update.MusicVideoCreditsMode;
c.MusicVideoCreditsTemplate = update.MusicVideoCreditsTemplate;
c.SongVideoMode = update.SongVideoMode;
c.TranscodeMode = update.TranscodeMode;
c.IdleBehavior = update.IdleBehavior;
c.IsEnabled = update.IsEnabled;
c.ShowInEpg = update.IsEnabled && update.ShowInEpg;
c.Artwork ??= [];
if (!string.IsNullOrWhiteSpace(update.Logo?.Path))
{
c.Name = update.Name;
c.Number = update.Number;
c.FFmpegProfileId = update.FFmpegProfileId;
c.PreferredLanguageCode = update.PreferredLanguageCode;
c.Artwork ??= new List<Artwork>();
if (!string.IsNullOrWhiteSpace(update.Logo))
string logo = update.Logo.Path;
if (logo.StartsWith("iptv/logos/", StringComparison.Ordinal))
{
Option<Artwork> maybeLogo =
Optional(c.Artwork).Flatten().FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Logo);
maybeLogo.Match(
artwork =>
{
artwork.Path = update.Logo;
artwork.DateUpdated = DateTime.UtcNow;
},
() =>
{
var artwork = new Artwork
{
Path = update.Logo,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow,
ArtworkKind = ArtworkKind.Logo
};
c.Artwork.Add(artwork);
});
logo = logo.Replace("iptv/logos/", string.Empty);
}
c.StreamingMode = update.StreamingMode;
c.WatermarkId = update.WatermarkId;
await dbContext.SaveChangesAsync();
return ProjectToViewModel(c);
}
private async Task<Validation<BaseError, Channel>> Validate(TvContext dbContext, UpdateChannel request) =>
(await ChannelMustExist(dbContext, request), ValidateName(request),
await ValidateNumber(dbContext, request),
ValidatePreferredLanguage(request))
.Apply((channelToUpdate, _, _, _) => channelToUpdate);
private static Task<Validation<BaseError, Channel>> ChannelMustExist(
TvContext dbContext,
UpdateChannel updateChannel) =>
dbContext.Channels
.Include(c => c.Artwork)
.Include(c => c.Watermark)
.SelectOneAsync(c => c.Id, c => c.Id == updateChannel.ChannelId)
.Map(o => o.ToValidation<BaseError>("Channel does not exist."));
private static Validation<BaseError, string> ValidateName(UpdateChannel updateChannel) =>
updateChannel.NotEmpty(c => c.Name)
.Bind(_ => updateChannel.NotLongerThan(50)(c => c.Name));
private static async Task<Validation<BaseError, string>> ValidateNumber(
TvContext dbContext,
UpdateChannel updateChannel)
{
int matchId = await dbContext.Channels
.SelectOneAsync(c => c.Number, c => c.Number == updateChannel.Number)
.Match(c => c.Id, () => updateChannel.ChannelId);
if (matchId == updateChannel.ChannelId)
Option<Artwork> maybeLogo = c.Artwork.Where(a => a.ArtworkKind == ArtworkKind.Logo).HeadOrNone();
foreach (Artwork artwork in maybeLogo)
{
if (Regex.IsMatch(updateChannel.Number, Channel.NumberValidator))
artwork.Path = logo;
artwork.OriginalContentType = !string.IsNullOrEmpty(update.Logo.ContentType)
? update.Logo.ContentType
: null;
artwork.DateUpdated = DateTime.UtcNow;
}
if (maybeLogo.IsNone)
{
var artwork = new Artwork
{
return updateChannel.Number;
}
return BaseError.New("Invalid channel number; one decimal is allowed for subchannels");
Path = logo,
OriginalContentType = !string.IsNullOrEmpty(update.Logo.ContentType)
? update.Logo.ContentType
: null,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow,
ArtworkKind = ArtworkKind.Logo
};
c.Artwork.Add(artwork);
}
}
else
{
await dbContext.Entry(c)
.Collection(channel => channel.Artwork)
.LoadAsync(cancellationToken);
return BaseError.New("Channel number must be unique");
foreach (Artwork artwork in c.Artwork.Where(x => x.ArtworkKind is ArtworkKind.Logo).ToList())
{
c.Artwork.Remove(artwork);
dbContext.Artwork.Remove(artwork);
}
}
private static Validation<BaseError, string> ValidatePreferredLanguage(UpdateChannel updateChannel) =>
Optional(updateChannel.PreferredLanguageCode ?? string.Empty)
.Filter(
lc => string.IsNullOrWhiteSpace(lc) || CultureInfo.GetCultures(CultureTypes.NeutralCultures).Any(
ci => string.Equals(ci.ThreeLetterISOLanguageName, lc, StringComparison.OrdinalIgnoreCase)))
.ToValidation<BaseError>("Preferred language code is invalid");
c.PlayoutSource = update.PlayoutSource;
c.PlayoutMode = update.PlayoutMode;
if (c.PlayoutSource is ChannelPlayoutSource.Mirror)
{
c.PlayoutMode = ChannelPlayoutMode.Continuous;
hasEpgChange |= c.MirrorSourceChannelId != update.MirrorSourceChannelId;
hasEpgChange |= c.PlayoutOffset != update.PlayoutOffset;
}
else
{
c.MirrorSourceChannelId = null;
c.PlayoutOffset = null;
}
c.MirrorSourceChannelId = update.MirrorSourceChannelId;
c.PlayoutOffset = update.PlayoutOffset;
c.StreamingMode = update.StreamingMode;
c.WatermarkId = update.WatermarkId;
c.FallbackFillerId = update.FallbackFillerId;
await dbContext.SaveChangesAsync(cancellationToken);
searchTargets.SearchTargetsChanged();
if (c.SubtitleMode != ChannelSubtitleMode.None)
{
Option<Playout> maybePlayout = await dbContext.Playouts
.SelectOneAsync(p => p.ChannelId, p => p.ChannelId == c.Id, cancellationToken);
foreach (Playout playout in maybePlayout)
{
await workerChannel.WriteAsync(new ExtractEmbeddedSubtitles(playout.Id), cancellationToken);
}
}
await workerChannel.WriteAsync(new RefreshChannelList(), cancellationToken);
if (hasEpgChange)
{
await workerChannel.WriteAsync(new RefreshChannelData(c.Number), cancellationToken);
}
return ProjectToViewModel(c, c.Playouts?.Count ?? 0);
}
private static async Task<Validation<BaseError, Channel>> Validate(
TvContext dbContext,
UpdateChannel request,
CancellationToken cancellationToken) =>
(await ChannelMustExist(dbContext, request, cancellationToken),
ValidateName(request),
await ValidateNumber(dbContext, request, cancellationToken),
await MirrorSourceMustBeValid(dbContext, request, cancellationToken))
.Apply((channelToUpdate, _, _, _) => channelToUpdate);
private static Task<Validation<BaseError, Channel>> ChannelMustExist(
TvContext dbContext,
UpdateChannel updateChannel,
CancellationToken cancellationToken) =>
dbContext.Channels
.Include(c => c.Artwork)
.Include(c => c.Watermark)
.Include(c => c.Playouts)
.SelectOneAsync(c => c.Id, c => c.Id == updateChannel.ChannelId, cancellationToken)
.Map(o => o.ToValidation<BaseError>("Channel does not exist."));
private static async Task<Validation<BaseError, Unit>> MirrorSourceMustBeValid(
TvContext dbContext,
UpdateChannel request,
CancellationToken cancellationToken)
{
if (request.PlayoutSource is not ChannelPlayoutSource.Mirror)
{
return Unit.Default;
}
Option<Channel> maybeMirrorSource = await dbContext.Channels
.AsNoTracking()
.SelectOneAsync(
c => c.Id == request.MirrorSourceChannelId,
c => c.Id == request.MirrorSourceChannelId,
cancellationToken);
if (maybeMirrorSource.IsNone)
{
return BaseError.New("Mirror source channel does not exist.");
}
foreach (var mirrorSource in maybeMirrorSource)
{
if (mirrorSource.PlayoutSource is not ChannelPlayoutSource.Generated)
{
return BaseError.New(
$"Mirror source channel {mirrorSource.Name} must use generated playout source");
}
}
foreach (TimeSpan playoutOffset in Optional(request.PlayoutOffset))
{
if (playoutOffset < TimeSpan.FromHours(-12) || playoutOffset > TimeSpan.FromHours(12))
{
return BaseError.New("Playout offset must not be greater than 12 hours");
}
}
return Unit.Default;
}
private static Validation<BaseError, string> ValidateName(UpdateChannel updateChannel) =>
updateChannel.NotEmpty(c => c.Name)
.Bind(_ => updateChannel.NotLongerThan(50)(c => c.Name));
private static async Task<Validation<BaseError, string>> ValidateNumber(
TvContext dbContext,
UpdateChannel updateChannel,
CancellationToken cancellationToken)
{
int matchId = await dbContext.Channels
.SelectOneAsync(c => c.Number, c => c.Number == updateChannel.Number, cancellationToken)
.Match(c => c.Id, () => updateChannel.ChannelId);
if (matchId == updateChannel.ChannelId)
{
if (Regex.IsMatch(updateChannel.Number, Channel.NumberValidator))
{
return updateChannel.Number;
}
return BaseError.New("Invalid channel number; two decimals are allowed for subchannels");
}
return BaseError.New("Channel number must be unique");
}
}

View File

@@ -0,0 +1,5 @@
using ErsatzTV.Core;
namespace ErsatzTV.Application.Channels;
public record UpdateChannelNumbers(List<ChannelSortViewModel> Channels) : IRequest<Option<BaseError>>;

View File

@@ -0,0 +1,72 @@
using System.Globalization;
using System.Threading.Channels;
using ErsatzTV.Core;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Channel = ErsatzTV.Core.Domain.Channel;
namespace ErsatzTV.Application.Channels;
public class UpdateChannelNumbersHandler(
IDbContextFactory<TvContext> dbContextFactory,
ChannelWriter<IBackgroundServiceRequest> workerChannel)
: IRequestHandler<UpdateChannelNumbers, Option<BaseError>>
{
public async Task<Option<BaseError>> Handle(UpdateChannelNumbers request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
try
{
var numberUpdates = request.Channels.ToDictionary(c => c.Id, c => c.Number);
var channelIds = numberUpdates.Keys;
List<Channel> channelsToUpdate = await dbContext.Channels
.Where(c => channelIds.Contains(c.Id))
.ToListAsync(cancellationToken);
// give every channel a non-conflicting number
foreach (var channel in channelsToUpdate)
{
channel.Number = $"-{channel.Id}";
}
// save those changes
await dbContext.SaveChangesAsync(cancellationToken);
// give every channel the proper new number
foreach (var channel in channelsToUpdate)
{
channel.Number = numberUpdates[channel.Id];
if (double.TryParse(channel.Number, CultureInfo.InvariantCulture, out double sortNumber))
{
channel.SortNumber = sortNumber;
}
else
{
return BaseError.New($"Failed to parse channel number {channel.Number}");
}
}
// save those changes
await dbContext.SaveChangesAsync(cancellationToken);
// commit the transaction
await transaction.CommitAsync(cancellationToken);
// update channel list and xmltv
await workerChannel.WriteAsync(new RefreshChannelList(), cancellationToken);
foreach (var channel in channelsToUpdate)
{
await workerChannel.WriteAsync(new RefreshChannelData(channel.Number), cancellationToken);
}
return Option<BaseError>.None;
}
catch (Exception ex)
{
return BaseError.New("Failed to update channel numbers: " + ex.Message);
}
}
}

View File

@@ -1,28 +1,87 @@
using System.Linq;
using ErsatzTV.Application.Artworks;
using ErsatzTV.Core.Api.Channels;
using ErsatzTV.Core.Domain;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Channels
namespace ErsatzTV.Application.Channels;
internal static class Mapper
{
internal static class Mapper
internal static ChannelViewModel ProjectToViewModel(Channel channel, int playoutCount) =>
new(
channel.Id,
channel.Number,
channel.Name,
channel.Group,
channel.Categories,
channel.FFmpegProfileId,
channel.SlugSeconds,
GetLogo(channel),
channel.StreamSelectorMode,
channel.StreamSelector,
channel.PreferredAudioLanguageCode,
channel.PreferredAudioTitle,
channel.PlayoutSource,
channel.PlayoutMode,
channel.MirrorSourceChannelId,
channel.PlayoutOffset,
channel.StreamingMode,
channel.WatermarkId,
channel.FallbackFillerId,
playoutCount,
channel.PreferredSubtitleLanguageCode,
channel.SubtitleMode,
channel.MusicVideoCreditsMode,
channel.MusicVideoCreditsTemplate,
channel.SongVideoMode,
channel.TranscodeMode,
channel.IdleBehavior,
channel.IsEnabled,
channel.ShowInEpg);
internal static ChannelResponseModel ProjectToResponseModel(Channel channel) =>
new(
channel.Id,
channel.Number,
channel.Name,
channel.FFmpegProfile.Name,
channel.PreferredAudioLanguageCode,
GetStreamingMode(channel));
internal static ResolutionViewModel ProjectToViewModel(Resolution resolution) =>
new(resolution.Height, resolution.Width);
internal static ChannelStreamingSpecsViewModel ProjectToSpecsViewModel(Channel channel) =>
new(
channel.FFmpegProfile.Resolution.Height,
channel.FFmpegProfile.Resolution.Width,
(int)((channel.FFmpegProfile.VideoBitrate * 1000 + channel.FFmpegProfile.AudioBitrate * 1000) * 1.2),
channel.FFmpegProfile.VideoFormat,
channel.FFmpegProfile.VideoProfile,
channel.FFmpegProfile.AudioFormat);
private static ArtworkContentTypeModel GetLogo(Channel channel)
{
internal static ChannelViewModel ProjectToViewModel(Channel channel) =>
new(
channel.Id,
channel.Number,
channel.Name,
channel.FFmpegProfileId,
GetLogo(channel),
channel.PreferredLanguageCode,
channel.StreamingMode,
channel.WatermarkId);
Option<Artwork> maybeArtwork = channel.Artwork
.Where(a => a.ArtworkKind == ArtworkKind.Logo)
.HeadOrNone();
private static string GetLogo(Channel channel) =>
Optional(channel.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Logo))
.Match(a => a.Path, string.Empty);
foreach (Artwork artwork in maybeArtwork)
{
return artwork.IsExternalUrl()
? new ArtworkContentTypeModel(artwork.Path, string.Empty)
: new ArtworkContentTypeModel($"iptv/logos/{artwork.Path}", artwork.OriginalContentType);
}
private static string GetWatermark(Channel channel) =>
Optional(channel.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Watermark))
.Match(a => a.Path, string.Empty);
return ArtworkContentTypeModel.None;
}
private static string GetStreamingMode(Channel channel) =>
channel.StreamingMode switch
{
StreamingMode.TransportStream => "MPEG-TS (Legacy)",
StreamingMode.TransportStreamHybrid => "MPEG-TS",
StreamingMode.HttpLiveStreamingDirect => "HLS Direct",
StreamingMode.HttpLiveStreamingSegmenter => "HLS Segmenter",
_ => throw new ArgumentOutOfRangeException(nameof(channel))
};
}

View File

@@ -1,7 +1,3 @@
using System.Collections.Generic;
using MediatR;
namespace ErsatzTV.Application.Channels;
namespace ErsatzTV.Application.Channels.Queries
{
public record GetAllChannels : IRequest<List<ChannelViewModel>>;
}
public record GetAllChannels(bool ShowDisabled = true) : IRequest<List<ChannelViewModel>>;

View File

@@ -0,0 +1,5 @@
using ErsatzTV.Core.Api.Channels;
namespace ErsatzTV.Application.Channels;
public record GetAllChannelsForApi : IRequest<List<ChannelResponseModel>>;

View File

@@ -0,0 +1,18 @@
using ErsatzTV.Core.Api.Channels;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using static ErsatzTV.Application.Channels.Mapper;
namespace ErsatzTV.Application.Channels;
public class GetAllChannelsForApiHandler(IChannelRepository channelRepository)
: IRequestHandler<GetAllChannelsForApi, List<ChannelResponseModel>>
{
public async Task<List<ChannelResponseModel>> Handle(
GetAllChannelsForApi request,
CancellationToken cancellationToken)
{
IEnumerable<Channel> channels = Optional(await channelRepository.GetAll(cancellationToken)).Flatten();
return channels.Map(ProjectToResponseModel).ToList();
}
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record GetAllChannelsForSort : IRequest<List<ChannelSortViewModel>>;

View File

@@ -0,0 +1,31 @@
using System.Globalization;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Channels;
public class GetAllChannelsForSortHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetAllChannelsForSort, List<ChannelSortViewModel>>
{
public async Task<List<ChannelSortViewModel>> Handle(
GetAllChannelsForSort request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Channels
.AsNoTracking()
.ToListAsync(cancellationToken)
.Map(list => list.Map(ProjectToSortViewModel)
.OrderBy(c => decimal.Parse(c.Number, CultureInfo.InvariantCulture)).ToList());
}
private static ChannelSortViewModel ProjectToSortViewModel(Channel channel)
=> new()
{
Id = channel.Id,
Number = channel.Number,
Name = channel.Name,
OriginalNumber = channel.Number
};
}

View File

@@ -1,21 +1,31 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using MediatR;
using static ErsatzTV.Application.Channels.Mapper;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Channels.Queries
namespace ErsatzTV.Application.Channels;
public class GetAllChannelsHandler(IChannelRepository channelRepository)
: IRequestHandler<GetAllChannels, List<ChannelViewModel>>
{
public class GetAllChannelsHandler : IRequestHandler<GetAllChannels, List<ChannelViewModel>>
public async Task<List<ChannelViewModel>> Handle(GetAllChannels request, CancellationToken cancellationToken) =>
await channelRepository.GetAll(cancellationToken)
.Map(list => list.Where(c => c.IsEnabled || request.ShowDisabled)
.Map(c => ProjectToViewModel(c, GetPlayoutsCount(c))).ToList());
private static int GetPlayoutsCount(Channel channel)
{
private readonly IChannelRepository _channelRepository;
var result = 0;
public GetAllChannelsHandler(IChannelRepository channelRepository) => _channelRepository = channelRepository;
if (channel.Playouts != null)
{
result += channel.Playouts.Count;
}
public async Task<List<ChannelViewModel>> Handle(GetAllChannels request, CancellationToken cancellationToken) =>
Optional(await _channelRepository.GetAll()).Flatten().Map(ProjectToViewModel).ToList();
if (channel.PlayoutSource is ChannelPlayoutSource.Mirror && channel.MirrorSourceChannel?.Playouts != null)
{
result += channel.MirrorSourceChannel.Playouts.Count;
}
return result;
}
}

View File

@@ -1,7 +1,3 @@
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Channels;
namespace ErsatzTV.Application.Channels.Queries
{
public record GetChannelById(int Id) : IRequest<Option<ChannelViewModel>>;
}
public record GetChannelById(int Id) : IRequest<Option<ChannelViewModel>>;

View File

@@ -1,20 +1,12 @@
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using ErsatzTV.Core.Interfaces.Repositories;
using static ErsatzTV.Application.Channels.Mapper;
namespace ErsatzTV.Application.Channels.Queries
namespace ErsatzTV.Application.Channels;
public class GetChannelByIdHandler(IChannelRepository channelRepository)
: IRequestHandler<GetChannelById, Option<ChannelViewModel>>
{
public class GetChannelByIdHandler : IRequestHandler<GetChannelById, Option<ChannelViewModel>>
{
private readonly IChannelRepository _channelRepository;
public GetChannelByIdHandler(IChannelRepository channelRepository) => _channelRepository = channelRepository;
public Task<Option<ChannelViewModel>> Handle(GetChannelById request, CancellationToken cancellationToken) =>
_channelRepository.Get(request.Id)
.MapT(ProjectToViewModel);
}
public Task<Option<ChannelViewModel>> Handle(GetChannelById request, CancellationToken cancellationToken) =>
channelRepository.GetChannel(request.Id)
.MapT(c => ProjectToViewModel(c, 0));
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record GetChannelByNumber(string ChannelNumber) : IRequest<Option<ChannelViewModel>>;

View File

@@ -0,0 +1,11 @@
using ErsatzTV.Core.Interfaces.Repositories;
using static ErsatzTV.Application.Channels.Mapper;
namespace ErsatzTV.Application.Channels;
public class GetChannelByNumberHandler(IChannelRepository channelRepository)
: IRequestHandler<GetChannelByNumber, Option<ChannelViewModel>>
{
public Task<Option<ChannelViewModel>> Handle(GetChannelByNumber request, CancellationToken cancellationToken) =>
channelRepository.GetByNumber(request.ChannelNumber).MapT(c => ProjectToViewModel(c, 0));
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record GetChannelByPlayoutId(int PlayoutId) : IRequest<Option<ChannelViewModel>>;

View File

@@ -0,0 +1,21 @@
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using static ErsatzTV.Application.Channels.Mapper;
namespace ErsatzTV.Application.Channels;
public class GetChannelByPlayoutIdHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetChannelByPlayoutId, Option<ChannelViewModel>>
{
public async Task<Option<ChannelViewModel>> Handle(
GetChannelByPlayoutId request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Playouts
.Include(p => p.Channel)
.ThenInclude(c => c.Artwork)
.SingleOrDefaultAsync(p => p.Id == request.PlayoutId, cancellationToken)
.Map(p => ProjectToViewModel(p.Channel, 1));
}
}

View File

@@ -0,0 +1,5 @@
using ErsatzTV.FFmpeg;
namespace ErsatzTV.Application.Channels;
public record GetChannelFramerate(string ChannelNumber) : IRequest<Option<FrameRate>>;

View File

@@ -0,0 +1,118 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.FFmpeg;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.Application.Channels;
public class GetChannelFramerateHandler(
IDbContextFactory<TvContext> dbContextFactory,
ILogger<GetChannelFramerateHandler> logger)
: IRequestHandler<GetChannelFramerate, Option<FrameRate>>
{
public async Task<Option<FrameRate>> Handle(GetChannelFramerate request, CancellationToken cancellationToken)
{
try
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
FFmpegProfile ffmpegProfile = await dbContext.Channels
.AsNoTracking()
.Filter(c => c.Number == request.ChannelNumber)
.Include(c => c.FFmpegProfile)
.Map(c => c.FFmpegProfile)
.SingleAsync(cancellationToken);
if (!ffmpegProfile.NormalizeFramerate)
{
return Option<FrameRate>.None;
}
// TODO: expand to check everything in collection rather than what's scheduled?
logger.LogDebug("Checking frame rates for channel {ChannelNumber}", request.ChannelNumber);
List<Playout> playouts = await dbContext.Playouts
.AsNoTracking()
.Include(p => p.Items)
.ThenInclude(pi => pi.MediaItem)
.ThenInclude(mi => (mi as Movie).MediaVersions)
.Include(p => p.Items)
.ThenInclude(pi => pi.MediaItem)
.ThenInclude(mi => (mi as Episode).MediaVersions)
.Include(p => p.Items)
.ThenInclude(pi => pi.MediaItem)
.ThenInclude(mi => (mi as Song).MediaVersions)
.Include(p => p.Items)
.ThenInclude(pi => pi.MediaItem)
.ThenInclude(mi => (mi as MusicVideo).MediaVersions)
.Include(p => p.Items)
.ThenInclude(pi => pi.MediaItem)
.ThenInclude(mi => (mi as OtherVideo).MediaVersions)
.Include(p => p.Items)
.ThenInclude(pi => pi.MediaItem)
.ThenInclude(mi => (mi as Image).MediaVersions)
.Include(p => p.Items)
.ThenInclude(pi => pi.MediaItem)
.ThenInclude(mi => (mi as RemoteStream).MediaVersions)
.Filter(p => p.Channel.Number == request.ChannelNumber)
.ToListAsync(cancellationToken);
var frameRates = playouts.Map(p => p.Items.Map(i => i.MediaItem.GetHeadVersion()))
.Flatten()
.Map(mv => new FrameRate(mv.RFrameRate))
.ToList();
var distinct = frameRates.Distinct().ToList();
if (distinct.Count > 1)
{
// TODO: something more intelligent than minimum framerate?
var validFrameRates = frameRates.Where(fr => fr.ParsedFrameRate > 23).ToList();
if (validFrameRates.Count > 0)
{
FrameRate result = validFrameRates.MinBy(fr => fr.ParsedFrameRate);
logger.LogInformation(
"Normalizing frame rate for channel {ChannelNumber} from {Distinct} to {FrameRate}",
request.ChannelNumber,
distinct.Map(fr => fr.RFrameRate),
result.RFrameRate);
return result;
}
FrameRate minFrameRate = frameRates.MinBy(fr => fr.ParsedFrameRate);
logger.LogInformation(
"Normalizing frame rate for channel {ChannelNumber} from {Distinct} to {FrameRate} instead of min value {MinFrameRate}",
request.ChannelNumber,
distinct.Map(fr => fr.RFrameRate),
FrameRate.DefaultFrameRate.RFrameRate,
minFrameRate.RFrameRate);
return FrameRate.DefaultFrameRate;
}
if (distinct.Count != 0)
{
logger.LogInformation(
"All content on channel {ChannelNumber} has the same frame rate of {FrameRate}; will not normalize",
request.ChannelNumber,
distinct[0].RFrameRate);
}
else
{
logger.LogInformation(
"No content on channel {ChannelNumber} has frame rate information; will not normalize",
request.ChannelNumber);
}
}
catch (Exception ex)
{
logger.LogWarning(
ex,
"Unexpected error checking frame rates on channel {ChannelNumber}",
request.ChannelNumber);
}
return None;
}
}

View File

@@ -1,7 +1,7 @@
using ErsatzTV.Core.Iptv;
using MediatR;
using ErsatzTV.Core;
using ErsatzTV.Core.Iptv;
namespace ErsatzTV.Application.Channels.Queries
{
public record GetChannelGuide(string Scheme, string Host) : IRequest<ChannelGuide>;
}
namespace ErsatzTV.Application.Channels;
public record GetChannelGuide(string Scheme, string Host, string BaseUrl, string AccessToken)
: IRequest<Either<BaseError, ChannelGuide>>;

View File

@@ -1,20 +1,106 @@
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Interfaces.Repositories;
using System.Collections.Immutable;
using System.IO.Abstractions;
using System.Text;
using System.Text.RegularExpressions;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Iptv;
using LanguageExt;
using MediatR;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.IO;
namespace ErsatzTV.Application.Channels.Queries
namespace ErsatzTV.Application.Channels;
public partial class GetChannelGuideHandler(
IDbContextFactory<TvContext> dbContextFactory,
RecyclableMemoryStreamManager recyclableMemoryStreamManager,
IFileSystem fileSystem,
ILocalFileSystem localFileSystem)
: IRequestHandler<GetChannelGuide, Either<BaseError, ChannelGuide>>
{
public class GetChannelGuideHandler : IRequestHandler<GetChannelGuide, ChannelGuide>
public async Task<Either<BaseError, ChannelGuide>> Handle(
GetChannelGuide request,
CancellationToken cancellationToken)
{
private readonly IChannelRepository _channelRepository;
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
var hiddenChannelNumbers = dbContext.Channels
.Where(c => c.ShowInEpg == false)
.Select(c => c.Number)
.AsEnumerable()
.Select(n => $"{n}.xml")
.ToImmutableHashSet();
public GetChannelGuideHandler(IChannelRepository channelRepository) => _channelRepository = channelRepository;
string channelsFile = fileSystem.Path.Combine(FileSystemLayout.ChannelGuideCacheFolder, "channels.xml");
if (!fileSystem.File.Exists(channelsFile))
{
return BaseError.New($"Required file {channelsFile} is missing");
}
public Task<ChannelGuide> Handle(GetChannelGuide request, CancellationToken cancellationToken) =>
_channelRepository.GetAllForGuide()
.Map(channels => new ChannelGuide(request.Scheme, request.Host, channels));
long mtime = fileSystem.File.GetLastWriteTime(channelsFile).Ticks;
var accessTokenUri = $"?v={mtime}";
if (!string.IsNullOrWhiteSpace(request.AccessToken))
{
accessTokenUri += $"&amp;access_token={request.AccessToken}";
}
string channelsFragment = await ReadAllTextShared(channelsFile, cancellationToken);
// TODO: is regex faster?
channelsFragment = channelsFragment
.Replace("{RequestBase}", $"{request.Scheme}://{request.Host}{request.BaseUrl}")
.Replace("{AccessTokenUri}", accessTokenUri);
var channelDataFragments = new Dictionary<string, string>();
foreach (string fileName in localFileSystem.ListFiles(FileSystemLayout.ChannelGuideCacheFolder))
{
if (fileName.Contains("channels"))
{
continue;
}
if (hiddenChannelNumbers.Contains(fileSystem.Path.GetFileName(fileName)))
{
continue;
}
try
{
string channelDataFragment = await ReadAllTextShared(fileName, cancellationToken);
channelDataFragment = channelDataFragment
.Replace("{RequestBase}", $"{request.Scheme}://{request.Host}{request.BaseUrl}")
.Replace("{AccessTokenUri}", accessTokenUri);
channelDataFragment = EtvTagRegex().Replace(channelDataFragment, string.Empty);
channelDataFragments.Add(fileSystem.Path.GetFileNameWithoutExtension(fileName), channelDataFragment);
}
catch (FileNotFoundException)
{
// ignore this channel fragment
}
catch (IOException)
{
// ignore this channel fragment
}
}
return new ChannelGuide(recyclableMemoryStreamManager, channelsFragment, channelDataFragments);
}
private async Task<string> ReadAllTextShared(string fileName, CancellationToken cancellationToken)
{
await using var stream = fileSystem.FileStream.New(
fileName,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite);
using var reader = new StreamReader(stream, Encoding.UTF8, leaveOpen: true);
return await reader.ReadToEndAsync(cancellationToken);
}
[GeneratedRegex(@"<etv:[^>]+?>.*?<\/etv:[^>]+?>|<etv:[^>]+?\/>", RegexOptions.Singleline)]
private static partial Regex EtvTagRegex();
}

View File

@@ -1,8 +1,5 @@
using System.Collections.Generic;
using ErsatzTV.Core.Hdhr;
using MediatR;
using ErsatzTV.Core.Hdhr;
namespace ErsatzTV.Application.Channels.Queries
{
public record GetChannelLineup(string Scheme, string Host) : IRequest<List<LineupItem>>;
}
namespace ErsatzTV.Application.Channels;
public record GetChannelLineup(string Scheme, string Host) : IRequest<List<LineupItem>>;

View File

@@ -1,22 +1,16 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Hdhr;
using ErsatzTV.Core.Hdhr;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Channels.Queries
namespace ErsatzTV.Application.Channels;
public class GetChannelLineupHandler : IRequestHandler<GetChannelLineup, List<LineupItem>>
{
public class GetChannelLineupHandler : IRequestHandler<GetChannelLineup, List<LineupItem>>
{
private readonly IChannelRepository _channelRepository;
private readonly IChannelRepository _channelRepository;
public GetChannelLineupHandler(IChannelRepository channelRepository) => _channelRepository = channelRepository;
public GetChannelLineupHandler(IChannelRepository channelRepository) => _channelRepository = channelRepository;
public Task<List<LineupItem>> Handle(GetChannelLineup request, CancellationToken cancellationToken) =>
_channelRepository.GetAll()
.Map(channels => channels.Map(c => new LineupItem(request.Scheme, request.Host, c)).ToList());
}
public Task<List<LineupItem>> Handle(GetChannelLineup request, CancellationToken cancellationToken) =>
_channelRepository.GetAll(cancellationToken)
.Map(channels => channels.Where(c => c.IsEnabled)
.Map(c => new LineupItem(request.Scheme, request.Host, c)).ToList());
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record GetChannelNameByPlayoutId(int PlayoutId) : IRequest<Option<string>>;

View File

@@ -0,0 +1,18 @@
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Channels;
public class GetChannelNameByPlayoutIdHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetChannelNameByPlayoutId, Option<string>>
{
public async Task<Option<string>> Handle(GetChannelNameByPlayoutId request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Playouts
.Include(p => p.Channel)
.SelectOneAsync(p => p.Id, p => p.Id == request.PlayoutId, cancellationToken)
.MapT(p => p.Channel.Name);
}
}

View File

@@ -1,7 +1,11 @@
using ErsatzTV.Core.Iptv;
using MediatR;
using ErsatzTV.Core.Iptv;
namespace ErsatzTV.Application.Channels.Queries
{
public record GetChannelPlaylist(string Scheme, string Host, string Mode) : IRequest<ChannelPlaylist>;
}
namespace ErsatzTV.Application.Channels;
public record GetChannelPlaylist(
string Scheme,
string Host,
string BaseUrl,
string Mode,
string UserAgent,
string AccessToken) : IRequest<ChannelPlaylist>;

View File

@@ -1,48 +1,57 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Iptv;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Channels.Queries
namespace ErsatzTV.Application.Channels;
public class GetChannelPlaylistHandler(IChannelRepository channelRepository)
: IRequestHandler<GetChannelPlaylist, ChannelPlaylist>
{
public class GetChannelPlaylistHandler : IRequestHandler<GetChannelPlaylist, ChannelPlaylist>
public Task<ChannelPlaylist> Handle(GetChannelPlaylist request, CancellationToken cancellationToken) =>
channelRepository.GetAll(cancellationToken)
.Map(channels => EnsureMode(channels, request.Mode))
.Map(channels => new ChannelPlaylist(
request.Scheme,
request.Host,
request.BaseUrl,
channels,
request.UserAgent,
request.AccessToken));
private static List<Channel> EnsureMode(IEnumerable<Channel> channels, string mode)
{
private readonly IChannelRepository _channelRepository;
public GetChannelPlaylistHandler(IChannelRepository channelRepository) =>
_channelRepository = channelRepository;
public Task<ChannelPlaylist> Handle(GetChannelPlaylist request, CancellationToken cancellationToken) =>
_channelRepository.GetAll()
.Map(channels => EnsureMode(channels, request.Mode))
.Map(channels => new ChannelPlaylist(request.Scheme, request.Host, channels));
private static List<Channel> EnsureMode(IEnumerable<Channel> channels, string mode)
var result = new List<Channel>();
foreach (Channel channel in channels)
{
var result = new List<Channel>();
foreach (Channel channel in channels)
if (!channel.IsEnabled)
{
switch (mode.ToLowerInvariant())
{
case "hls-direct":
channel.StreamingMode = StreamingMode.HttpLiveStreamingDirect;
result.Add(channel);
break;
case "ts":
channel.StreamingMode = StreamingMode.TransportStream;
result.Add(channel);
break;
default:
result.Add(channel);
break;
}
continue;
}
return result;
switch (mode.ToLowerInvariant())
{
case "segmenter":
channel.StreamingMode = StreamingMode.HttpLiveStreamingSegmenter;
result.Add(channel);
break;
case "hls-direct":
channel.StreamingMode = StreamingMode.HttpLiveStreamingDirect;
result.Add(channel);
break;
case "ts-legacy":
channel.StreamingMode = StreamingMode.TransportStream;
result.Add(channel);
break;
case "ts":
channel.StreamingMode = StreamingMode.TransportStreamHybrid;
result.Add(channel);
break;
default:
result.Add(channel);
break;
}
}
return result;
}
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record GetChannelStreamSelectors : IRequest<List<string>>;

View File

@@ -0,0 +1,14 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Metadata;
namespace ErsatzTV.Application.Channels;
public class GetChannelStreamSelectorsHandler(ILocalFileSystem localFileSystem)
: IRequestHandler<GetChannelStreamSelectors, List<string>>
{
public Task<List<string>> Handle(GetChannelStreamSelectors request, CancellationToken cancellationToken) =>
localFileSystem.ListFiles(FileSystemLayout.ChannelStreamSelectorsFolder)
.Map(Path.GetFileName)
.ToList()
.AsTask();
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record GetChannelStreamingSpecs(string ChannelNumber) : IRequest<Option<ChannelStreamingSpecsViewModel>>;

View File

@@ -0,0 +1,25 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Channels;
public class GetChannelStreamingSpecsHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetChannelStreamingSpecs, Option<ChannelStreamingSpecsViewModel>>
{
public async Task<Option<ChannelStreamingSpecsViewModel>> Handle(
GetChannelStreamingSpecs request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Option<Channel> maybeChannel = await dbContext.Channels
.AsNoTracking()
.Include(c => c.FFmpegProfile)
.ThenInclude(ff => ff.Resolution)
.SelectOneAsync(c => c.Number, c => c.Number == request.ChannelNumber, cancellationToken);
return maybeChannel.Map(Mapper.ProjectToSpecsViewModel);
}
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record GetSlugSecondsByChannelNumber(string ChannelNumber) : IRequest<Option<double>>;

View File

@@ -0,0 +1,17 @@
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Channels;
public class GetSlugSecondsByChannelNumberHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetSlugSecondsByChannelNumber, Option<double>>
{
public async Task<Option<double>> Handle(GetSlugSecondsByChannelNumber request, CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.Channels
.AsNoTracking()
.SingleOrDefaultAsync(c => c.Number == request.ChannelNumber, cancellationToken)
.Map(c => Optional(c?.SlugSeconds));
}
}

View File

@@ -0,0 +1,3 @@
namespace ErsatzTV.Application.Channels;
public record ResolutionViewModel(int Height, int Width);

View File

@@ -0,0 +1,14 @@
using System.Net;
using Scriban;
using Scriban.Parsing;
namespace ErsatzTV.Application.Channels;
public class XmlTemplateContext : TemplateContext
{
public override TemplateContext Write(SourceSpan span, object textAsObject)
=> base.Write(span, textAsObject is string text ? WebUtility.HtmlEncode(text) : textAsObject);
public override ValueTask<TemplateContext> WriteAsync(SourceSpan span, object textAsObject)
=> base.WriteAsync(span, textAsObject is string text ? WebUtility.HtmlEncode(text) : textAsObject);
}

View File

@@ -1,7 +1,5 @@
using ErsatzTV.Core.Domain;
using LanguageExt;
namespace ErsatzTV.Application.Configuration.Commands
{
public record SaveConfigElementByKey(ConfigElementKey Key, string Value) : MediatR.IRequest<Unit>;
}
namespace ErsatzTV.Application.Configuration;
public record SaveConfigElementByKey(ConfigElementKey Key, string Value) : IRequest;

View File

@@ -1,21 +1,14 @@
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using ErsatzTV.Core.Interfaces.Repositories;
namespace ErsatzTV.Application.Configuration.Commands
namespace ErsatzTV.Application.Configuration;
public class SaveConfigElementByKeyHandler : IRequestHandler<SaveConfigElementByKey>
{
public class SaveConfigElementByKeyHandler : MediatR.IRequestHandler<SaveConfigElementByKey, Unit>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IConfigElementRepository _configElementRepository;
public SaveConfigElementByKeyHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public SaveConfigElementByKeyHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public async Task<Unit> Handle(SaveConfigElementByKey request, CancellationToken cancellationToken)
{
await _configElementRepository.Upsert(request.Key, request.Value);
return Unit.Default;
}
}
public async Task Handle(SaveConfigElementByKey request, CancellationToken cancellationToken) =>
await _configElementRepository.Upsert(request.Key, request.Value, cancellationToken);
}

View File

@@ -1,7 +1,5 @@
using ErsatzTV.Core;
using LanguageExt;
namespace ErsatzTV.Application.Configuration.Commands
{
public record UpdateLibraryRefreshInterval(int LibraryRefreshInterval) : MediatR.IRequest<Either<BaseError, Unit>>;
}
namespace ErsatzTV.Application.Configuration;
public record UpdateLibraryRefreshInterval(int LibraryRefreshInterval) : IRequest<Either<BaseError, Unit>>;

View File

@@ -1,33 +1,31 @@
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Configuration.Commands
namespace ErsatzTV.Application.Configuration;
public class UpdateLibraryRefreshIntervalHandler :
IRequestHandler<UpdateLibraryRefreshInterval, Either<BaseError, Unit>>
{
public class UpdateLibraryRefreshIntervalHandler :
MediatR.IRequestHandler<UpdateLibraryRefreshInterval, Either<BaseError, Unit>>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IConfigElementRepository _configElementRepository;
public UpdateLibraryRefreshIntervalHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public UpdateLibraryRefreshIntervalHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public Task<Either<BaseError, Unit>> Handle(
UpdateLibraryRefreshInterval request,
CancellationToken cancellationToken) =>
Validate(request)
.MapT(_ => _configElementRepository.Upsert(ConfigElementKey.LibraryRefreshInterval, request.LibraryRefreshInterval))
.Bind(v => v.ToEitherAsync());
public Task<Either<BaseError, Unit>> Handle(
UpdateLibraryRefreshInterval request,
CancellationToken cancellationToken) =>
Validate(request)
.MapT(_ => _configElementRepository.Upsert(
ConfigElementKey.LibraryRefreshInterval,
request.LibraryRefreshInterval,
cancellationToken))
.Bind(v => v.ToEitherAsync());
private static Task<Validation<BaseError, Unit>> Validate(UpdateLibraryRefreshInterval request) =>
Optional(request.LibraryRefreshInterval)
.Filter(lri => lri > 0)
.Map(_ => Unit.Default)
.ToValidation<BaseError>("Tuner count must be greater than zero")
.AsTask();
}
private static Task<Validation<BaseError, Unit>> Validate(UpdateLibraryRefreshInterval request) =>
Optional(request.LibraryRefreshInterval)
.Where(lri => lri is >= 0 and < 1_000_000)
.Map(_ => Unit.Default)
.ToValidation<BaseError>("Library refresh interval must be zero or greater")
.AsTask();
}

View File

@@ -0,0 +1,5 @@
using ErsatzTV.Core;
namespace ErsatzTV.Application.Configuration;
public record UpdateLoggingSettings(LoggingSettingsViewModel LoggingSettings) : IRequest<Either<BaseError, Unit>>;

View File

@@ -0,0 +1,56 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
namespace ErsatzTV.Application.Configuration;
public class UpdateLoggingSettingsHandler : IRequestHandler<UpdateLoggingSettings, Either<BaseError, Unit>>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly LoggingLevelSwitches _loggingLevelSwitches;
public UpdateLoggingSettingsHandler(
LoggingLevelSwitches loggingLevelSwitches,
IConfigElementRepository configElementRepository)
{
_loggingLevelSwitches = loggingLevelSwitches;
_configElementRepository = configElementRepository;
}
public async Task<Either<BaseError, Unit>> Handle(
UpdateLoggingSettings request,
CancellationToken cancellationToken) => await ApplyUpdate(request.LoggingSettings, cancellationToken);
private async Task<Unit> ApplyUpdate(LoggingSettingsViewModel loggingSettings, CancellationToken cancellationToken)
{
await _configElementRepository.Upsert(ConfigElementKey.MinimumLogLevel, loggingSettings.DefaultMinimumLogLevel, cancellationToken);
_loggingLevelSwitches.DefaultLevelSwitch.MinimumLevel = loggingSettings.DefaultMinimumLogLevel;
await _configElementRepository.Upsert(
ConfigElementKey.MinimumLogLevelScanning,
loggingSettings.ScanningMinimumLogLevel, cancellationToken);
_loggingLevelSwitches.ScanningLevelSwitch.MinimumLevel = loggingSettings.ScanningMinimumLogLevel;
await _configElementRepository.Upsert(
ConfigElementKey.MinimumLogLevelScheduling,
loggingSettings.SchedulingMinimumLogLevel, cancellationToken);
_loggingLevelSwitches.SchedulingLevelSwitch.MinimumLevel = loggingSettings.SchedulingMinimumLogLevel;
await _configElementRepository.Upsert(
ConfigElementKey.MinimumLogLevelSearching,
loggingSettings.SearchingMinimumLogLevel, cancellationToken);
_loggingLevelSwitches.SearchingLevelSwitch.MinimumLevel = loggingSettings.SearchingMinimumLogLevel;
await _configElementRepository.Upsert(
ConfigElementKey.MinimumLogLevelStreaming,
loggingSettings.StreamingMinimumLogLevel, cancellationToken);
_loggingLevelSwitches.StreamingLevelSwitch.MinimumLevel = loggingSettings.StreamingMinimumLogLevel;
await _configElementRepository.Upsert(
ConfigElementKey.MinimumLogLevelHttp,
loggingSettings.HttpMinimumLogLevel, cancellationToken);
_loggingLevelSwitches.HttpLevelSwitch.MinimumLevel = loggingSettings.HttpMinimumLogLevel;
return Unit.Default;
}
}

View File

@@ -1,7 +0,0 @@
using ErsatzTV.Core;
using LanguageExt;
namespace ErsatzTV.Application.Configuration.Commands
{
public record UpdatePlayoutDaysToBuild(int DaysToBuild) : MediatR.IRequest<Either<BaseError, Unit>>;
}

View File

@@ -1,66 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Application.Playouts.Commands;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Infrastructure.Data;
using LanguageExt;
using Microsoft.EntityFrameworkCore;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Configuration.Commands
{
public class
UpdatePlayoutDaysToBuildHandler : MediatR.IRequestHandler<UpdatePlayoutDaysToBuild, Either<BaseError, Unit>>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public UpdatePlayoutDaysToBuildHandler(
IConfigElementRepository configElementRepository,
IDbContextFactory<TvContext> dbContextFactory,
ChannelWriter<IBackgroundServiceRequest> workerChannel)
{
_configElementRepository = configElementRepository;
_dbContextFactory = dbContextFactory;
_workerChannel = workerChannel;
}
public async Task<Either<BaseError, Unit>> Handle(
UpdatePlayoutDaysToBuild request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Validation<BaseError, Unit> validation = await Validate(request);
return await validation.Apply<Unit, Unit>(_ => ApplyUpdate(dbContext, request.DaysToBuild));
}
private async Task<Unit> ApplyUpdate(TvContext dbContext, int daysToBuild)
{
await _configElementRepository.Upsert(ConfigElementKey.PlayoutDaysToBuild, daysToBuild);
// build all playouts to proper number of days
List<Playout> playouts = await dbContext.Playouts
.Include(p => p.Channel)
.ToListAsync();
foreach (int playoutId in playouts.OrderBy(p => decimal.Parse(p.Channel.Number)).Map(p => p.Id))
{
await _workerChannel.WriteAsync(new BuildPlayout(playoutId));
}
return Unit.Default;
}
private static Task<Validation<BaseError, Unit>> Validate(UpdatePlayoutDaysToBuild request) =>
Optional(request.DaysToBuild)
.Filter(days => days > 0)
.Map(_ => Unit.Default)
.ToValidation<BaseError>("Days to build must be greater than zero")
.AsTask();
}
}

View File

@@ -0,0 +1,5 @@
using ErsatzTV.Core;
namespace ErsatzTV.Application.Configuration;
public record UpdatePlayoutSettings(PlayoutSettingsViewModel PlayoutSettings) : IRequest<Either<BaseError, Unit>>;

View File

@@ -0,0 +1,80 @@
using System.Globalization;
using System.Threading.Channels;
using ErsatzTV.Application.Playouts;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Scheduling;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Configuration;
public class UpdatePlayoutSettingsHandler : IRequestHandler<UpdatePlayoutSettings, Either<BaseError, Unit>>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public UpdatePlayoutSettingsHandler(
IConfigElementRepository configElementRepository,
IDbContextFactory<TvContext> dbContextFactory,
ChannelWriter<IBackgroundServiceRequest> workerChannel)
{
_configElementRepository = configElementRepository;
_dbContextFactory = dbContextFactory;
_workerChannel = workerChannel;
}
public async Task<Either<BaseError, Unit>> Handle(
UpdatePlayoutSettings request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, Unit> validation = await Validate(request);
return await validation.Apply<Unit, Unit>(_ => ApplyUpdate(
dbContext,
request.PlayoutSettings,
cancellationToken));
}
private async Task<Unit> ApplyUpdate(
TvContext dbContext,
PlayoutSettingsViewModel playoutSettings,
CancellationToken cancellationToken)
{
await _configElementRepository.Upsert(
ConfigElementKey.PlayoutDaysToBuild,
playoutSettings.DaysToBuild,
cancellationToken);
await _configElementRepository.Upsert(
ConfigElementKey.PlayoutSkipMissingItems,
playoutSettings.SkipMissingItems,
cancellationToken);
await _configElementRepository.Upsert(
ConfigElementKey.PlayoutScriptedScheduleTimeoutSeconds,
playoutSettings.ScriptedScheduleTimeoutSeconds,
cancellationToken);
// continue all playouts to proper number of days
List<Playout> playouts = await dbContext.Playouts
.Include(p => p.Channel)
.ToListAsync(cancellationToken);
foreach (int playoutId in playouts.OrderBy(p => decimal.Parse(p.Channel.Number, CultureInfo.InvariantCulture))
.Map(p => p.Id))
{
await _workerChannel.WriteAsync(new BuildPlayout(playoutId, PlayoutBuildMode.Continue), cancellationToken);
}
return Unit.Default;
}
private static Task<Validation<BaseError, Unit>> Validate(UpdatePlayoutSettings request) =>
Optional(request.PlayoutSettings.DaysToBuild)
.Where(days => days > 0)
.Map(_ => Unit.Default)
.ToValidation<BaseError>("Days to build must be greater than zero")
.AsTask();
}

View File

@@ -0,0 +1,5 @@
using ErsatzTV.Core;
namespace ErsatzTV.Application.Configuration;
public record UpdateUiSettings(UiSettingsViewModel UiSettings) : IRequest<Either<BaseError, Unit>>;

View File

@@ -0,0 +1,28 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
namespace ErsatzTV.Application.Configuration;
public class UpdateUiSettingsHandler(IConfigElementRepository configElementRepository)
: IRequestHandler<UpdateUiSettings, Either<BaseError, Unit>>
{
public async Task<Either<BaseError, Unit>> Handle(
UpdateUiSettings request,
CancellationToken cancellationToken)
{
return await ApplyUpdate(request.UiSettings, cancellationToken);
}
private async Task<Unit> ApplyUpdate(UiSettingsViewModel uiSettings, CancellationToken cancellationToken)
{
await configElementRepository.Upsert(
ConfigElementKey.PagesIsDarkMode,
uiSettings.IsDarkMode,
cancellationToken);
await configElementRepository.Upsert(ConfigElementKey.PagesLanguage, uiSettings.Language, cancellationToken);
return Unit.Default;
}
}

View File

@@ -0,0 +1,5 @@
using ErsatzTV.Core;
namespace ErsatzTV.Application.Configuration;
public record UpdateXmltvSettings(XmltvSettingsViewModel XmltvSettings) : IRequest<Either<BaseError, Unit>>;

View File

@@ -0,0 +1,50 @@
using System.Threading.Channels;
using ErsatzTV.Application.Channels;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Configuration;
public class UpdateXmltvSettingsHandler(
IDbContextFactory<TvContext> dbContextFactory,
IConfigElementRepository configElementRepository,
ChannelWriter<IBackgroundServiceRequest> workerChannel)
: IRequestHandler<UpdateXmltvSettings, Either<BaseError, Unit>>
{
public async Task<Either<BaseError, Unit>> Handle(
UpdateXmltvSettings request,
CancellationToken cancellationToken)
{
int playoutDaysToBuild =
await configElementRepository
.GetValue<int>(ConfigElementKey.PlayoutDaysToBuild, cancellationToken)
.IfNoneAsync(2);
if (playoutDaysToBuild < request.XmltvSettings.DaysToBuild)
{
return BaseError.New(
$"XMLTV days to build ({request.XmltvSettings.DaysToBuild}) cannot be greater than Playout days to build ({playoutDaysToBuild})");
}
return await ApplyUpdate(request.XmltvSettings, cancellationToken);
}
private async Task<Unit> ApplyUpdate(XmltvSettingsViewModel xmltvSettings, CancellationToken cancellationToken)
{
await configElementRepository.Upsert(ConfigElementKey.XmltvTimeZone, xmltvSettings.TimeZone, cancellationToken);
await configElementRepository.Upsert(ConfigElementKey.XmltvDaysToBuild, xmltvSettings.DaysToBuild, cancellationToken);
await configElementRepository.Upsert(ConfigElementKey.XmltvBlockBehavior, xmltvSettings.BlockBehavior, cancellationToken);
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
foreach (string channelNumber in await dbContext.Channels.Map(c => c.Number).ToListAsync(cancellationToken))
{
await workerChannel.WriteAsync(new RefreshChannelData(channelNumber), cancellationToken);
}
return Unit.Default;
}
}

View File

@@ -1,4 +1,3 @@
namespace ErsatzTV.Application.Configuration
{
public record ConfigElementViewModel(string Key, string Value);
}
namespace ErsatzTV.Application.Configuration;
public record ConfigElementViewModel(string Key, string Value);

View File

@@ -0,0 +1,13 @@
using Serilog.Events;
namespace ErsatzTV.Application.Configuration;
public class LoggingSettingsViewModel
{
public LogEventLevel DefaultMinimumLogLevel { get; set; }
public LogEventLevel ScanningMinimumLogLevel { get; set; }
public LogEventLevel SchedulingMinimumLogLevel { get; set; }
public LogEventLevel SearchingMinimumLogLevel { get; set; }
public LogEventLevel StreamingMinimumLogLevel { get; set; }
public LogEventLevel HttpMinimumLogLevel { get; set; }
}

View File

@@ -1,10 +1,9 @@
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Application.Configuration
namespace ErsatzTV.Application.Configuration;
internal static class Mapper
{
internal static class Mapper
{
internal static ConfigElementViewModel ProjectToViewModel(ConfigElement element) =>
new(element.Key, element.Value);
}
internal static ConfigElementViewModel ProjectToViewModel(ConfigElement element) =>
new(element.Key, element.Value);
}

View File

@@ -0,0 +1,8 @@
namespace ErsatzTV.Application.Configuration;
public class PlayoutSettingsViewModel
{
public int DaysToBuild { get; set; }
public bool SkipMissingItems { get; set; }
public int ScriptedScheduleTimeoutSeconds { get; set; }
}

View File

@@ -1,8 +1,5 @@
using ErsatzTV.Core.Domain;
using LanguageExt;
using MediatR;
namespace ErsatzTV.Application.Configuration.Queries
{
public record GetConfigElementByKey(ConfigElementKey Key) : IRequest<Option<ConfigElementViewModel>>;
}
namespace ErsatzTV.Application.Configuration;
public record GetConfigElementByKey(ConfigElementKey Key) : IRequest<Option<ConfigElementViewModel>>;

View File

@@ -1,22 +1,17 @@
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
using ErsatzTV.Core.Interfaces.Repositories;
using static ErsatzTV.Application.Configuration.Mapper;
namespace ErsatzTV.Application.Configuration.Queries
namespace ErsatzTV.Application.Configuration;
public class GetConfigElementByKeyHandler : IRequestHandler<GetConfigElementByKey, Option<ConfigElementViewModel>>
{
public class GetConfigElementByKeyHandler : IRequestHandler<GetConfigElementByKey, Option<ConfigElementViewModel>>
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IConfigElementRepository _configElementRepository;
public GetConfigElementByKeyHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public GetConfigElementByKeyHandler(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
public Task<Option<ConfigElementViewModel>> Handle(
GetConfigElementByKey request,
CancellationToken cancellationToken) =>
_configElementRepository.Get(request.Key).MapT(ProjectToViewModel);
}
public Task<Option<ConfigElementViewModel>> Handle(
GetConfigElementByKey request,
CancellationToken cancellationToken) =>
_configElementRepository.GetConfigElement(request.Key, cancellationToken).MapT(ProjectToViewModel);
}

Some files were not shown because too many files have changed in this diff Show More