Skip to content

refactor: decouple lyrics providers from synced-lyrics#4267

Draft
Yumeo0 wants to merge 3 commits intopear-devs:masterfrom
Yumeo0:lyrics-provider-feature
Draft

refactor: decouple lyrics providers from synced-lyrics#4267
Yumeo0 wants to merge 3 commits intopear-devs:masterfrom
Yumeo0:lyrics-provider-feature

Conversation

@Yumeo0
Copy link
Contributor

@Yumeo0 Yumeo0 commented Jan 24, 2026

This splits the actual lyric fetching from the lyrics displaying.

I thought it was logical to split out the lyrics-provider when I worked on the better-fullscreen plugin because fetching the lyrics multiple times seemed stupid. So I create the lyrics-provider plugin and a way for other plugins to depend on it.

This PR also rewrites the synced-lyrics plugin to use the new lyrics-provider.

github-actions[bot]

This comment was marked as spam.

@ArjixWasTaken
Copy link
Member

ArjixWasTaken commented Jan 27, 2026

I am converting this to a draft PR so annoying copilot won't pollute the chat.
I've noticed that you have not documented in the PR the changes you've made.

You introduced a dependency system between plugins, you detect circular dependencies, among other stuff.
Could you spend 30 minutes detailing your design choices, so we can discuss them?

Plus, if we are going to do a refactor of this scale, might as well implement a local lyrics database, to reduce our reliance on the lyrics providers being available. (and avoid rate-limits)

So discussing it first is the way to go

@ArjixWasTaken ArjixWasTaken marked this pull request as draft January 27, 2026 10:29
Comment on lines +21 to +27
(window as any).lyricsProvider = {
fetchLyrics,
currentLyrics,
lyricsStore,
setLyricsStore,
retrySearch,
};
Copy link
Member

Choose a reason for hiding this comment

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

I would be in favour of introducing a dependency injection container for such needs.
My personal favorite is di-wise

@ArjixWasTaken ArjixWasTaken self-assigned this Jan 27, 2026
@ArjixWasTaken ArjixWasTaken added the enhancement New feature or request label Jan 27, 2026
@ArjixWasTaken ArjixWasTaken changed the title Lyrics provider plugin refactor: decouple lyrics providers from synced-lyrics Jan 27, 2026
@Yumeo0
Copy link
Contributor Author

Yumeo0 commented Jan 27, 2026

Plus, if we are going to do a refactor of this scale, might as well implement a local lyrics database, to reduce our reliance on the lyrics providers being available. (and avoid rate-limits)

I'm gonna comment on everything else later but I just quickly wanted to say that this is absolutely out of scope for what this PR is supposed to do. I only copy pastes the code from synced-lyrics into the new plugin. I didn't change the underlying logic at all. If somebody wants to add a local lyrics database in a new PR they can feel free to do so.

@ArjixWasTaken
Copy link
Member

I'm gonna comment on everything else later but I just quickly wanted to say that this is absolutely out of scope for what this PR is supposed to do.

I may have been too ambiguous, by "database" I meant having a local .json file or smth that "caches" the lyrics across app restarts.

Currently we store them in memory, and only keep them cached for the lifetime of the session.

const searchCache = new Map<VideoId, SearchCache>();

@Yumeo0
Copy link
Contributor Author

Yumeo0 commented Jan 27, 2026

You introduced a dependency system between plugins, you detect circular dependencies, among other stuff. Could you spend 30 minutes detailing your design choices, so we can discuss them?

Topological Sort
I had to make sure that the dependencies load before the dependents so I implemented a depth-first topological sort with cycle detection that I found online.

const topologicalSort = (plugins) => {
  const visiting = new Set();  // Tracks current DFS path (cycle detection)
  const visited = new Set();   // Tracks fully processed nodes
  // ...
}

The visiting set detects circular dependencies—if a node is encountered while still in the current DFS path, it's a cycle. This prevents infinite loops and warns the developer.

Global API exposure via window
I just put the API object onto the window as I thought this was a simple enough use-case seeing as the dependencies always load before the dependents which means it is always available. I can look into dependency injectors though.

Providing the lyrics
I just used a simple solid store to create a reactive store which other plugins can consume. Should be pretty self explanatory why it is that way.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants