Skip to content

Commit e315c45

Browse files
committed
feat(lyrics): add search lyrics by id
- resolve #726
1 parent 6fd71bf commit e315c45

File tree

8 files changed

+158
-91
lines changed

8 files changed

+158
-91
lines changed

common/intl/translations/de.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
"lyrics.delay.slowly": "Slowly",
3333
"lyrics.delay.default": "Default",
3434
"lyrics.delay.fastly": "Fastly",
35+
"lyrics.search-mode.default": "Default Search",
36+
"lyrics.search-mode.id": "ID Search",
37+
"lyrics.id": "ID",
3538

3639
"setting.title.position": "Position",
3740
"setting.title.view": "View",

common/intl/translations/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
"lyrics.delay.slowly": "Slowly",
3737
"lyrics.delay.default": "Default",
3838
"lyrics.delay.fastly": "Fastly",
39+
"lyrics.search-mode.default": "Default Search",
40+
"lyrics.search-mode.id": "ID Search",
41+
"lyrics.id": "ID",
3942

4043
"setting.title.position": "position",
4144
"setting.title.view": "View",

common/intl/translations/ja.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
"lyrics.delay.slowly": "Slowly",
3333
"lyrics.delay.default": "Default",
3434
"lyrics.delay.fastly": "Fastly",
35+
"lyrics.search-mode.default": "Default Search",
36+
"lyrics.search-mode.id": "ID Search",
37+
"lyrics.id": "ID",
3538

3639
"setting.title.position": "位置",
3740
"setting.title.view": "View",

common/intl/translations/ko.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
"lyrics.delay.slowly": "천천히",
3737
"lyrics.delay.default": "보통",
3838
"lyrics.delay.fastly": "빠르게",
39+
"lyrics.search-mode.default": "기본 검색",
40+
"lyrics.search-mode.id": "아이디 검색",
41+
"lyrics.id": "아이디",
3942

4043
"setting.title.position": "위치",
4144
"setting.title.view": "",

common/plugins/event.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ export interface OverrideParameterMap {
6464

6565
/* renderer */
6666
'search-lyrics': [
67+
mode: 'default' | 'id',
6768
artist: string,
6869
title: string,
70+
id: string,
6971
options?: {
7072
playtime?: number;
7173
page?: number;

renderer/components/PlayingInfoProvider.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ const PlayingInfoProvider = (props: { children: JSX.Element }) => {
111111
let metadata: LyricMetadata[] = [];
112112
await usePluginOverride(
113113
'search-lyrics',
114-
async (artist, title, options) => {
114+
async (_, artist, title, __, options) => {
115115
metadata = await lyricProvider
116116
.searchLyrics({
117117
artist,
@@ -120,8 +120,10 @@ const PlayingInfoProvider = (props: { children: JSX.Element }) => {
120120
})
121121
.catch(() => []);
122122
},
123+
'default',
123124
artist,
124125
title,
126+
'',
125127
{ playtime: data.data.duration },
126128
);
127129

renderer/lyrics/App.tsx

Lines changed: 122 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import {
22
createEffect,
33
createSignal,
44
For,
5+
Match,
56
on,
67
onCleanup,
78
Show,
89
startTransition,
10+
Switch,
911
} from 'solid-js';
1012
import {
1113
Trans,
@@ -14,8 +16,6 @@ import {
1416
} from '@jellybrick/solid-i18next';
1517
import { Marquee } from '@suyongs/solid-utility';
1618

17-
import alsong from 'alsong';
18-
1919
import SideBar from './SideBar';
2020

2121
import Card from '../components/Card';
@@ -34,21 +34,26 @@ import { formatTime } from '../utils/formatTime';
3434
import { LangResource } from '../../common/intl';
3535
import { useLyricProvider } from '../hooks/useLyricProvider';
3636
import { LyricMetadata } from '../../common/provider';
37+
import Selector from '../components/Select';
3738

3839
const LyricsMapEditor = () => {
3940
usePluginsCSS();
4041

4142
const lyricProvider = useLyricProvider();
4243
const {
44+
lyricData,
45+
id: playingId,
4346
title: playingTitle,
4447
artist: playingArtist,
4548
duration,
4649
status,
47-
id,
4850
} = usePlayingInfo();
4951

52+
const [searchMode, setSearchMode] = createSignal<'default' | 'id'>('default');
53+
5054
const [title, setTitle] = createSignal(playingTitle());
5155
const [artist, setArtist] = createSignal(playingArtist());
56+
const [id, setId] = createSignal('');
5257

5358
const [loading, setLoading] = createSignal(false);
5459
const [searchList, setSearchList] = createSignal<LyricMetadata[]>([]);
@@ -71,64 +76,63 @@ const LyricsMapEditor = () => {
7176
observer.disconnect();
7277
});
7378

74-
const onSearch = async () => {
79+
const onSearch = async (nextPage = false) => {
7580
setLoading(true);
7681

82+
if (!nextPage) {
83+
setPage(0);
84+
}
85+
7786
await usePluginOverride(
7887
'search-lyrics',
79-
async (artist, title, options) => {
80-
const result = await lyricProvider()
81-
.searchLyrics({
82-
artist,
83-
title,
84-
playtime: options?.playtime,
85-
page: options?.page,
86-
})
87-
.catch((e) => {
88-
console.error(e);
89-
return [];
90-
});
88+
async (mode, artist, title, id, options) => {
89+
const list: LyricMetadata[] = [];
9190

92-
setSearchList(result);
93-
setPage(0);
94-
setHasNext(true);
95-
},
96-
artist(),
97-
title(),
98-
{ playtime: duration(), page: 0 },
99-
);
100-
101-
setLoading(false);
102-
};
91+
if (mode === 'default') {
92+
list.push(
93+
...(await lyricProvider()
94+
.searchLyrics({
95+
artist,
96+
title,
97+
playtime: options?.playtime,
98+
page: options?.page,
99+
})
100+
.catch((e) => {
101+
console.error(e);
102+
return [];
103+
})),
104+
);
105+
}
106+
if (mode === 'id') {
107+
const result = await lyricProvider()
108+
.getLyricById(id)
109+
.catch((e) => {
110+
console.error(e);
111+
return null;
112+
});
103113

104-
const onSearchNextPage = async () => {
105-
setLoading(true);
114+
if (result) list.push(result);
115+
}
106116

107-
await usePluginOverride(
108-
'search-lyrics',
109-
async (artist, title, options) => {
110-
const result = await lyricProvider()
111-
.searchLyrics({
112-
artist,
113-
title,
114-
playtime: options?.playtime,
115-
page: options?.page,
116-
})
117-
.catch((e) => {
118-
console.error(e);
119-
return [];
120-
});
117+
if (nextPage) {
118+
const isDuplicated = searchList().at(-1)?.id === list.at(-1)?.id;
121119

122-
if (result.length === 0) {
123-
setHasNext(false);
124-
return;
120+
if (!isDuplicated) {
121+
setPage(page() + 1);
122+
setSearchList([...searchList(), ...list]);
123+
} else {
124+
setHasNext(false);
125+
}
126+
} else {
127+
setPage(0);
128+
setSearchList(list);
129+
setHasNext(true);
125130
}
126-
127-
setSearchList([...searchList(), ...result]);
128-
setPage(page() + 1);
129131
},
132+
searchMode(),
130133
artist(),
131134
title(),
135+
id(),
132136
{ playtime: duration(), page: page() },
133137
);
134138

@@ -137,7 +141,7 @@ const LyricsMapEditor = () => {
137141

138142
const onSelect = async (metadata: LyricMetadata) => {
139143
const newMapper = {
140-
[id()]: {
144+
[playingId()]: {
141145
mode: {
142146
type: 'provider' as const,
143147
id: metadata.id,
@@ -151,7 +155,7 @@ const LyricsMapEditor = () => {
151155

152156
const observer = new IntersectionObserver((entries) => {
153157
if (!loading() && entries[0].intersectionRatio > 0) {
154-
onSearchNextPage();
158+
onSearch(true);
155159
}
156160
});
157161

@@ -179,18 +183,43 @@ const LyricsMapEditor = () => {
179183
onSearch();
180184
}}
181185
>
182-
<input
183-
class={'input'}
184-
placeholder={t('lyrics.artist')}
185-
value={artist()}
186-
onInput={(event) => setArtist(event.target.value)}
187-
/>
188-
<input
189-
class={'input flex-1'}
190-
placeholder={t('lyrics.title')}
191-
value={title()}
192-
onInput={(event) => setTitle(event.target.value)}
186+
<Selector
187+
mode={'select'}
188+
placeholder={t('lyrics.search-mode')}
189+
class={'select min-w-[90px] w-16 basis-1/5'}
190+
options={['default', 'id'] as const}
191+
value={searchMode()}
192+
onChange={setSearchMode}
193+
format={(str) => t(`lyrics.search-mode.${str}`)}
193194
/>
195+
<Switch>
196+
<Match when={searchMode() === 'default'}>
197+
<>
198+
<input
199+
class={'input w-16 basis-1/5'}
200+
placeholder={t('lyrics.artist')}
201+
value={artist()}
202+
onInput={(event) => setArtist(event.target.value)}
203+
/>
204+
<input
205+
class={'input w-16 basis-1/5 flex-1'}
206+
placeholder={t('lyrics.title')}
207+
value={title()}
208+
onInput={(event) => setTitle(event.target.value)}
209+
/>
210+
</>
211+
</Match>
212+
<Match when={searchMode() === 'id'}>
213+
<>
214+
<input
215+
class={'input flex-1 w-16 basis-1/5'}
216+
placeholder={t('lyrics.id')}
217+
value={id()}
218+
onInput={(event) => setId(event.target.value)}
219+
/>
220+
</>
221+
</Match>
222+
</Switch>
194223
<button type={'submit'} class={'btn-text btn-icon !min-w-0'}>
195224
<svg
196225
width="16"
@@ -222,7 +251,9 @@ const LyricsMapEditor = () => {
222251
<For each={searchList()}>
223252
{(item) => (
224253
<Card
225-
class={'flex flex-row justify-start items-center gap-1'}
254+
class={`flex flex-row justify-start items-center gap-1
255+
${lyricData()?.id === item.id ? '!bg-primary-100 dark:!bg-primary-800 hover:!bg-primary-200 hover:dark:!bg-primary-700' : ''}
256+
`}
226257
onClick={() => onSelect(item)}
227258
>
228259
<div
@@ -274,19 +305,35 @@ const LyricsMapEditor = () => {
274305
</div>
275306
</Show>
276307
</div>
277-
<svg
278-
width="16"
279-
height="16"
280-
fill="none"
281-
viewBox="0 0 24 24"
282-
xmlns="http://www.w3.org/2000/svg"
283-
class={'self-center flex-shrink-0'}
308+
<Show
309+
when={lyricData()?.id !== item.id}
310+
fallback={
311+
<svg
312+
class={'w-6 h-6 fill-none self-center flex-shrink-0'}
313+
xmlns="http://www.w3.org/2000/svg"
314+
viewBox="0 -960 960 960"
315+
>
316+
<path
317+
d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z"
318+
class={'fill-green-500'}
319+
/>
320+
</svg>
321+
}
284322
>
285-
<path
286-
d="M8.293 4.293a1 1 0 0 0 0 1.414L14.586 12l-6.293 6.293a1 1 0 1 0 1.414 1.414l7-7a1 1 0 0 0 0-1.414l-7-7a1 1 0 0 0-1.414 0Z"
287-
class={'fill-black dark:fill-white'}
288-
/>
289-
</svg>
323+
<svg
324+
width="16"
325+
height="16"
326+
fill="none"
327+
viewBox="0 0 24 24"
328+
xmlns="http://www.w3.org/2000/svg"
329+
class={'w-6 h-6 fill-none self-center flex-shrink-0'}
330+
>
331+
<path
332+
d="M8.293 4.293a1 1 0 0 0 0 1.414L14.586 12l-6.293 6.293a1 1 0 1 0 1.414 1.414l7-7a1 1 0 0 0 0-1.414l-7-7a1 1 0 0 0-1.414 0Z"
333+
class={'fill-black dark:fill-white'}
334+
/>
335+
</svg>
336+
</Show>
290337
</Card>
291338
)}
292339
</For>

0 commit comments

Comments
 (0)