mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-10 10:11:46 +00:00
feat(Synced-Lyrics): Also search for lyrics with the original title language (#3206)
* Add tags array for song info * Implement original title and original artist search for LRCBLib * comment cleanup * Check if microformat.tags is an array
This commit is contained in:
@ -11,10 +11,13 @@ export class LRCLib implements LyricProvider {
|
||||
|
||||
async search({
|
||||
title,
|
||||
alternativeTitle,
|
||||
artist,
|
||||
album,
|
||||
songDuration,
|
||||
tags,
|
||||
}: SearchSongInfo): Promise<LyricResult | null> {
|
||||
|
||||
let query = new URLSearchParams({
|
||||
artist_name: artist,
|
||||
track_name: title,
|
||||
@ -42,7 +45,9 @@ export class LRCLib implements LyricProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
query = new URLSearchParams({ q: title });
|
||||
// Try to search with the alternative title (original language)
|
||||
const trackName = alternativeTitle || title;
|
||||
query = new URLSearchParams({ q: `${trackName}` });
|
||||
url = `${this.baseUrl}/api/search?${query.toString()}`;
|
||||
|
||||
response = await fetch(url);
|
||||
@ -54,6 +59,22 @@ export class LRCLib implements LyricProvider {
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error(`Expected an array, instead got ${typeof data}`);
|
||||
}
|
||||
|
||||
// If still no results, try with the original title as fallback
|
||||
if (data.length === 0 && alternativeTitle) {
|
||||
query = new URLSearchParams({ q: title });
|
||||
url = `${this.baseUrl}/api/search?${query.toString()}`;
|
||||
|
||||
response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`bad HTTPStatus(${response.statusText})`);
|
||||
}
|
||||
|
||||
data = (await response.json()) as LRCLIBSearchResponse;
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error(`Expected an array, instead got ${typeof data}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const filteredResults = [];
|
||||
@ -63,6 +84,7 @@ export class LRCLib implements LyricProvider {
|
||||
const artists = artist.split(/[&,]/g).map((i) => i.trim());
|
||||
const itemArtists = artistName.split(/[&,]/g).map((i) => i.trim());
|
||||
|
||||
// Try to match using artist name first
|
||||
const permutations = [];
|
||||
for (const artistA of artists) {
|
||||
for (const artistB of itemArtists) {
|
||||
@ -76,10 +98,40 @@ export class LRCLib implements LyricProvider {
|
||||
}
|
||||
}
|
||||
|
||||
const ratio = Math.max(
|
||||
let ratio = Math.max(
|
||||
...permutations.map(([x, y]) => jaroWinkler(x, y)),
|
||||
);
|
||||
|
||||
// If direct artist match is below threshold and we have tags, try matching with tags
|
||||
if (ratio <= 0.9 && tags && tags.length > 0) {
|
||||
// Filter out the artist from tags to avoid duplicate comparisons
|
||||
const filteredTags = tags.filter(tag => tag.toLowerCase() !== artist.toLowerCase());
|
||||
|
||||
const tagPermutations = [];
|
||||
// Compare each tag with each item artist
|
||||
for (const tag of filteredTags) {
|
||||
for (const itemArtist of itemArtists) {
|
||||
tagPermutations.push([tag.toLowerCase(), itemArtist.toLowerCase()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Compare each item artist with each tag
|
||||
for (const itemArtist of itemArtists) {
|
||||
for (const tag of filteredTags) {
|
||||
tagPermutations.push([itemArtist.toLowerCase(), tag.toLowerCase()]);
|
||||
}
|
||||
}
|
||||
|
||||
if (tagPermutations.length > 0) {
|
||||
const tagRatio = Math.max(
|
||||
...tagPermutations.map(([x, y]) => jaroWinkler(x, y)),
|
||||
);
|
||||
|
||||
// Use the best match ratio between direct artist match and tag match
|
||||
ratio = Math.max(ratio, tagRatio);
|
||||
}
|
||||
}
|
||||
|
||||
if (ratio <= 0.9) continue;
|
||||
filteredResults.push(item);
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ export interface LyricResult {
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export type SearchSongInfo = Pick<SongInfo, 'title' | 'artist' | 'album' | 'songDuration' | 'videoId'>;
|
||||
export type SearchSongInfo = Pick<SongInfo, 'title' | 'alternativeTitle' | 'artist' | 'album' | 'songDuration' | 'videoId' | 'tags'>;
|
||||
|
||||
export interface LyricProvider {
|
||||
name: string;
|
||||
|
||||
@ -42,6 +42,7 @@ export interface SongInfo {
|
||||
videoId: string;
|
||||
playlistId?: string;
|
||||
mediaType: MediaType;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
// Grab the native image using the src
|
||||
@ -83,6 +84,7 @@ const handleData = async (
|
||||
videoId: '',
|
||||
playlistId: '',
|
||||
mediaType: MediaType.Audio,
|
||||
tags: [],
|
||||
} satisfies SongInfo;
|
||||
|
||||
const microformat = data.microformat?.microformatDataRenderer;
|
||||
@ -96,6 +98,7 @@ const handleData = async (
|
||||
songInfo.alternativeTitle = microformat.linkAlternates.find(
|
||||
(link) => link.title,
|
||||
)?.title;
|
||||
songInfo.tags = Array.isArray(microformat.tags) ? microformat.tags : [];
|
||||
}
|
||||
|
||||
const { videoDetails } = data;
|
||||
|
||||
Reference in New Issue
Block a user