Lyrics implementation prototype (#224)

* Lyrics implementation prototype

* feat: update lyrics view

* chore: add docs

* chore: cleanup

* feat: animate active text

* fix: hide lyrics button when there are none

* feat: create lyrics preview in now playing modal

* fix: header overlay color

Closes #224 
Closes #151 
Closes #100 

---------

Co-authored-by: Lei Nelissen <lei@codified.nl>
This commit is contained in:
Abubakr Khabebulloev
2024-07-25 20:07:23 +09:00
committed by GitHub
parent a64f52c4f9
commit c5b1406e16
22 changed files with 599 additions and 40 deletions

View File

@@ -1,5 +1,6 @@
import { Album, AlbumTrack, SimilarAlbum } from '@/store/music/types';
import { fetchApi } from './lib';
import {retrieveAndInjectLyricsToTracks} from '@/utility/JellyfinApi/lyrics.ts';
const albumOptions = {
SortBy: 'AlbumArtist,SortName',
@@ -39,7 +40,7 @@ const latestAlbumsOptions = {
};
/**
* Retrieve the most recently added albums on the Jellyfin server
* Retrieve the most recently added albums on the Jellyfin server
*/
export async function retrieveRecentAlbums(numberOfAlbums = 24) {
// Generate custom config based on function input
@@ -64,5 +65,5 @@ export async function retrieveAlbumTracks(ItemId: string) {
const singleAlbumParams = new URLSearchParams(singleAlbumOptions).toString();
return fetchApi<{ Items: AlbumTrack[] }>(({ user_id }) => `/Users/${user_id}/Items?${singleAlbumParams}`)
.then((data) => data!.Items);
}
.then((data) => retrieveAndInjectLyricsToTracks(data.Items));
}

View File

@@ -0,0 +1,48 @@
import { fetchApi } from './lib';
import {AlbumTrack} from '@/store/music/types.ts';
interface Metadata {
Artist: string
Album: string
Title: string
Author: string
Length: number
By: string
Offset: number
Creator: string
Version: string
IsSynced: boolean
}
interface LyricData {
Text: string
Start: number
}
export interface Lyrics {
Metadata: Metadata
Lyrics: LyricData[]
}
async function retrieveTrackLyrics(trackId: string): Promise<Lyrics | null> {
return fetchApi<Lyrics>(`/Audio/${trackId}/Lyrics`)
.catch((e) => {
console.error('Error on fetching track lyrics: ', e);
return null;
});
}
export async function retrieveAndInjectLyricsToTracks(tracks: AlbumTrack[]): Promise<AlbumTrack[]> {
return Promise.all(tracks.map(async (track) => {
if (!track.HasLyrics) {
track.Lyrics = null;
return track;
}
track.Lyrics = await retrieveTrackLyrics(track.Id);
return track;
}));
}

View File

@@ -1,5 +1,6 @@
import { AlbumTrack, Playlist } from '@/store/music/types';
import { asyncFetchStore, fetchApi } from './lib';
import {retrieveAndInjectLyricsToTracks} from '@/utility/JellyfinApi/lyrics.ts';
const playlistOptions = {
SortBy: 'SortName',
@@ -17,7 +18,7 @@ const playlistOptions = {
*/
export async function retrieveAllPlaylists() {
const playlistParams = new URLSearchParams(playlistOptions).toString();
return fetchApi<{ Items: Playlist[] }>(({ user_id }) => `/Users/${user_id}/Items?${playlistParams}`)
.then((d) => d!.Items);
}
@@ -34,5 +35,5 @@ export async function retrievePlaylistTracks(ItemId: string) {
const singlePlaylistParams = new URLSearchParams(singlePlaylistOptions).toString();
return fetchApi<{ Items: AlbumTrack[] }>(`/Playlists/${ItemId}/Items?${singlePlaylistParams}`)
.then((d) => d!.Items);
}
.then((d) => retrieveAndInjectLyricsToTracks(d.Items));
}

View File

@@ -3,6 +3,7 @@ import { Platform } from 'react-native';
import { Track } from 'react-native-track-player';
import { fetchApi, getImage } from './lib';
import store from '@/store';
import {retrieveAndInjectLyricsToTracks} from '@/utility/JellyfinApi/lyrics';
const trackOptionsOsOverrides: Record<typeof Platform.OS, Record<string, string>> = {
ios: {
@@ -60,6 +61,8 @@ export function generateTrack(track: AlbumTrack): Track {
artwork: track.AlbumId
? getImage(track.AlbumId)
: getImage(track.Id),
hasLyrics: track.HasLyrics,
lyrics: track.Lyrics,
};
}
@@ -77,5 +80,5 @@ const trackParams = {
*/
export async function retrieveAllTracks() {
return fetchApi<{ Items: AlbumTrack[] }>(({ user_id }) => `/Users/${user_id}/Items?${trackParams}`)
.then((d) => d!.Items);
.then((d) => retrieveAndInjectLyricsToTracks(d.Items));
}