Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6828248
feat(subsonic): add star/unstar red-heart write, ported from feat/sub…
pyss56 Sep 6, 2026
45629af
feat(subsonic): add online fallback resolution for star/unstar (githu…
pyss56 Sep 6, 2026
8af9488
feat(subsonic): add album/artist star/unstar with meta persistence (g…
pyss56 Sep 6, 2026
5404016
fix(subsonic): reflect starred state in artist/album listings and bac…
pyss56 Sep 6, 2026
1c35634
Merge pull request #338 from pyss56/dev
XCQ0607 Sep 6, 2026
2fb6c89
chore(release): bump version to 2.0.2 and update changelog for #338 (…
XCQ0607 Sep 6, 2026
0f1d611
fix(subsonic): persist onlineSongCache across restarts and fix metada…
pyss56 Sep 6, 2026
ae7eefa
feat(subsonic): add cacheOnPlay option, UI and download dedup
pyss56 Sep 6, 2026
58199d2
chore: align public/js/config.js buildHash with upstream/dev to avoid…
pyss56 Sep 6, 2026
19fec64
fix(subsonic): serve cached audio directly in stream instead of fetch…
XCQ0607 Sep 7, 2026
e6db604
feat(subsonic): 增强缓存机制与收藏状态同步,支持双向持久化联动
XCQ0607 Sep 7, 2026
e209df2
Merge branch 'dev' into dev
XCQ0607 Sep 7, 2026
f9c0d8e
Merge pull request #339 from pyss56/dev
XCQ0607 Sep 7, 2026
6037de0
fix(filemanager): 修复返回后台导航跳转并升级 Material 现代主题 (#341)
XCQ0607 Sep 7, 2026
8c144b2
fix(settings): 修复歌曲命名方式修改不生效及无法触发重命名弹窗的问题 (#342)
XCQ0607 Sep 7, 2026
6a71fea
fix(subsonic): restore real cover URLs for home album lists (buildAlb…
pyss56 Sep 7, 2026
ab69f30
fix(player): 修复关闭“切换歌单”设置时列表退回失效及索引错误的问题 (#343)
XCQ0607 Sep 7, 2026
cf083e7
refactor(subsonic): extract cover image proxy into dedicated coverPro…
pyss56 Sep 7, 2026
95d27a7
fix(subsonic): bound cover cache to prevent OOM crash
pyss56 Sep 7, 2026
0c0d205
Merge branch 'dev' into dev
XCQ0607 Sep 7, 2026
663e037
fix(subsonic): 进程级共享媒体封面拉取并发控制与请求防击穿,收敛调试日志与补充更新日志 (#344)
XCQ0607 Sep 7, 2026
165a14d
fix(subsonic): 支持动态 Content-Type 响应,增加客户端中断防护与专辑封面 In-flight 复用 (#344)
XCQ0607 Sep 7, 2026
4ae7265
Merge pull request #344 from pyss56/dev
XCQ0607 Sep 7, 2026
1110d1e
fix(config): 配置文件默认持久化至 data/config.js 并支持平滑迁移 (#345)
XCQ0607 Sep 7, 2026
8578706
fix(subsonic): 限制封面缓存容量并增加传输层 read_timeout
XCQ0607 Sep 7, 2026
0f0d71e
feat(subsonic): expose QQ Music leaderboards as read-only virtual pla…
pyss56 Sep 8, 2026
70ff76a
feat(subsonic): 增加多平台公开排行榜开关和排行榜平台设置 (#348)
XCQ0607 Sep 8, 2026
e32e1ed
Merge pull request #348 from pyss56/feat/leaderboard
XCQ0607 Sep 8, 2026
329baca
fix(music): 修复自定义目录与本地音乐 songmid 类型异常报错 (#347)
XCQ0607 Sep 8, 2026
0bb781a
docs(notice): update
XCQ0607 Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ ENV BIND_IP='0.0.0.0'
# ENV LIST_ADD_MUSIC_LOCATION_TYPE 'top'
# ENV LX_USER_user1 '123.123'
# ENV LX_USER_user2 '{ "password": "123.456", "maxSnapshotNum": 10, "list.addMusicLocationType": "top" }'
# ENV CONFIG_PATH '/server/config.js'
# ENV CONFIG_PATH '/server/data/config.js'
# ENV WEBDAV_URL ''
# ENV WEBDAV_USERNAME ''
# ENV WEBDAV_PASSWORD ''
Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<h1>LX Sync Server</h1> -->
<p>
<img src="https://img.shields.io/badge/build-passing-brightgreen?style=flat-square" alt="Build Status">
<img src="https://img.shields.io/badge/version-v2.0.1-blue?style=flat-square" alt="Version">
<img src="https://img.shields.io/badge/version-v2.0.2-blue?style=flat-square" alt="Version">
<img src="https://img.shields.io/badge/node-%3E%3D16-green?style=flat-square" alt="Node Version">
<img src="https://img.shields.io/github/license/XCQ0607/lxserver?style=flat-square" alt="License">
<br>
Expand Down Expand Up @@ -252,7 +252,7 @@ npm start

## 🛠️ 配置说明

可以直接编辑 `config.js`。环境变量优先级最高:
系统配置文件已默认持久化在数据目录中的 `data/config.js`(Docker 部署只需挂载 `./data` 卷即可在容器更新、重启后永久保留配置,若根目录下存在旧 `config.js` 会自动平滑迁移)。环境变量优先级最高:

| 环境变量 | 对应配置项 | 说明 | 默认值 |
| --------------------------------------- | ------------------------------------ | ------------------------------------------------------------------ | ------------------ |
Expand All @@ -265,7 +265,7 @@ npm start
| `FRONTEND_PASSWORD` | `frontend.password` | Web 管理界面访问密码 | `123456` |
| `SERVER_NAME` | `serverName` | 同步服务名称 | `lxserver` |
| `MAX_SNAPSHOT_NUM` | `maxSnapshotNum` | 保留的最大快照数量 | `10` |
| `CONFIG_PATH` | - | 指定外部配置文件的绝对路径 | - |
| `CONFIG_PATH` | - | 指定外部配置文件的绝对路径 (默认使用 `data/config.js`) | - |
| `DATA_PATH` | - | 指定数据存储目录的绝对路径 | `./data` |
| `LOG_PATH` | - | 指定日志输出目录的绝对路径 | `./logs` |
| `PROXY_HEADER` | `proxy.header` | 代理转发 IP 头 (如 `x-real-ip`) | - |
Expand Down Expand Up @@ -299,7 +299,11 @@ npm start
| `SUBSONIC_ONLINE_SEARCH` | `subsonic.onlineSearch` | 是否开启 Subsonic 在线全网搜索 | `true` |
| `SUBSONIC_ONLINE_SEARCH_MODE` | `subsonic.onlineSearchMode` | Subsonic 在线搜索模式 (`fallback` / `merge` / `local_only`) | `fallback` |
| `SUBSONIC_ONLINE_SEARCH_SOURCES` | `subsonic.onlineSearchSources` | Subsonic 在线搜索默认音源列表 | `wy,tx,kw,kg,mg` |
| `SUBSONIC_PUBLIC_LEADERBOARDS` | `subsonic.publicLeaderboards` | 是否开启 Subsonic 公开排行榜 (将在线排行榜映射为只读歌单) | `true` |
| `SUBSONIC_LEADERBOARD_SOURCE` | `subsonic.leaderboardSource` | Subsonic 公开排行榜默认音源平台 (仅支持单选, 如 `tx`, `wy` 等) | `tx` |
| `SUBSONIC_LYRIC_TRANSLATION` | `subsonic.lyricTranslation` | Subsonic 歌词中是否包含翻译 | `true` |
| `SUBSONIC_CACHE_ON_PLAY` | `subsonic.cacheOnPlay` | Subsonic 播放时是否触发服务器自动缓存保存 (落盘到用户目录) | `false` |
| `SUBSONIC_PLAY_CACHE_FIRST` | `subsonic.playCacheFirst` | Subsonic 播放时是否优先使用服务器已有的本地缓存/下载文件直接传输 | `true` |
| `ARTIST_MAX_FETCH_PAGES` | `artist.maxFetchPages` | 歌手歌曲最大抓取页数 | `20` |
| `CACHE_NAMING_PATTERN` | `cache.namingPattern` | 缓存文件命名规则 (`simple` / `custom`) | `simple` |
| `SYSTEM_ALLOW_UNSAFE_VM` | `system.allowUnsafeVM` | 是否允许运行 VM 模式自定义源脚本 (需注意安全风险) | `false` |
Expand Down
10 changes: 7 additions & 3 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<div align="center">
<p>
<img src="https://img.shields.io/badge/build-passing-brightgreen?style=flat-square" alt="Build Status">
<img src="https://img.shields.io/badge/version-v2.0.1-blue?style=flat-square" alt="Version">
<img src="https://img.shields.io/badge/version-v2.0.2-blue?style=flat-square" alt="Version">
<img src="https://img.shields.io/badge/node-%3E%3D16-green?style=flat-square" alt="Node Version">
<img src="https://img.shields.io/github/license/XCQ0607/lxserver?style=flat-square" alt="License">
<br>
Expand Down Expand Up @@ -242,7 +242,7 @@ Separated frontend and backend architecture based on Node.js:

## 🛠️ Configuration

Edit `config.js` directly. Environment variables take precedence:
The configuration file is persisted by default in the data directory at `data/config.js` (Docker deployments only need to mount the `./data` volume to retain all settings across container updates and restarts; existing legacy `config.js` in root will be migrated automatically). Environment variables take precedence:

| Env Variable | Config Key | Description | Default |
| --- | --- | --- | --- |
Expand All @@ -255,7 +255,7 @@ Edit `config.js` directly. Environment variables take precedence:
| `FRONTEND_PASSWORD` | `frontend.password` | Web dashboard password | `123456` |
| `SERVER_NAME` | `serverName` | Sync service name | `lxserver` |
| `MAX_SNAPSHOT_NUM` | `maxSnapshotNum` | Max snapshots to keep | `10` |
| `CONFIG_PATH` | - | Absolute path to external config file | - |
| `CONFIG_PATH` | - | Absolute path to external config file (defaults to `data/config.js`) | - |
| `DATA_PATH` | - | Absolute path to data storage directory | `./data` |
| `LOG_PATH` | - | Absolute path to log output directory | `./logs` |
| `PROXY_HEADER` | `proxy.header` | Proxy IP header (e.g., `x-real-ip`) | - |
Expand Down Expand Up @@ -289,7 +289,11 @@ Edit `config.js` directly. Environment variables take precedence:
| `SUBSONIC_ONLINE_SEARCH` | `subsonic.onlineSearch` | Enable Subsonic online search | `true` |
| `SUBSONIC_ONLINE_SEARCH_MODE` | `subsonic.onlineSearchMode` | Subsonic online search mode (`fallback` / `merge` / `local_only`) | `fallback` |
| `SUBSONIC_ONLINE_SEARCH_SOURCES` | `subsonic.onlineSearchSources` | Subsonic online search default platforms | `wy,tx,kw,kg,mg` |
| `SUBSONIC_PUBLIC_LEADERBOARDS` | `subsonic.publicLeaderboards` | Enable Subsonic public leaderboards (map online charts to read-only playlists) | `true` |
| `SUBSONIC_LEADERBOARD_SOURCE` | `subsonic.leaderboardSource` | Subsonic public leaderboard default platform (single platform, e.g., `tx`, `wy`) | `tx` |
| `SUBSONIC_LYRIC_TRANSLATION` | `subsonic.lyricTranslation` | Include translations in Subsonic lyrics | `true` |
| `SUBSONIC_CACHE_ON_PLAY` | `subsonic.cacheOnPlay` | Trigger server caching on Subsonic playback (cached to user dir) | `false` |
| `SUBSONIC_PLAY_CACHE_FIRST` | `subsonic.playCacheFirst` | Prefer streaming local cached/downloaded files on Subsonic playback | `true` |
| `ARTIST_MAX_FETCH_PAGES` | `artist.maxFetchPages` | Maximum fetch pages for artist tracks | `20` |
| `CACHE_NAMING_PATTERN` | `cache.namingPattern` | Cache file naming rule (`simple` / `custom`) | `simple` |
| `SYSTEM_ALLOW_UNSAFE_VM` | `system.allowUnsafeVM` | Allow VM mode custom source scripts (note security risks) | `false` |
Expand Down
62 changes: 62 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,67 @@
# Changelog

## v2.0.2 (2026-09-07)

### 🌟 新增功能

- **Subsonic 公开排行榜映射 (#348 @pyss56)**:
- **在线排行榜暴露**: 在 Subsonic 协议中将各平台(如 QQ 音乐)的在线排行榜暴露为只读虚拟歌单,歌单统一归属于虚拟用户 `lxserver` 的公开歌单中,支持通过平台设置查看不同平台的榜单数据。
- **设置项扩展**: 在系统设置中新增了独立的“开启公开排行榜映射”开关及“排行榜音源平台”配置,界面采用现代 Tag 标签单选交互,方便一键切换目标数据源。
- ![Subsonic Leaderboard Settings](md/log/2.0.2-2.png)

- **Subsonic 播放缓存能力** :

- **播放时触发服务器缓存 (#339 @pyss56)**: 新增 `subsonic.cacheOnPlay` 独立开关,支持在通过 Subsonic 协议播放音乐时,在后台自动将曲目落盘至用户的缓存目录,已缓存的会自动跳过,极大增强离线体验。(注意:开启此项可能产生较大流量)
- **服务器存在缓存优先播放**: 新增独立开关,开启后通过 Subsonic 播放曲目时,若服务器已存在该歌曲的缓存或下载文件,将直接通过本地流式传输,避免重复向源站发起请求。
- **切歌并发控制**: 为防止用户在客户端快速切歌导致后台并行下载任务堆积跑满带宽,新增了流式响应的 Abort (取消) 控制器调度机制,在客户端断开连接时自动终止缓存任务。
- ![Subsonic Settings](md/log/2.0.2-1.png)
- **Subsonic 红心收藏/取消收藏功能与持久化联动 (#338 @pyss56)**:

- **红心收藏与写入**: 新增 Subsonic 协议 star 与 unstar 接口,支持单曲(id)、专辑(albumId)与歌手(artistId)收藏。歌曲实时写入/移出用户的「我的收藏(love)」歌单并生成快照持久化。
- **在线兜底解析**: 收藏不在本地歌单中的单曲时,支持自动通过平台源在线反查元数据后写入收藏。
- **媒体库双向联动**: 建立 `subsonic-meta.json` 扩展元数据,打通音流等客户端与 LX Web 前端原生媒体库(artists.json / albums.json)的双向收藏同步。
- **星标状态与封面防崩**: 优化 getArtists / getArtist 及单曲对象,实时回显 starred 标记;修复专辑封面读取导致的 Node 服务异常,提升客户端交互体验与稳定性。
- **Subsonic 在线元数据落盘持久化**:

- 将此前仅存于内存的在线歌曲缓存升级为磁盘文件持久化(写入 `subsonic-online-cache.json`),引入防抖批量聚合与原子写入,彻底解决服务端重启导致检索元数据丢失的问题。
- **文件管理器现代化与路由联动**:

- **动态感知管理后台路径 (#341)**: 将文件管理器快捷操作栏的「返回主页」按钮优化为「返回后台」,通过动态读取服务端 `admin.path` 环境变量与配置(`window.CONFIG['admin.path']`),支持在自定义管理后台路径下精准跳转回对应后台控制台。
- **引入 Material 现代主题**: 引入现代 Material Design 样式,全面升级工具栏、列表区与右键菜单视觉效果,提供更具质感的扁平与圆角交互体验。

### 🔧 修复与优化

- **播放列表回退逻辑修复 (#343)**:
- **搜索与歌单列表回退 UI 刷新**: 修复了在关闭“播放时切换歌单”相关设置后,点击搜索列表或歌单中的单曲播放时,界面播放队列依然错误显示为整个搜索列表/歌单,且当前播放索引被强制置零的 Bug。现在回退默认试听列表时 UI 会正确刷新并精确定位到刚刚播放的新歌。
- **Subsonic 收藏 (红心) 状态全局联动修复**:
- **`getStarred` 接口精准剥离**: 修复了获取已星标收藏列表时,服务端错误地聚合所有自定义歌单的 Bug。现在客户端的“我的收藏”严格镜像服务端的 `love` 列表。
- **Subsonic 封面代理与首页/推荐专辑封面修复 (#344 @pyss56)**:
- **抽取独立封面代理模块 (`coverProxy`)**: 将此前客户端 302 重定向拉取封面的模式重构为服务端代理流式返回,内置并发信号量调度(限制同时回源并发数)、自动失败重试(最多 3 次)与内存缓存降级(`STALE`)保护,彻底解决音流等客户端冷启动并发拉取封面被平台 CDN 封禁导致的封面大面积空白问题。
- **恢复首页/推荐与云端专辑封面**: 新增 `buildAlbumCoverUrl` 根据 mid 动态构造云端封面,并为网易云等无法直接拼接 URL 的专辑接入 SDK 详情兜底拉取首曲封面;同时为推荐接口引入抖动自动重试机制。
- **进程级并发队列与请求防击穿**: 将媒体库专辑/歌手补全封面的并发控制提升至模块进程级,并实现 In-flight Promise 复用,防止多客户端并发请求击穿音源;带缓存容量上限管理,预防内存泄露与 OOM。
- **歌曲命名方式修改与重命名联动修复 (#342)**:
- **修复新命名规则无法选中及保存**: 修复前端 `SETTINGS_UI_MAP` 中 `serverCacheNamingPattern` 的 `normalize` 规则遗漏新命名模式的问题,解决选择“歌手-歌名-音质-专辑”、“歌手-歌名”或“歌名-歌手”后无法选中并自动弹回“简洁”的 Bug。
- **配置持久化与 Docker 升级数据保留优化 (#345)**:
- **配置文件默认迁移至数据卷目录 (`data/config.js`)**: 将服务配置文件的默认持久化路径从容易随容器销毁而丢失的根目录重定向至持久化卷目录 `data/config.js`,彻底解决 Docker/Watchtower 升级或重建容器后通过后台保存的所有设置(密码、路径、用户权限等)静默重置为默认值的 Bug。
- **平滑无感兼容迁移**: 服务启动时若 `data/config.js` 尚不存在,将自动从根目录旧 `config.js` 迁移至 `data/config.js`,无需用户手动修改挂载映射。
- **WebDAV 备份与同步统一**: WebDAV 增量同步与全量打包天然覆盖 `data/config.js`,移除了繁琐的根目录文件特判与转移代码,增强了数据备份的稳定性。

- **自定义目录与本地音乐异常报错修复 (#347)**:
- **修复 songmid 类型异常导致的崩溃**: 修复了在自定义目录关联歌曲、重新渲染或操作本地音乐列表时,由于极少部分未索引歌曲的 `songmid` 为数字类型从而触发 `item.songmid.includes is not a function` 导致组件或整个页面崩溃、误报权限错误的 Bug。

### 💡 升级与迁移建议 (Migration Guide)

- **标准 Docker / Docker Compose 用户(推荐)**:
- 本次更新针对 Docker 容器生命周期进行了无感平滑迁移设计。如果您按照官方推荐挂载了 `./data:/server/data` 目录:
- **直接拉取新镜像重启容器即可**(`docker compose pull && docker compose up -d` 或 Watchtower 自动更新)。
- 容器首次启动时,程序会自动检测并初始化持久化配置文件 `data/config.js`。
- 以后在 Web 管理后台保存的所有配置(包括自定义路径、密码、缓存策略等)都将安全持久化在 `./data/config.js` 中,**后续任何镜像更新或容器销毁重建均不会再丢失配置**。
- **曾手动挂载过 `-v ./data/config.js:/server/config.js` 的用户**:
- 现在系统原生支持读取和写入 `data/config.js`,您可以继续保留该挂载,也可以直接精简 `docker-compose.yml`,移除单独的 `config.js` 挂载项,仅保留 `./data:/server/data` 即可。
- **源码直接运行 / Node.js 物理机部署用户**:
- 系统启动时若发现 `data/config.js` 不存在,会自动将项目根目录现有的 `config.js` 复制到 `data/config.js` 并作为主配置生效。
- 建议后续直接在后台管理页面修改配置,或直接编辑 `data/config.js`。如需使用自定义配置文件路径,可继续通过环境变量 `CONFIG_PATH` 显式指定。

## v2.0.1 (2026-07-23)

### 🌟 新增功能
Expand Down
8 changes: 8 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ module.exports = {
// 环境变量: SUBSONIC_LYRIC_TRANSLATION
"subsonic.lyricTranslation": true,

// 是否在 Subsonic 播放音乐时触发服务器缓存保存 (落盘到该用户缓存目录,已缓存自动跳过)
// 环境变量: SUBSONIC_CACHE_ON_PLAY (true/false)
"subsonic.cacheOnPlay": false,

// 是否在 Subsonic 播放音乐时优先使用本地缓存/下载文件直接流式传输 (默认开启)
// 环境变量: SUBSONIC_PLAY_CACHE_FIRST (true/false)
"subsonic.playCacheFirst": true,

// 歌手信息源优先级 (多个源用逗号分隔,如 tx,wy)
// 环境变量: SINGER_SOURCE_PRIORITY
"singer.sourcePriority": [
Expand Down
10 changes: 5 additions & 5 deletions docs/en/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ LX Music Sync Server has built a unified basic model skeleton (located in `src/d
The loading and merging of configurations follow the priority sequence from high to low below. High-priority options will **hardly override** the corresponding keys of low-priority ones:

1. **Runtime Environment Variables (Environment Variables)**: Has very high priority. For example, `PORT=9527`.
2. **WebDAV Cloud Data (WebDAV Cloud Data)**: If WebDAV is configured, the system will try to restore from the cloud on startup. **Restored cloud content will overwrite the local `config.js` and trigger a hot-reload**.
3. **Explicit Custom Configuration File Path (Custom Config File)**: Static JSON file specified via `CONFIG_PATH`.
4. **Global Default Entry Configuration (Global Config.js)**: The `config.js` file in the project's root directory.
2. **WebDAV Cloud Data (WebDAV Cloud Data)**: If WebDAV is configured, the system will try to restore from the cloud on startup. **Restored cloud content will overwrite persistent `data/config.js` and trigger a hot-reload**.
3. **Explicit Custom Configuration File Path (Custom Config File)**: Path specified via `CONFIG_PATH` (defaults to persistent `data/config.js` inside the data directory).
4. **Persistent Configuration (Persistent Config)**: The `data/config.js` in the data directory (if absent on first launch, will smoothly migrate from legacy root `config.js`).
5. **System-level Default Constants (Default Consts)**: Defaults in `src/defaultConfig.ts`.

---
Expand Down Expand Up @@ -74,8 +74,8 @@ The underlying periodic polling asynchronous daemon of the service will only be
| `SYNC_INTERVAL` | `60` | Integer | Cold shrinking timed parameters (unit: minutes) that trigger full thermal backup and pull comparison synchronization flow periods. |

> 🔖 **Stateful Resurrection and Initialization Mechanism**:
> 1. **Cloud-First Restore**: If the variables are detected on startup, the system prioritizes pulling archives from the cloud.
> 2. **Environment-Driven Persistence**: If the cloud config is empty (e.g., first deployment in Docker/Cloud), the system will **automatically persist the current effective configuration (such as ports, passwords set via environment variables) into the local `config.js` and upload it to the cloud** for initialization. This ensures you can establish the initial cloud data solely through environment variables.
> 1. **Cloud-First Restoration**: If this set of variables is detected at startup, the system will prioritize attempting to pull archives from the cloud.
> 2. **Environment-Driven Persistence**: If the cloud config is empty (e.g., first deployment in Docker/Cloud), the system will **automatically persist the current effective configuration (such as ports, passwords set via environment variables) into `data/config.js` in the data directory and upload it to the cloud** for initialization. This ensures you can establish the initial cloud data solely through environment variables.

### IV. Web-side Composite Media Playback Space Protection Logic

Expand Down
Loading