[+] Fully implement netease import

This commit is contained in:
2025-11-19 23:07:36 +08:00
parent dbaca29397
commit 69c9e42a3c
3 changed files with 56 additions and 41 deletions
+18
View File
@@ -0,0 +1,18 @@
<script lang="ts">
import Dialog from "./Dialog.svelte";
let p: {
error?: string
} = $props()
let open = $derived(!!p.error)
</script>
<Dialog title="错误" bind:open buttons={[{
text: "刷新重试",
onclick: () => location.reload()
}]}>
<div class="text-red-500">
{p.error}
</div>
</Dialog>
+7 -1
View File
@@ -8,7 +8,13 @@ export async function post(endpoint: string, data: any) {
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}).then(res => res.json()) }).then(async res => {
if (res.status >= 400) throw new Error(`错误 ${res.status}${await res.text()}`)
return res.json()
}).catch(e => {
console.error(e)
throw e
})
} }
export const API = { export const API = {
+31 -40
View File
@@ -4,6 +4,7 @@
import Button from "../../../components/Button.svelte" import Button from "../../../components/Button.svelte"
import type { NeteaseSongBrief } from "../../../shared/types" import type { NeteaseSongBrief } from "../../../shared/types"
import { API } from "../../../lib/client" import { API } from "../../../lib/client"
import ErrorDialog from "../../../components/status/ErrorDialog.svelte";
let link = $state('') let link = $state('')
@@ -18,6 +19,8 @@
total: songs.length, total: songs.length,
done: songs.filter(song => song.status !== 'importing').length done: songs.filter(song => song.status !== 'importing').length
}) })
let error = $state('')
let id = $state('')
function statusToIcon(stat: string): string { function statusToIcon(stat: string): string {
switch (stat) { switch (stat) {
@@ -34,52 +37,34 @@
status = 'importing' status = 'importing'
songs = [] songs = []
try { API.netease.startImport(link)
const data = await API.netease.startImport(link) .catch(e => error = e.message)
.then(data => {
if (data.error) { id = data.playlistId
alert(data.error)
status = 'error'
return
}
const importId = data.id
songs = data.songs
pollProgress(importId)
} catch (e) {
console.error(e)
status = 'error'
alert('Failed to start import')
}
}
async function pollProgress(id: string) {
const interval = setInterval(async () => {
try {
const data = await API.netease.checkProgress(id)
if (data.error) {
clearInterval(interval)
return
}
songs = data.songs songs = data.songs
if (data.done) { const interval = setInterval(() => {
clearInterval(interval) API.netease.checkProgress(data.id)
status = 'success' .catch(e => {
} error = e.message
} catch (e) { clearInterval(interval)
console.error(e) })
clearInterval(interval) .then(data => {
} songs = data.songs
}, 1000) if (data.done) {
clearInterval(interval)
status = 'success'
}
})
}, 1000)
})
} }
</script> </script>
<AppBar title="从网易云导入"/> <AppBar title="从网易云导入"/>
<ErrorDialog error={error} />
<div class="vbox gap-16px flex-1 min-h-0"> <div class="vbox gap-16px flex-1 min-h-0">
<div class="m3-font-body-medium mfg-on-surface-variant py-12px p-content"> <div class="m3-font-body-medium mfg-on-surface-variant py-12px p-content">
去网易云 APP 找一个你喜欢的日本语歌单,点击分享,再点击复制链接,然后把链接粘贴到这里就可以开始导入了! 去网易云 APP 找一个你喜欢的日本语歌单,点击分享,再点击复制链接,然后把链接粘贴到这里就可以开始导入了!
@@ -113,6 +98,12 @@
</div> </div>
<div class="py-16px p-content"> <div class="py-16px p-content">
<Button big icon="i-material-symbols:download" onclick={startImport} disabled={status === 'importing'}>开始导入</Button> {#if status === 'idle'}
<Button big icon="i-material-symbols:download" onclick={startImport}>开始导入</Button>
{:else if status === 'success'}
<a href="/playlist/{id}">
<Button big icon="i-material-symbols:right-arrow">查看歌单</Button>
</a>
{/if}
</div> </div>
</div> </div>