-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(plugin): Skip Live Songs - Automatically skip most non-studio recordings #4093
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
925ef98
bee0523
7ab5bf3
63776bf
4e6256e
e1f559e
f63bb72
43992d7
10c4584
c60d715
0f9c16e
70e6ce1
e2c07fe
41f8334
473c942
548c536
dd350d4
16df9f3
0000964
445448b
36c3d09
2f02ace
5e58654
d6c4f78
e6a9339
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,90 @@ | ||||||||||||||||
| import { t } from '@/i18n'; | ||||||||||||||||
| import { createPlugin } from '@/utils'; | ||||||||||||||||
|
|
||||||||||||||||
| import type { SongInfo } from '@/providers/song-info'; | ||||||||||||||||
| import { nonStudioPatterns } from './patterns'; | ||||||||||||||||
amontariol marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
|
|
||||||||||||||||
| import type { SongInfo } from '@/providers/song-info'; | ||||||||||||||||
|
Comment on lines
+4
to
+7
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <importPlugin/no-duplicates> reported by reviewdog 🐶
Suggested change
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <importPlugin/no-duplicates> reported by reviewdog 🐶 |
||||||||||||||||
|
|
||||||||||||||||
| export default createPlugin({ | ||||||||||||||||
| name: () => t('plugins.skip-live-songs.name'), | ||||||||||||||||
| description: () => t('plugins.skip-live-songs.description'), | ||||||||||||||||
| restartNeeded: false, | ||||||||||||||||
| config: { | ||||||||||||||||
| enabled: false, | ||||||||||||||||
| }, | ||||||||||||||||
| renderer: { | ||||||||||||||||
| lastSkippedVideoId: '', | ||||||||||||||||
|
|
||||||||||||||||
| _skipLiveHandler: undefined as unknown as | ||||||||||||||||
| | ((songInfo: SongInfo) => void) | ||||||||||||||||
| | undefined, | ||||||||||||||||
|
|
||||||||||||||||
| start({ ipc }) { | ||||||||||||||||
| console.debug('[Skip Live Songs] Renderer started'); | ||||||||||||||||
|
|
||||||||||||||||
| const SELECTORS = [ | ||||||||||||||||
| 'yt-icon-button.next-button', | ||||||||||||||||
| '.next-button', | ||||||||||||||||
| 'button[aria-label*="Next"]', | ||||||||||||||||
| 'button[aria-label*="next"]', | ||||||||||||||||
| '#player-bar-next-button', | ||||||||||||||||
| 'ytmusic-player-bar .next-button', | ||||||||||||||||
| '.player-bar .next-button', | ||||||||||||||||
| ]; | ||||||||||||||||
|
|
||||||||||||||||
| const handler = (songInfo: SongInfo) => { | ||||||||||||||||
| const titleToCheck = songInfo.alternativeTitle || songInfo.title; | ||||||||||||||||
| if (!titleToCheck) return; | ||||||||||||||||
|
|
||||||||||||||||
| // Skip if we've already attempted this video id | ||||||||||||||||
| if (songInfo.videoId === this.lastSkippedVideoId) return; | ||||||||||||||||
|
|
||||||||||||||||
| const isNonStudio = nonStudioPatterns.some((pattern) => | ||||||||||||||||
| pattern.test(titleToCheck), | ||||||||||||||||
| ); | ||||||||||||||||
|
|
||||||||||||||||
| if (!isNonStudio) return; // studio version — nothing to do | ||||||||||||||||
|
|
||||||||||||||||
| // Mark as attempted so we don't loop repeatedly | ||||||||||||||||
| this.lastSkippedVideoId = songInfo.videoId; | ||||||||||||||||
| console.info( | ||||||||||||||||
| `[Skip Live Songs] Skipping non-studio song: "${titleToCheck}" (id: ${songInfo.videoId})`, | ||||||||||||||||
| ); | ||||||||||||||||
|
|
||||||||||||||||
| let clicked = false; | ||||||||||||||||
| for (const sel of SELECTORS) { | ||||||||||||||||
| const button = document.querySelector<HTMLElement>(sel); | ||||||||||||||||
| if (button) { | ||||||||||||||||
| button.click(); | ||||||||||||||||
| console.debug( | ||||||||||||||||
| `[Skip Live Songs] Clicked next button using selector: ${sel}`, | ||||||||||||||||
| ); | ||||||||||||||||
| clicked = true; | ||||||||||||||||
| break; | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if (!clicked) { | ||||||||||||||||
| console.warn( | ||||||||||||||||
| '[Skip Live Songs] Could not find next button with any configured selector', | ||||||||||||||||
| ); | ||||||||||||||||
| } | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| this._skipLiveHandler = handler; | ||||||||||||||||
| ipc.on('peard:update-song-info', handler); | ||||||||||||||||
| }, | ||||||||||||||||
|
|
||||||||||||||||
| // Unregister the ipc handler on plugin stop to avoid duplicate listeners on hot reload | ||||||||||||||||
| stop({ ipc }) { | ||||||||||||||||
| if (this._skipLiveHandler) { | ||||||||||||||||
| ipc.removeAllListeners('peard:update-song-info'); | ||||||||||||||||
| this._skipLiveHandler = undefined; | ||||||||||||||||
| console.debug( | ||||||||||||||||
| '[Skip Live Songs] Renderer stopped and listeners removed', | ||||||||||||||||
| ); | ||||||||||||||||
| } | ||||||||||||||||
| }, | ||||||||||||||||
| }, | ||||||||||||||||
| }); | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| /** | ||
| * Patterns to detect non-studio recordings | ||
| * | ||
| * Add or modify patterns here to customize what gets skipped. | ||
| * All patterns are not case-sensitive. | ||
| */ | ||
|
|
||
| export const nonStudioPatterns = [ | ||
| // "Live" in specific contexts (not as part of song title) | ||
| /[\(\[]live[\)\]]/i, // "(Live)" or "[Live]" in parentheses/brackets | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <no-useless-escape> reported by reviewdog 🐶
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <no-useless-escape> reported by reviewdog 🐶
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [eslint] <no-useless-escape> reported by reviewdog 🐶 |
||
| /live\s+(at|from|in|on|with|@)/i, // "Live at", "Live from", "Live in", etc. | ||
| /live\s+with\b/i, // "Live with" (e.g. "Live with the SFSO") | ||
| /-\s*live\s*$/i, // "- Live" at the end of title | ||
| /:\s*live\s*$/i, // ": Live" at the end of title | ||
| // Concert/Performance indicators | ||
| /\b(concert|festival|tour)\b/i, // Concert, Festival, Tour | ||
| /\(.*?(concert|live performance|live recording).*?(19|20)\d{2}\)/i, // (Live 1985), (Concert 2024) | ||
| // Recording types | ||
| /\b(acoustic|unplugged|rehearsal|demo)\b/i, // Acoustic, Unplugged, Rehearsal, Demo | ||
| // Venues | ||
| /\b(arena|stadium|center|centre|hall)\b/i, // Arena, Stadium, Center, Hall | ||
| /\bmadison\s+square\s+garden\b/i, // Madison Square Garden | ||
| /day\s+on\s+the\s+green/i, // Day on the Green | ||
| // Famous venues/festivals | ||
| /\b(wembley|glastonbury|woodstock|coachella)\b/i, // Wembley, Glastonbury, Woodstock, Coachella | ||
| // Dates and locations | ||
| /\b(january|february|march|april|may|june|july|august|september|october|november|december)\s+\d+/i, // "September 22", "August 31" | ||
| /\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b/, // Date formats: 09/22/2024, 9-22-24 | ||
| /\b[A-Z][a-z]+,\s*[A-Z]{2}\b/, // Locations: "Oakland, CA", "London, UK" | ||
| /\b[A-Z][a-z]+\s+City\b/i, // Cities: "Mexico City", "New York City" | ||
| /\b(tokyo|paris|berlin|sydney)\b/i, // More cities | ||
| /\b(bbc|radio|session)\b/i, // Radio sessions | ||
| ]; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.