Skip to content

fix: 修复歌单重复问题#247

Open
Xdyu1522 wants to merge 2 commits intoFerry-200:mainfrom
Xdyu1522:fix/playlist-duplicate-issue
Open

fix: 修复歌单重复问题#247
Xdyu1522 wants to merge 2 commits intoFerry-200:mainfrom
Xdyu1522:fix/playlist-duplicate-issue

Conversation

@Xdyu1522
Copy link
Copy Markdown

@Xdyu1522 Xdyu1522 commented Mar 8, 2026

问题描述

点击"确定"按钮重建索引后,原有的歌单会被复制一份,变成两个一样的歌单。

问题原因

readPlaylists()readLyricSources() 函数中,从文件读取数据时没有先清空全局变量(PLAYLISTSLYRIC_SOURCES),导致每次调用都会追加数据。

修复方案

在两个函数中添加 clear() 调用,在读取数据前先清空全局变量:

  • lib/library/playlist.dart: 在 readPlaylists() 中添加 PLAYLISTS.clear()
  • lib/lyric/lyric_source.dart: 在 readLyricSources() 中添加 LYRIC_SOURCES.clear()

测试

  • 修复后点击确定按钮不会重复歌单
  • 重建索引功能正常工作
  • 歌词来源数据不会重复

影响范围

  • other_settings.dart 点击确定按钮时
  • updating_page.dart 应用更新时

Releated #195

在 readPlaylists() 和 readLyricSources() 函数中添加 clear() 调用,
避免在重建索引时重复添加歌单和歌词来源数据。

修复问题:
- 点击确定按钮后歌单会被复制一份
- 重复调用读取函数导致数据累积

影响范围:
- other_settings.dart 点击确定按钮时
- updating_page.dart 应用更新时
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求旨在解决一个关键的数据重复问题,即在执行重建索引或应用更新操作时,歌单和歌词来源数据会被错误地复制。根本原因在于相关的数据加载函数在从文件读取数据时,没有预先清空存储数据的全局变量。通过引入简单的 clear() 调用,此修复确保了数据加载过程的幂等性,从而维护了数据的完整性和用户体验。

Highlights

  • 修复歌单重复问题: 解决了在重建索引或应用更新时,歌单和歌词来源数据会重复的问题。
  • 数据加载逻辑优化: 在 readPlaylists() 和 readLyricSources() 函数中,通过在读取数据前调用 clear() 方法,确保全局变量 PLAYLISTS 和 LYRIC_SOURCES 被清空,从而避免数据重复追加。

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • lib/library/playlist.dart
    • 在 readPlaylists() 函数中添加了 PLAYLISTS.clear() 调用,以防止歌单重复。
  • lib/lyric/lyric_source.dart
    • 在 readLyricSources() 函数中添加了 LYRIC_SOURCES.clear() 调用,以防止歌词来源数据重复。
Activity
  • 暂无人工活动。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

本次 PR 旨在修复重建索引时歌单和歌词源重复的问题。您通过在 readPlaylistsreadLyricSources 函数开头添加 .clear() 调用来解决此问题。

虽然这解决了重复的根本原因,但当前的实现方式(在 await 调用之前清空全局集合)可能会引入潜在的竞态条件或 UI 闪烁问题。当异步操作正在进行时,应用的其它部分可能会访问到被清空的集合,导致非预期的行为。

我在代码中留下了具体的审查评论,建议将数据加载到本地变量中,然后原子性地更新全局集合,以提高代码的健壮性。建议的重构方案中也包含了对路径处理的改进,以增强跨平台兼容性。请查看这些评论以获取更详细的建议。


Future<void> readPlaylists() async {
try {
PLAYLISTS.clear();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

await 调用之前清空列表(PLAYLISTS.clear())可能会导致UI闪烁或竞态条件。在异步操作(getAppDataDir())等待期间,应用程序的其他部分可能会看到一个空的播放列表。

为了避免这种情况,更安全的做法是先将数据加载到一个本地列表中,然后一次性地更新全局的 PLAYLISTS

建议重构如下(需要引入 package:path/path.dart as path):

Future<void> readPlaylists() async {
  try {
    final supportPath = (await getAppDataDir()).path;
    final playlistsPath = path.join(supportPath, "playlists.json");

    final playlistsStr = File(playlistsPath).readAsStringSync();
    final List playlistsJson = json.decode(playlistsStr);

    final newPlaylists = <Playlist>[];
    for (Map item in playlistsJson) {
      newPlaylists.add(Playlist.fromMap(item));
    }
    
    PLAYLISTS.clear();
    PLAYLISTS.addAll(newPlaylists);
  } catch (err, trace) {
    LOGGER.e(err, stackTrace: trace);
  }
}

这个修改会移除当前的 PLAYLISTS.clear(),并在数据准备好之后再更新列表。同时,使用 path.join 也能改善跨平台的兼容性。


Future<void> readLyricSources() async {
try {
LYRIC_SOURCES.clear();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

readPlaylists 函数中的问题类似,在 await 调用之前清空 LYRIC_SOURCES 可能会导致在异步操作期间数据状态不一致。

建议采用相同的模式:先将数据加载到本地的 Map 中,然后一次性更新全局的 LYRIC_SOURCES

建议重构如下(需要引入 package:path/path.dart as path):

Future<void> readLyricSources() async {
  try {
    final supportPath = (await getAppDataDir()).path;
    final lyricSourcePath = path.join(supportPath, "lyric_source.json");

    final lyricSourceStr = File(lyricSourcePath).readAsStringSync();
    final Map lyricSourceJson = json.decode(lyricSourceStr);

    final newLyricSources = <String, LyricSource>{};
    for (final item in lyricSourceJson.entries) {
      if (File(item.key).existsSync() == false) continue;
      newLyricSources[item.key] = LyricSource.fromMap(item.value);
    }
    
    LYRIC_SOURCES.clear();
    LYRIC_SOURCES.addAll(newLyricSources);
  } catch (err, trace) {
    LOGGER.e(err, stackTrace: trace);
  }
}

修改读取播放列表和歌词源的逻辑,先构建新集合再替换原集合,
避免在读取过程中直接操作全局变量可能导致的并发问题
Copy link
Copy Markdown
Author

@Xdyu1522 Xdyu1522 left a comment

Choose a reason for hiding this comment

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

感谢review!已根据建议优化数据加载逻辑。

修改内容:

  • 先加载数据到本地变量(newPlaylists / newLyricSources
  • 数据准备好后一次性更新全局变量(clear() + addAll()
  • 避免在异步等待期间出现空列表导致的UI闪烁

已应用到 readPlaylists()readLyricSources() 两个函数。

@Xdyu1522
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

本次 PR 修复了歌单和歌词来源重复的问题。通过创建新集合然后替换旧集合的方式来保证操作的原子性,这个方法是有效的。我提供了一些建议,可以让代码更简洁、更符合 Dart 的编程习惯。

Comment on lines +20 to 23
final newPlaylists = <Playlist>[];
for (Map item in playlistsJson) {
PLAYLISTS.add(Playlist.fromMap(item));
newPlaylists.add(Playlist.fromMap(item));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

为了使代码更简洁,您可以使用 maptoList 来代替 for 循环来创建 newPlaylists

Suggested change
final newPlaylists = <Playlist>[];
for (Map item in playlistsJson) {
PLAYLISTS.add(Playlist.fromMap(item));
newPlaylists.add(Playlist.fromMap(item));
}
final newPlaylists = playlistsJson.map((item) => Playlist.fromMap(item as Map)).toList();


final newLyricSources = <String, LyricSource>{};
for (final item in lyricSourceJson.entries) {
if (File(item.key).existsSync() == false) continue;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

为了提高代码的可读性,建议使用 ! 操作符进行布尔否定,而不是与 false 进行比较。

Suggested change
if (File(item.key).existsSync() == false) continue;
if (!File(item.key).existsSync()) continue;

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