Skip to content

feat:增加播客插件#20

Open
ieshishinjin wants to merge 3 commits into
SeaLantern-Studio:mainfrom
ieshishinjin:main
Open

feat:增加播客插件#20
ieshishinjin wants to merge 3 commits into
SeaLantern-Studio:mainfrom
ieshishinjin:main

Conversation

@ieshishinjin

@ieshishinjin ieshishinjin commented Jun 14, 2026

Copy link
Copy Markdown
截屏2026-06-14 22 26 27 截屏2026-06-14 22 29 02

Summary by Sourcery

添加一个新的播客订阅和播放插件,包含持久化的底部播放器 UI、RSS 解析以及侧边栏集成。

New Features:

  • 引入一个播客阅读器插件,用于订阅 RSS 源,获取并解析播客元数据和节目,并在专用界面中展示。
  • 添加一个持久化的底部音频播放器栏,提供节目信息、进度拖动控制、播放速度调整以及上一集/下一集导航。
  • 在侧边栏中提供入口和页面,用于管理播客订阅,包括查看节目、标记为已收听,以及刷新订阅源以获取新内容。

Enhancements:

  • 使用存储持久化播客订阅、节目以及收听状态,使播放状态和播客库在会话之间得以保留。
  • 当播客阅读器 UI 激活时隐藏默认插件页面的外框,以呈现类似应用的体验。

Documentation:

  • 在插件清单中描述新的播客阅读器插件,包括元数据、权限以及面向用户的描述。
Original summary in English

Summary by Sourcery

Add a new podcast subscription and playback plugin with persistent bottom player UI, RSS parsing, and sidebar integration.

New Features:

  • Introduce a podcast reader plugin that subscribes to RSS feeds, fetches and parses podcast metadata and episodes, and displays them in a dedicated UI.
  • Add a persistent bottom audio player bar with episode info, seek controls, playback speed adjustment, and previous/next episode navigation.
  • Provide a sidebar entry and page for managing podcast subscriptions, including viewing episodes, marking them as played, and refreshing feeds for new content.

Enhancements:

  • Persist podcast subscriptions, episodes, and listened state using storage so playback state and library are retained across sessions.
  • Hide the default plugin page chrome when the podcast reader UI is active to present an app-like experience.

Documentation:

  • Describe the new podcast reader plugin in its manifest with metadata, permissions, and a user-facing description.

@sourcery-ai

sourcery-ai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Reviewer's Guide

添加一个新的“播客订阅器”(podcast reader)插件,包含独立的 Lua 实现、UI 资源和 manifest,其中包括底部持久音频播放器栏、RSS 解析、订阅管理,以及与宿主应用插件框架的集成。

File-Level Changes

Change Details Files
引入一个功能完整的播客订阅插件,支持 RSS 解析、订阅管理和与宿主 UI 集成的剧集播放。
  • 实现核心 Lua 插件逻辑,用于解析 RSS XML 订阅源,规范化日期和时长,并映射到内部的播客和剧集结构中。
  • 使用宿主存储 API 为播客、剧集及已收听状态添加持久化存储,包含加载/保存辅助函数以及兼容迁移的深拷贝。
  • 接入插件生命周期钩子(onLoad/onEnable/onDisable/onUnload/onPageChanged),用于注入/移除自定义 UI、记录状态日志以及处理页面内命令。
  • 定义命令处理逻辑,以支持添加/移除/刷新订阅、选择播客/剧集、上一集/下一集导航,以及将剧集标记为已播放。
  • 注入核心 HTML/JS 音频控制器(底部播放器栏),并使用类 URL 路径的轻量级 IPC 机制在页面内 JS 与 Lua 之间通信。
  • 为插件主视图生成动态 HTML:欢迎状态、播客网格、包含作者/描述的播客详情、带播放按钮的剧集列表,以及添加播客对话框。
  • 使全局播放器 UI 与当前选中剧集保持同步,包括封面、标题、时长以及音频源切换,同时遵循 show_player 设置。
  • 在插件启用/禁用或页面变更时隐藏默认插件页面外框,并清理重复 UI。
plugins/ieshishinjin/podcast-reader/main.lua
为播客订阅器视图和底部播放器栏添加样式与布局。
  • 定义固定底部播放栏的样式,包括响应式行为、进度条、倍速按钮和播放控制。
  • 为主播客阅读器布局设置样式:页眉、欢迎界面、带封面与徽标的播客网格卡片,以及具有悬停/播放状态的剧集列表行。
  • 为插件页面中的内嵌播放器添加样式,包括剧集信息、控制按钮和进度条。
  • 为添加新播客 RSS 订阅源的表单和对话框,以及空状态提示信息实现样式。
  • 为小屏幕和无动画偏好等无障碍场景提供响应式微调和减弱动效支持。
  • 为播客/剧集描述和元信息添加排版与布局样式。
plugins/ieshishinjin/podcast-reader/style.css
在宿主应用中注册新的播客订阅器插件。
  • 创建 manifest,描述插件的 id、名称、版本、描述、权限、主入口脚本、图标以及侧边栏集成元数据。
  • 暴露一个可配置设置,用于在保持播放进行的前提下显示/隐藏底部播放栏。
  • 将插件接入侧边栏,并使用耳机图标及指定优先级进行展示。
plugins/ieshishinjin/podcast-reader/manifest.json
plugins/ieshishinjin/podcast-reader/podcast-reader.json
api/plugins.json

Tips and commands

Interacting with Sourcery

  • 触发新的代码审查: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在审查评论下回复,请求 Sourcery 从该评论创建 issue。你也可以直接回复 @sourcery-ai issue 来从该评论创建 issue。
  • 生成 pull request 标题: 在 pull request 标题中任意位置写入 @sourcery-ai 即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 概要: 在 pull request 正文任意位置写入 @sourcery-ai summary,即可在指定位置生成 PR 概要。你也可以在 pull request 中评论 @sourcery-ai summary 来(重新)生成概要。
  • 生成 Reviewer's Guide: 在 pull request 中评论 @sourcery-ai guide,即可随时(重新)生成审查指南。
  • 批量解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,即可将所有 Sourcery 评论标记为已解决。适用于你已经处理完所有评论且不希望再看到它们的情况。
  • 批量忽略所有 Sourcery 审查: 在 pull request 中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。特别适用于你想从全新的审查开始——别忘了再评论 @sourcery-ai review 触发一次新的审查!

Customizing Your Experience

前往你的 dashboard 以:

  • 启用或禁用审查功能,例如 Sourcery 生成的 pull request 概要、审查指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查指令。
  • 调整其他审查相关设置。

Getting Help

Original review guide in English

Reviewer's Guide

Adds a new '播客订阅器' (podcast reader) plugin with its own Lua implementation, UI assets, and manifest, including a bottom persistent audio player bar, RSS parsing, subscription management, and integration with the host app’s plugin framework.

File-Level Changes

Change Details Files
Introduce a full-featured podcast reader plugin with RSS parsing, subscription management, and episode playback integrated into the host UI.
  • Implement main Lua plugin logic to parse RSS XML feeds, normalize dates and durations, and map them into internal podcast and episode structures.
  • Add persistent storage for podcasts, episodes, and heard status using the host storage API, with load/save helpers and migration-safe deep copies.
  • Wire plugin lifecycle hooks (onLoad/onEnable/onDisable/onUnload/onPageChanged) to inject/remove custom UI, log state, and handle in-page commands.
  • Define command handling to support adding/removing/refreshing subscriptions, selecting podcasts/episodes, navigating prev/next, and marking episodes as played.
  • Inject a core HTML/JS audio controller (bottom player bar) and use a lightweight IPC mechanism via URL-like paths to communicate between in-page JS and Lua.
  • Generate dynamic HTML for the plugin main view: welcome state, podcast grid, podcast detail with author/description, episode list with play buttons, and add-podcast dialog.
  • Keep the global player UI in sync with the selected episode, including artwork, titles, durations, and audio source switching, while respecting the show_player setting.
  • Hide default plugin-page chrome and clean up duplicated UI when the plugin is enabled/disabled or the page changes.
plugins/ieshishinjin/podcast-reader/main.lua
Add styling and layout for the podcast reader views and bottom player bar.
  • Define styles for the fixed bottom playback bar, including responsive behavior, seek bar, speed button, and playback controls.
  • Style the main podcast reader layout: header, welcome screen, podcast grid cards with artwork and badges, and episode list rows with hover/playing states.
  • Add styles for the embedded player inside the plugin page, including episode information, controls, and seek bar.
  • Implement form and dialog styles for adding new podcast RSS feeds and for empty states messaging.
  • Provide responsive tweaks and reduced-motion accommodations for smaller screens and accessibility.
  • Add typography and layout styles for podcast/episode descriptions and meta information.
plugins/ieshishinjin/podcast-reader/style.css
Register the new podcast reader plugin with the host application.
  • Create a manifest describing the plugin’s id, name, version, description, permissions, main entry script, icon, and sidebar integration metadata.
  • Expose a configurable setting to show/hide the bottom playback bar while keeping playback running.
  • Wire the plugin to appear in the sidebar with a headphones icon and defined priority.
plugins/ieshishinjin/podcast-reader/manifest.json
plugins/ieshishinjin/podcast-reader/podcast-reader.json
api/plugins.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 3 个问题,并留下了一些整体性的反馈:

  • main.lua 中,很多辅助和领域函数(addPodcastremovePodcastfetchPodrenderUI 等)在声明时没有使用 local,这会污染全局命名空间;建议将它们标记为 local,或者显式挂载到 plugin 表上,以避免与其他插件发生命名冲突。
  • 注入的 JS 里 alignPlayer 的逻辑除了通过 resize 监听器外,还使用 setInterval(..., 200) 轮询;这种高频轮询在较慢的机器上代价较高,可以考虑改用 ResizeObserver,或者只依赖 resize/布局事件来更新播放器位置。
  • podcast-reader.json 文件已创建但内容为空;如果不会使用,建议删除,否则应填入预期的配置以免造成困惑。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `main.lua` many helper and domain functions (`addPodcast`, `removePodcast`, `fetchPod`, `renderUI`, etc.) are declared without `local`, which pollutes the global namespace; consider marking them `local` or attaching them explicitly to the `plugin` table to avoid collisions with other plugins.
- The `alignPlayer` logic in the injected JS runs via `setInterval(..., 200)` in addition to a `resize` listener; this frequent polling can be costly on slower machines and could be replaced with a `ResizeObserver` or relying solely on `resize`/layout events to update the player position.
- The `podcast-reader.json` file is created but empty; if it is not used, it should be removed, or otherwise populated with the intended configuration to avoid confusion.

## Individual Comments

### Comment 1
<location path="plugins/ieshishinjin/podcast-reader/main.lua" line_range="190-197" />
<code_context>
+-- ============================================================
+-- 播客管理
+-- ============================================================
+function addPodcast(url)
+  url = trim(url)
+  if not url or #url == 0 then return false, "请输入地址" end
+  if not url:match("^https?://") then return false, "请输入有效地址" end
+  for _, p in ipairs(state.podcasts) do if p.url == url then return false, "已添加过" end end
+  local pod = {id = mkId(url), url = url, title = url, author = "", artwork = "", desc = ""}
+  table.insert(state.podcasts, pod); saveAll()
+  local ok, msg = fetchPod(pod)
+  return true, ok and "已添加" or "添加失败: " .. tostring(msg)
+end
</code_context>
<issue_to_address>
**issue (bug_risk):** Consider reverting the newly inserted podcast if RSS fetching/parsing fails

Because `addPodcast` inserts and saves `pod` before `fetchPod` completes, a failed fetch still returns `true` and leaves a permanently broken entry in `state.podcasts` (and storage). Consider either deferring insertion/saving until after a successful `fetchPod`, or removing/invalidating the newly added `pod` on failure so persisted state and UI only reflect valid podcasts.
</issue_to_address>

### Comment 2
<location path="plugins/ieshishinjin/podcast-reader/main.lua" line_range="106" />
<code_context>
+    else
+      local ce = xml:find(">", ts); if not ce then break end
+      local tc = xml:sub(ts + 1, ce - 1)
+      if tc:match("^%s*$") then i = ce + 1; break end
+      local sc = tc:sub(-1) == "/"
+      if sc then tc = tc:sub(1, -2) end
</code_context>
<issue_to_address>
**issue (bug_risk):** Whitespace-only tag names cause the XML parser to stop parsing early

In `parseXml`, when `tc:match("^%s*$")` is true you currently set `i = ce + 1` and `break` out of the loop. That means a single whitespace-only tag candidate (e.g. from malformed `< >` content) stops parsing and silently drops all remaining XML, which can hide feeds/episodes.

Instead, advance `i` and continue parsing (e.g. restructure the loop or use a `goto` to skip to the next `<`), or simply treat this as a no-op and move on to the next tag, so that one bad segment doesn’t abort the whole parse.
</issue_to_address>

### Comment 3
<location path="plugins/ieshishinjin/podcast-reader/main.lua" line_range="386-395" />
<code_context>
+setInterval(function(){
</code_context>
<issue_to_address>
**suggestion (performance):** Two 200ms polling intervals in the core script may be unnecessarily aggressive

The core script runs two `setInterval` loops at 200ms: one for the seek UI and one repeatedly calling `alignPlayer`. On slower machines or layout-heavy pages, this polling—especially for alignment—can be more frequent than necessary.

Consider keeping 200ms for the seek UI, but lowering the `alignPlayer` interval (e.g., 500–1000ms) or triggering it via `resize` events and a `MutationObserver` on the sidebar instead. This should reduce layout work while keeping the bar in sync.

Suggested implementation:

```
setInterval(function(){
alignPlayer();
},800);

```

` section.

Here are the edits:

<file_operations>
<file_operation operation="edit" file_path="plugins/ieshishinjin/podcast-reader/main.lua">
<<<<<<< SEARCH
setInterval(function(){
alignPlayer();
},200);
=======
setInterval(function(){
alignPlayer();
},800);
>>>>>>> REPLACE
</file_operation>
</file_operations>

<additional_changes>
To fully align with your suggestion of using `resize` events and a `MutationObserver` instead of frequent polling, you will likely want to:

1. Identify the container/sidebar element whose layout changes necessitate realignment (e.g., an element with an id like `pr-sidebar` or similar).
2. Add a `window.addEventListener("resize", function(){ alignPlayer(); });` listener near the `alignPlayer` definition.
3. Instantiate a `MutationObserver` on the sidebar element that calls `alignPlayer()` on relevant DOM mutations (attribute changes, child list changes, subtree changes).
4. Once you are satisfied that `alignPlayer` is kept in sync by these event-based triggers, you can consider removing the `setInterval` entirely or further increasing its interval as a safety net.

These changes require knowledge of the actual DOM structure and naming of elements in the rest of the file, so you will need to adapt the event/observer wiring to match your existing IDs/classes.
</issue_to_address>

Sourcery 是对开源项目免费的——如果你觉得这些 Review 有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的 Review。
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • In main.lua many helper and domain functions (addPodcast, removePodcast, fetchPod, renderUI, etc.) are declared without local, which pollutes the global namespace; consider marking them local or attaching them explicitly to the plugin table to avoid collisions with other plugins.
  • The alignPlayer logic in the injected JS runs via setInterval(..., 200) in addition to a resize listener; this frequent polling can be costly on slower machines and could be replaced with a ResizeObserver or relying solely on resize/layout events to update the player position.
  • The podcast-reader.json file is created but empty; if it is not used, it should be removed, or otherwise populated with the intended configuration to avoid confusion.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `main.lua` many helper and domain functions (`addPodcast`, `removePodcast`, `fetchPod`, `renderUI`, etc.) are declared without `local`, which pollutes the global namespace; consider marking them `local` or attaching them explicitly to the `plugin` table to avoid collisions with other plugins.
- The `alignPlayer` logic in the injected JS runs via `setInterval(..., 200)` in addition to a `resize` listener; this frequent polling can be costly on slower machines and could be replaced with a `ResizeObserver` or relying solely on `resize`/layout events to update the player position.
- The `podcast-reader.json` file is created but empty; if it is not used, it should be removed, or otherwise populated with the intended configuration to avoid confusion.

## Individual Comments

### Comment 1
<location path="plugins/ieshishinjin/podcast-reader/main.lua" line_range="190-197" />
<code_context>
+-- ============================================================
+-- 播客管理
+-- ============================================================
+function addPodcast(url)
+  url = trim(url)
+  if not url or #url == 0 then return false, "请输入地址" end
+  if not url:match("^https?://") then return false, "请输入有效地址" end
+  for _, p in ipairs(state.podcasts) do if p.url == url then return false, "已添加过" end end
+  local pod = {id = mkId(url), url = url, title = url, author = "", artwork = "", desc = ""}
+  table.insert(state.podcasts, pod); saveAll()
+  local ok, msg = fetchPod(pod)
+  return true, ok and "已添加" or "添加失败: " .. tostring(msg)
+end
</code_context>
<issue_to_address>
**issue (bug_risk):** Consider reverting the newly inserted podcast if RSS fetching/parsing fails

Because `addPodcast` inserts and saves `pod` before `fetchPod` completes, a failed fetch still returns `true` and leaves a permanently broken entry in `state.podcasts` (and storage). Consider either deferring insertion/saving until after a successful `fetchPod`, or removing/invalidating the newly added `pod` on failure so persisted state and UI only reflect valid podcasts.
</issue_to_address>

### Comment 2
<location path="plugins/ieshishinjin/podcast-reader/main.lua" line_range="106" />
<code_context>
+    else
+      local ce = xml:find(">", ts); if not ce then break end
+      local tc = xml:sub(ts + 1, ce - 1)
+      if tc:match("^%s*$") then i = ce + 1; break end
+      local sc = tc:sub(-1) == "/"
+      if sc then tc = tc:sub(1, -2) end
</code_context>
<issue_to_address>
**issue (bug_risk):** Whitespace-only tag names cause the XML parser to stop parsing early

In `parseXml`, when `tc:match("^%s*$")` is true you currently set `i = ce + 1` and `break` out of the loop. That means a single whitespace-only tag candidate (e.g. from malformed `< >` content) stops parsing and silently drops all remaining XML, which can hide feeds/episodes.

Instead, advance `i` and continue parsing (e.g. restructure the loop or use a `goto` to skip to the next `<`), or simply treat this as a no-op and move on to the next tag, so that one bad segment doesn’t abort the whole parse.
</issue_to_address>

### Comment 3
<location path="plugins/ieshishinjin/podcast-reader/main.lua" line_range="386-395" />
<code_context>
+setInterval(function(){
</code_context>
<issue_to_address>
**suggestion (performance):** Two 200ms polling intervals in the core script may be unnecessarily aggressive

The core script runs two `setInterval` loops at 200ms: one for the seek UI and one repeatedly calling `alignPlayer`. On slower machines or layout-heavy pages, this polling—especially for alignment—can be more frequent than necessary.

Consider keeping 200ms for the seek UI, but lowering the `alignPlayer` interval (e.g., 500–1000ms) or triggering it via `resize` events and a `MutationObserver` on the sidebar instead. This should reduce layout work while keeping the bar in sync.

Suggested implementation:

```
setInterval(function(){
alignPlayer();
},800);

```

` section.

Here are the edits:

<file_operations>
<file_operation operation="edit" file_path="plugins/ieshishinjin/podcast-reader/main.lua">
<<<<<<< SEARCH
setInterval(function(){
alignPlayer();
},200);
=======
setInterval(function(){
alignPlayer();
},800);
>>>>>>> REPLACE
</file_operation>
</file_operations>

<additional_changes>
To fully align with your suggestion of using `resize` events and a `MutationObserver` instead of frequent polling, you will likely want to:

1. Identify the container/sidebar element whose layout changes necessitate realignment (e.g., an element with an id like `pr-sidebar` or similar).
2. Add a `window.addEventListener("resize", function(){ alignPlayer(); });` listener near the `alignPlayer` definition.
3. Instantiate a `MutationObserver` on the sidebar element that calls `alignPlayer()` on relevant DOM mutations (attribute changes, child list changes, subtree changes).
4. Once you are satisfied that `alignPlayer` is kept in sync by these event-based triggers, you can consider removing the `setInterval` entirely or further increasing its interval as a safety net.

These changes require knowledge of the actual DOM structure and naming of elements in the rest of the file, so you will need to adapt the event/observer wiring to match your existing IDs/classes.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +190 to +197
function addPodcast(url)
url = trim(url)
if not url or #url == 0 then return false, "请输入地址" end
if not url:match("^https?://") then return false, "请输入有效地址" end
for _, p in ipairs(state.podcasts) do if p.url == url then return false, "已添加过" end end
local pod = {id = mkId(url), url = url, title = url, author = "", artwork = "", desc = ""}
table.insert(state.podcasts, pod); saveAll()
local ok, msg = fetchPod(pod)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 如果 RSS 获取/解析失败,建议回滚新插入的播客

由于 addPodcastfetchPod 完成之前就插入并保存了 pod,当抓取失败时仍然会返回 true,并在 state.podcasts(以及存储)中留下一个永久损坏的条目。建议要么等 fetchPod 成功后再插入/保存,要么在失败时移除/失效刚添加的 pod,从而确保持久化状态和 UI 中只反映有效的播客。

Original comment in English

issue (bug_risk): Consider reverting the newly inserted podcast if RSS fetching/parsing fails

Because addPodcast inserts and saves pod before fetchPod completes, a failed fetch still returns true and leaves a permanently broken entry in state.podcasts (and storage). Consider either deferring insertion/saving until after a successful fetchPod, or removing/invalidating the newly added pod on failure so persisted state and UI only reflect valid podcasts.

else
local ce = xml:find(">", ts); if not ce then break end
local tc = xml:sub(ts + 1, ce - 1)
if tc:match("^%s*$") then i = ce + 1; break end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 仅包含空白的标签名会导致 XML 解析器过早停止解析

parseXml 中,当 tc:match("^%s*$") 为真时,你当前会设置 i = ce + 1break 跳出循环。这意味着只要出现一个仅包含空白的标签候选(例如由格式错误的 < > 内容导致),解析就会停止,并静默丢弃后续所有 XML,从而隐藏后面的订阅源/节目。

更好的做法是:前进 i 并继续解析(例如重构循环或使用 goto 跳到下一个 <),或者简单地将其视为 no-op 并移到下一个标签,这样单个坏片段就不会导致整个解析过程被中止。

Original comment in English

issue (bug_risk): Whitespace-only tag names cause the XML parser to stop parsing early

In parseXml, when tc:match("^%s*$") is true you currently set i = ce + 1 and break out of the loop. That means a single whitespace-only tag candidate (e.g. from malformed < > content) stops parsing and silently drops all remaining XML, which can hide feeds/episodes.

Instead, advance i and continue parsing (e.g. restructure the loop or use a goto to skip to the next <), or simply treat this as a no-op and move on to the next tag, so that one bad segment doesn’t abort the whole parse.

Comment thread plugins/ieshishinjin/podcast-reader/main.lua
@ieshishinjin

Copy link
Copy Markdown
Author

🫪

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant