toposync-ext-streaming 0.4.0__tar.gz → 0.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/PKG-INFO +2 -2
  2. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/README.md +1 -1
  3. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/pyproject.toml +1 -1
  4. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/api/models.py +1 -1
  5. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/api/routes.py +34 -8
  6. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/writer_bridge.py +1 -1
  7. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/.gitignore +0 -0
  8. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/LICENSE +0 -0
  9. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/LICENSE.ffmpeg +0 -0
  10. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/LICENSE.mediamtx +0 -0
  11. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/__init__.py +0 -0
  12. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/api/__init__.py +0 -0
  13. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/bin/ffmpeg/LICENSE +0 -0
  14. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/bin/mediamtx/LICENSE +0 -0
  15. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/extension.json +0 -0
  16. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/pipelines/__init__.py +0 -0
  17. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/pipelines/operators.py +0 -0
  18. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/plugin.py +0 -0
  19. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/326.js +0 -0
  20. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/326.js.LICENSE.txt +0 -0
  21. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/4.js +0 -0
  22. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/4.js.LICENSE.txt +0 -0
  23. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/623.js +0 -0
  24. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/623.js.LICENSE.txt +0 -0
  25. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/703.js +0 -0
  26. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/703.js.LICENSE.txt +0 -0
  27. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/main.js +0 -0
  28. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/main.js.LICENSE.txt +0 -0
  29. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/static/remoteEntry.js +0 -0
  30. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/__init__.py +0 -0
  31. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/arbitration.py +0 -0
  32. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/camera_ingest.py +0 -0
  33. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/distributed_sync.py +0 -0
  34. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/encoder_state.py +0 -0
  35. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/engine_manager.py +0 -0
  36. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/ffmpeg_binary.py +0 -0
  37. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/go2rtc_binary.py +0 -0
  38. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/go2rtc_config.py +0 -0
  39. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/go2rtc_manager.py +0 -0
  40. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/ingest_auth.py +0 -0
  41. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/ingest_resolver.py +0 -0
  42. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/jsmpeg_manager.py +0 -0
  43. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/mediamtx_api_client.py +0 -0
  44. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/mediamtx_binary.py +0 -0
  45. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/mediamtx_config.py +0 -0
  46. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/mediamtx_processes.py +0 -0
  47. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/placeholder.py +0 -0
  48. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/platform.py +0 -0
  49. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/playback_events.py +0 -0
  50. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/publisher_manager.py +0 -0
  51. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/resize.py +0 -0
  52. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/streaming/runtime_state.py +0 -0
  53. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/wizard/__init__.py +0 -0
  54. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/src/toposync_ext_streaming/wizard/pipeline_builder.py +0 -0
  55. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/package.json +0 -0
  56. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/activate.tsx +0 -0
  57. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/api/streamingApi.ts +0 -0
  58. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/constants.ts +0 -0
  59. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/entry.ts +0 -0
  60. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/settings/StreamingSettingsPanel.tsx +0 -0
  61. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/settings/SubModal.tsx +0 -0
  62. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/settings/WizardCreatePipelineFromTransmission.tsx +0 -0
  63. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/translations.ts +0 -0
  64. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/src/types.ts +0 -0
  65. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/tsconfig.json +0 -0
  66. {toposync_ext_streaming-0.4.0 → toposync_ext_streaming-0.4.2}/ui/webpack.config.js +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: toposync-ext-streaming
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Toposync first-party extension: streaming settings, API surface, and pipeline sink bootstrap.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -1106,7 +1106,7 @@ Then run Toposync as usual (see repo `docs/DEVELOPMENT.md`).
1106
1106
 
1107
1107
  - Public wheels do not ship MediaMTX binaries. The extension downloads the correct release asset on demand and caches it under `runtime/streaming/mediamtx/<version>/<platform>/`.
1108
1108
  - License notice: [LICENSE.mediamtx](LICENSE.mediamtx)
1109
- - Public wheels do not ship go2rtc binaries. The MSE sidecar downloads go2rtc `v1.9.14` on demand and caches it under `~/.toposync/runtime/streaming/go2rtc/<version>/<platform>/`, unless `TOPOSYNC_STREAMING_GO2RTC_PATH` points to an explicit binary.
1109
+ - Public wheels do not ship go2rtc binaries. The MSE sidecar downloads go2rtc `v1.9.14` automatically on first start and caches it under `~/.toposync/runtime/streaming/go2rtc/<version>/<platform>/`, unless `TOPOSYNC_STREAMING_GO2RTC_PATH` points to an explicit binary. The official Docker/Home Assistant images can pre-bundle `/usr/local/bin/go2rtc` and set that environment variable so MSE does not depend on a runtime download.
1110
1110
  - FFmpeg integration expects an external binary by default (`PATH` or `TOPOSYNC_STREAMING_FFMPEG_PATH`). Bundling FFmpeg binaries is optional and must be handled carefully for redistribution.
1111
1111
  - License placeholder: [LICENSE.ffmpeg](LICENSE.ffmpeg)
1112
1112
 
@@ -1093,7 +1093,7 @@ Then run Toposync as usual (see repo `docs/DEVELOPMENT.md`).
1093
1093
 
1094
1094
  - Public wheels do not ship MediaMTX binaries. The extension downloads the correct release asset on demand and caches it under `runtime/streaming/mediamtx/<version>/<platform>/`.
1095
1095
  - License notice: [LICENSE.mediamtx](LICENSE.mediamtx)
1096
- - Public wheels do not ship go2rtc binaries. The MSE sidecar downloads go2rtc `v1.9.14` on demand and caches it under `~/.toposync/runtime/streaming/go2rtc/<version>/<platform>/`, unless `TOPOSYNC_STREAMING_GO2RTC_PATH` points to an explicit binary.
1096
+ - Public wheels do not ship go2rtc binaries. The MSE sidecar downloads go2rtc `v1.9.14` automatically on first start and caches it under `~/.toposync/runtime/streaming/go2rtc/<version>/<platform>/`, unless `TOPOSYNC_STREAMING_GO2RTC_PATH` points to an explicit binary. The official Docker/Home Assistant images can pre-bundle `/usr/local/bin/go2rtc` and set that environment variable so MSE does not depend on a runtime download.
1097
1097
  - FFmpeg integration expects an external binary by default (`PATH` or `TOPOSYNC_STREAMING_FFMPEG_PATH`). Bundling FFmpeg binaries is optional and must be handled carefully for redistribution.
1098
1098
  - License placeholder: [LICENSE.ffmpeg](LICENSE.ffmpeg)
1099
1099
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "toposync-ext-streaming"
3
- version = "0.4.0"
3
+ version = "0.4.2"
4
4
  description = "Toposync first-party extension: streaming settings, API surface, and pipeline sink bootstrap."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -1377,7 +1377,7 @@ class TransmissionDemandHeartbeatRequest(BaseModel):
1377
1377
  quality_profile_id: StreamingQualityProfileId | None = None
1378
1378
  transport: Literal["hls", "webrtc", "rtsp", "mse", "jsmpeg"] = "hls"
1379
1379
  source: Literal["player", "home_assistant_entity"] = "player"
1380
- ttl_seconds: float | None = Field(default=None, ge=5.0, le=300.0)
1380
+ ttl_seconds: float | None = Field(default=None, ge=5.0, le=1800.0)
1381
1381
 
1382
1382
 
1383
1383
  class TransmissionDemandHeartbeatResponse(BaseModel):
@@ -518,6 +518,7 @@ def _hls_proxy_public_base_path(request: Request) -> str:
518
518
 
519
519
  MEDIA_TOKEN_SCOPE = "stream:media:read"
520
520
  LEGACY_HLS_MEDIA_TOKEN_SCOPE = "stream:hls:read"
521
+ MAX_MEDIA_TOKEN_TTL_OVERRIDE_SECONDS = 1800.0
521
522
 
522
523
 
523
524
  def _hls_proxy_url(
@@ -571,15 +572,10 @@ def _mse_sidecar_start_blocking_errors(
571
572
  if settings.engine.enabled and settings.engine.mse_sidecar.enabled:
572
573
  try:
573
574
  platform = detect_go2rtc_platform()
574
- installed = find_installed_go2rtc_binary(
575
+ find_installed_go2rtc_binary(
575
576
  platform=platform,
576
577
  version=settings.engine.mse_sidecar.go2rtc_version,
577
578
  )
578
- if installed is None:
579
- errors.append(
580
- "go2rtc binary is not installed. Use /api/streams/mse/download or set "
581
- "TOPOSYNC_STREAMING_GO2RTC_PATH before using MSE."
582
- )
583
579
  except Exception as exc:
584
580
  errors.append(f"go2rtc binary is unavailable: {exc}")
585
581
  return _dedupe_messages(errors)
@@ -656,9 +652,18 @@ def _issue_media_token(
656
652
  output: TransmissionOutput,
657
653
  engine_path: str,
658
654
  transport: Literal["hls", "mse", "jsmpeg"],
655
+ ttl_seconds: float | None = None,
659
656
  ) -> tuple[str, float, float]:
660
657
  now = time.time()
661
- ttl_s = max(30.0, float(settings.engine.media_auth.token_ttl_seconds))
658
+ configured_ttl_s = max(30.0, float(settings.engine.media_auth.token_ttl_seconds))
659
+ if ttl_seconds is not None:
660
+ requested_ttl_s = max(
661
+ 30.0,
662
+ min(float(ttl_seconds), MAX_MEDIA_TOKEN_TTL_OVERRIDE_SECONDS),
663
+ )
664
+ ttl_s = max(configured_ttl_s, requested_ttl_s)
665
+ else:
666
+ ttl_s = configured_ttl_s
662
667
  renew_margin_s = max(1.0, float(settings.engine.media_auth.renew_margin_seconds))
663
668
  expires_at = now + ttl_s
664
669
  renew_after = max(now, expires_at - min(renew_margin_s, ttl_s - 1.0))
@@ -685,6 +690,7 @@ def _issue_hls_media_token(
685
690
  transmission: Transmission,
686
691
  output: TransmissionOutput,
687
692
  engine_path: str,
693
+ ttl_seconds: float | None = None,
688
694
  ) -> tuple[str, float, float]:
689
695
  return _issue_media_token(
690
696
  config_store=config_store,
@@ -693,6 +699,7 @@ def _issue_hls_media_token(
693
699
  output=output,
694
700
  engine_path=engine_path,
695
701
  transport="hls",
702
+ ttl_seconds=ttl_seconds,
696
703
  )
697
704
 
698
705
 
@@ -1540,6 +1547,7 @@ async def _resolve_local_transmission_urls(
1540
1547
  transmission: Transmission,
1541
1548
  output_id: str | None = None,
1542
1549
  quality_profile_id: str | None = None,
1550
+ media_token_ttl_seconds: float | None = None,
1543
1551
  ) -> TransmissionUrlsResponse:
1544
1552
  bridge = _writer_bridge(request)
1545
1553
  prime_demand = getattr(bridge, "prime_transmission_demand", None)
@@ -1677,6 +1685,7 @@ async def _resolve_local_transmission_urls(
1677
1685
  transmission=transmission,
1678
1686
  output=output,
1679
1687
  engine_path=engine_path,
1688
+ ttl_seconds=media_token_ttl_seconds,
1680
1689
  )
1681
1690
  url = _hls_proxy_url(request, engine_path, media_token=media_token) or ""
1682
1691
  media_auth_type = "signed_url"
@@ -1706,6 +1715,7 @@ async def _resolve_local_transmission_urls(
1706
1715
  output=output,
1707
1716
  engine_path=engine_path,
1708
1717
  transport="mse",
1718
+ ttl_seconds=media_token_ttl_seconds,
1709
1719
  )
1710
1720
  outputs.append(
1711
1721
  TransmissionOutputUrl(
@@ -1729,6 +1739,7 @@ async def _resolve_local_transmission_urls(
1729
1739
  output=output,
1730
1740
  engine_path=engine_path,
1731
1741
  transport="jsmpeg",
1742
+ ttl_seconds=media_token_ttl_seconds,
1732
1743
  )
1733
1744
  outputs.append(
1734
1745
  TransmissionOutputUrl(
@@ -1781,6 +1792,7 @@ async def _resolve_local_transmission_urls(
1781
1792
  output=output,
1782
1793
  engine_path=engine_path,
1783
1794
  transport="mse",
1795
+ ttl_seconds=media_token_ttl_seconds,
1784
1796
  )
1785
1797
  outputs.append(
1786
1798
  TransmissionOutputUrl(
@@ -1804,6 +1816,7 @@ async def _resolve_local_transmission_urls(
1804
1816
  output=output,
1805
1817
  engine_path=engine_path,
1806
1818
  transport="jsmpeg",
1819
+ ttl_seconds=media_token_ttl_seconds,
1807
1820
  )
1808
1821
  outputs.append(
1809
1822
  TransmissionOutputUrl(
@@ -1851,6 +1864,7 @@ async def _resolve_remote_transmission_urls(
1851
1864
  transmission: Transmission,
1852
1865
  output_id: str | None = None,
1853
1866
  quality_profile_id: str | None = None,
1867
+ media_token_ttl_seconds: float | None = None,
1854
1868
  ) -> TransmissionUrlsResponse:
1855
1869
  servers_by_id = await _processing_servers_by_id(config_store)
1856
1870
  host_server_id = normalize_server_id(transmission.host_server_id, fallback="local")
@@ -1877,6 +1891,7 @@ async def _resolve_remote_transmission_urls(
1877
1891
  for key, value in {
1878
1892
  "output_id": str(output_id or "").strip(),
1879
1893
  "quality_profile_id": str(quality_profile_id or "").strip(),
1894
+ "media_token_ttl_seconds": str(media_token_ttl_seconds or "").strip(),
1880
1895
  }.items()
1881
1896
  if value
1882
1897
  }
@@ -5951,7 +5966,7 @@ def create_streaming_router() -> APIRouter:
5951
5966
  warnings.append("MSE sidecar needs the MediaMTX streaming engine to be enabled.")
5952
5967
  if settings.engine.mse_sidecar.enabled and not status.running and not binary_path:
5953
5968
  warnings.append(
5954
- "go2rtc binary is not installed yet. Starting MSE will download it (internet required), "
5969
+ "go2rtc binary is not installed yet. The next MSE start will download it automatically (internet required), "
5955
5970
  "or set TOPOSYNC_STREAMING_GO2RTC_PATH to a local path."
5956
5971
  )
5957
5972
  return StreamingMseSidecarStatusResponse(
@@ -6290,6 +6305,7 @@ def create_streaming_router() -> APIRouter:
6290
6305
  live_view_id: str,
6291
6306
  context: StreamingCameraLiveContext = "thumbnail",
6292
6307
  variant_id: str | None = None,
6308
+ media_token_ttl_seconds: float | None = None,
6293
6309
  ) -> CameraLiveViewPlaybackResponse:
6294
6310
  _require_auth(request, action="core:settings:read")
6295
6311
  config_store = _config_store(request)
@@ -6343,12 +6359,14 @@ def create_streaming_router() -> APIRouter:
6343
6359
  settings=settings,
6344
6360
  transmission=transmission,
6345
6361
  quality_profile_id=variant.quality_profile_id,
6362
+ media_token_ttl_seconds=media_token_ttl_seconds,
6346
6363
  )
6347
6364
  else:
6348
6365
  urls = await _resolve_remote_transmission_urls(
6349
6366
  config_store=config_store,
6350
6367
  transmission=transmission,
6351
6368
  quality_profile_id=variant.quality_profile_id,
6369
+ media_token_ttl_seconds=media_token_ttl_seconds,
6352
6370
  )
6353
6371
 
6354
6372
  selected_output = _select_live_playback_output(urls=urls, variant=variant)
@@ -7440,6 +7458,7 @@ def create_streaming_router() -> APIRouter:
7440
7458
  transmission_id: str,
7441
7459
  output_id: str | None = None,
7442
7460
  quality_profile_id: str | None = None,
7461
+ media_token_ttl_seconds: float | None = None,
7443
7462
  ) -> TransmissionUrlsResponse:
7444
7463
  _require_auth(request, action="core:settings:read")
7445
7464
  config_store = _config_store(request)
@@ -7461,12 +7480,14 @@ def create_streaming_router() -> APIRouter:
7461
7480
  transmission=transmission,
7462
7481
  output_id=output_id,
7463
7482
  quality_profile_id=quality_profile_id,
7483
+ media_token_ttl_seconds=media_token_ttl_seconds,
7464
7484
  )
7465
7485
  return await _resolve_remote_transmission_urls(
7466
7486
  config_store=config_store,
7467
7487
  transmission=transmission,
7468
7488
  output_id=output_id,
7469
7489
  quality_profile_id=quality_profile_id,
7490
+ media_token_ttl_seconds=media_token_ttl_seconds,
7470
7491
  )
7471
7492
 
7472
7493
  @router.get(
@@ -7481,6 +7502,7 @@ def create_streaming_router() -> APIRouter:
7481
7502
  quality_profile_id: str | None = None,
7482
7503
  context: StreamingCameraLiveContext | None = None,
7483
7504
  low_latency: bool = False,
7505
+ media_token_ttl_seconds: float | None = None,
7484
7506
  ) -> StreamingPlaybackPlanResponse:
7485
7507
  _require_auth(request, action="core:settings:read")
7486
7508
  config_store = _config_store(request)
@@ -7498,6 +7520,7 @@ def create_streaming_router() -> APIRouter:
7498
7520
  transmission=transmission,
7499
7521
  output_id=output_id,
7500
7522
  quality_profile_id=quality_profile_id,
7523
+ media_token_ttl_seconds=media_token_ttl_seconds,
7501
7524
  )
7502
7525
  runtime_health: StreamingRuntimeTransmissionHealth | None = None
7503
7526
  try:
@@ -7514,6 +7537,7 @@ def create_streaming_router() -> APIRouter:
7514
7537
  transmission=transmission,
7515
7538
  output_id=output_id,
7516
7539
  quality_profile_id=quality_profile_id,
7540
+ media_token_ttl_seconds=media_token_ttl_seconds,
7517
7541
  )
7518
7542
  runtime_health = None
7519
7543
 
@@ -7693,6 +7717,7 @@ def create_streaming_router() -> APIRouter:
7693
7717
  transmission_id: str,
7694
7718
  output_id: str | None = None,
7695
7719
  quality_profile_id: str | None = None,
7720
+ media_token_ttl_seconds: float | None = None,
7696
7721
  ) -> TransmissionUrlsResponse:
7697
7722
  _require_auth(request, action="core:settings:read")
7698
7723
  config_store = _config_store(request)
@@ -7721,6 +7746,7 @@ def create_streaming_router() -> APIRouter:
7721
7746
  transmission=transmission,
7722
7747
  output_id=output_id,
7723
7748
  quality_profile_id=quality_profile_id,
7749
+ media_token_ttl_seconds=media_token_ttl_seconds,
7724
7750
  )
7725
7751
 
7726
7752
  @router.get("/distributed/settings/{server_id}", response_model=StreamingExtensionSettings)
@@ -238,7 +238,7 @@ class StreamWriterBridge:
238
238
  selected_profile_id = _as_str(quality_profile_id)
239
239
 
240
240
  now_monotonic = self._monotonic()
241
- ttl = self._on_demand_prime_ttl_s if ttl_s is None else min(300.0, max(1.0, float(ttl_s)))
241
+ ttl = self._on_demand_prime_ttl_s if ttl_s is None else min(1800.0, max(1.0, float(ttl_s)))
242
242
  _engine_settings, targets, _path_auth, _bypass, _ingest, _ingest_configs = await self._load_settings(now_monotonic)
243
243
 
244
244
  primed_publishers: set[str] = set()