Repository Wiki
ldx123000/Hydrogen-Music

Player Queue & Audio Quality

本页记录当前可核实的播放队列随机排序逻辑,以及音质部分的证据边界。已提供的源码仅包含三个随机队列辅助函数及一个随机整数函数;没有播放器、音频请求或音质选择的实现资料,因此不能把队列算法描述成完整的播放器或音质系统。

Purpose and Scope

面向维护播放队列的开发者,说明随机排列、跨周期换序和歌曲 ID 集合比较的实际行为。本文依据请求中提供的 1–78 行源码;未提供仓库相对文件路径、File Reference Base URL 或可用的源码读取工具,因此无法建立可验证的文件链接。音质等级、编码格式、音源选择、实际播放顺序的状态持久化及 UI 行为均不在可核实范围内;相关实现细节未在所提供源码中找到。

Overview

createShuffledList 从输入列表复制出新数组,逐项与前缀中的一个随机位置交换;可选择把当前歌曲置于开头,并在指定条件下避免首曲重复。createNextShuffledCycle 基于同一排序函数生成下一周期,并在特定条件下防止下一周期与上一周期完全同序。haveSameSongIds 用 ID 计数而非顺序判断两个列表是否包含相同数量的各首歌曲。默认随机数由 getRandomInt 生成,调用方也可传入 randomInt 以控制随机过程。

Architecture

Loading diagram...

图示依据:请求所附源码第 1–78 行。运行时未提供文件引用基础 URL 与文件路径,故无法生成文件链接。

createNextShuffledCycle 调用 createShuffledList,显式传入 isPlayAll: true、avoidFirstSongId: currentSongId 和 randomInt(第 39–47 行)。haveSameSongIds 与排序函数之间没有可见的调用关系;图中将它单独连接至其内部的 Map,不暗示它参与下一周期生成(第 61–77 行)。

随机队列构造

复制与洗牌

createShuffledList(songList, { isPlayAll = false, currentSongId = null, currentSong = null, avoidFirstSongId = null, randomInt = getRandomInt } = {}) 首先执行 songList.slice();之后所有交换都作用于副本。循环从索引 0 递增到数组末尾,每次调用 randomInt(0, i),再交换索引 i 和返回位置的元素(第 5–19 行)。默认的 getRandomInt(min, max) 使用 Math.floor(Math.random() * (max - min + 1) + min),即按该表达式从含端点的区间取整数(第 1–3 行)。源码没有检查注入的 randomInt 是否返回有效索引;要保持交换行为,调用方须提供符合该调用约定的函数。

这段算法先复制再交换,使原始数组的元素位置不因这里的交换而改变;但它不是深拷贝,元素对象仍是原来的引用(第 12–19 行)。仅根据这段代码不能判断外围状态是否还会变动。

当前歌曲与首曲回避

当 isPlayAll 为假时,函数先按 String(song?.id ?? '') === String(currentSongId ?? '') 找到匹配的歌曲。如果 currentSong 为真值,则在找到匹配项时删除该项,再将提供的 currentSong 放到开头;如果没找到匹配项,仍会插入 currentSong(第 21–27 行)。这里删除的依据是 currentSongId,并未验证插入对象的 ID 与之相同,因此不能将此步骤理解为无条件去重。isPlayAll 为真则跳过整个置顶分支。

如果提供了非 null/undefined 的 avoidFirstSongId、数组长度大于 1,且首元素的字符串化 ID 等于该 ID,函数寻找第一个 ID 不同的元素并与首元素交换(第 29–34 行)。如果所有 ID 都相同,搜索结果为 -1;源码未显式处理该情况,不应宣称它总能避免连续同曲。

周期切换

createNextShuffledCycle(songList, previousShuffledList, { currentSongId = null, randomInt = getRandomInt } = {}) 生成全列表随机排列,并尝试避开当前歌曲作为首曲。它将非数组的 previousShuffledList 视为空数组;只有新周期长度大于 2 且逐位置字符串化 ID 全都与上一周期相等时,才交换新周期最后两个元素(第 39–59 行)。因此这个补救策略不是重新洗牌,也不适用于长度为 0、1 或 2 的周期。它比较的是 ID 顺序,而不是对象引用。

Loading diagram...

图示依据:请求所附源码第 29–59 行;图中的“存在不同 ID”是交换能找到有效目标的条件,而非源码执行的显式守卫。未提供可构造文件链接的运行时信息。

歌曲 ID 多重集合比较

haveSameSongIds(leftList, rightList) 对非数组输入或长度不等的输入返回 false。它遍历左侧列表,用 Map 记录每个 String(song?.id ?? '') 的出现次数;随后遍历右侧列表,遇到不存在或已经耗尽计数的 ID 就返回 false,否则减一。遍历结束返回 true(第 61–77 行)。因此它保留重复次数,却忽略顺序;例如列表中相同 ID 的两个不同对象在此比较中不可区分。null、undefined 或无 id 的元素在 ID 提取表达式中均变为字符串 '',会被统计到同一个键。

Loading diagram...

图示依据:请求所附源码第 61–77 行。文件路径和引用基础 URL 未提供,无法附上文件链接。

API Reference

导出函数可见参数及默认值返回及行为可见的错误处理
getRandomInt(min, max)min、max,无默认值使用 Math.random 计算整数;第 1–3 行未显式验证区间或捕获错误
createShuffledList(songList, options = {})isPlayAll = false、currentSongId = null、currentSong = null、avoidFirstSongId = null、randomInt = getRandomInt返回副本经交换及可选位置调整后的数组;第 5–37 行未显式验证 songList 或随机位置;调用 slice 依赖输入支持此方法
createNextShuffledCycle(songList, previousShuffledList, options = {})currentSongId = null、randomInt = getRandomInt返回新周期数组;第 39–59 行仅对 previousShuffledList 进行 Array.isArray 保护;其他输入无显式验证
haveSameSongIds(leftList, rightList)两个列表,无默认值返回布尔值;非数组或长度不同为 false;第 61–77 行对非数组输入以返回值处理,未显式抛出异常

这里的签名仅列出源码实际展示的 JavaScript 参数,不推断 TypeScript 类型、未列出的异常或外部调用约定。

Usage Examples

No code example available:虽然请求提供了函数实现文本,但没有对应的真实仓库文件路径和运行时 File Reference Base URL,无法为代码块提供规定的文件链接。可按上表及逐行说明理解函数;不应把未核实的调用代码当作仓库示例。

边界、性能与扩展

  • 空数组:洗牌循环不执行;createNextShuffledCycle 的重复周期补救条件不成立(第 12–19、49–56 行)。
  • 同 ID 歌曲:首曲回避查找的是不同 ID;上一周期重复检测比较 ID,因此同 ID 的不同对象不能提供区分依据(第 29–34、49–55 行)。
  • 复杂度:洗牌遍历数组并复制数组;haveSameSongIds 用 Map 和两次列表遍历。createShuffledList 在置顶及回避分支还会搜索数组;下一周期函数另外逐项比较旧顺序。这里没有缓存、锁、异步操作或持久化代码(第 5–77 行)。
  • 可测试性:randomInt 是实际可见的注入点,可用于控制洗牌所选索引;请求没有提供测试文件,因此不能声称特定场景已有测试覆盖(第 10、15、41、46 行)。
  • 音质:没有关于码率、格式、音源 URL、播放器实例、网络回退或配置默认值的源码。Implementation details not found in source;不要据此推断本项目支持或不支持某个音质等级。

当前没有提供可验证的相关文档路径或源码 URL。待仓库上下文可用时,应分别关联播放器生命周期、音质配置及播放列表状态管理的相应页面,而不是把这些未见实现并入本文。

Sources

(1 files)