mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-19 05:42:12 +00:00
feat: animethemes
This commit is contained in:
parent
bc35557ebd
commit
fd01257bdf
6 changed files with 80 additions and 45 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ui",
|
||||
"version": "6.3.34",
|
||||
"version": "6.3.35",
|
||||
"license": "BUSL-1.1",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.14.4",
|
||||
|
|
|
|||
|
|
@ -177,8 +177,7 @@ select:not([disabled]):active,
|
|||
textarea:not([disabled]):active,
|
||||
details:active,
|
||||
[tabindex]:not([tabindex="-1"]):active,
|
||||
[contenteditable]:active,
|
||||
[controls]:active {
|
||||
[contenteditable]:active {
|
||||
transition: all 0.1s ease-in-out;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
<script lang='ts'>
|
||||
import Play from 'lucide-svelte/icons/play'
|
||||
|
||||
import { Button, iconSizes } from '../button'
|
||||
|
||||
import type { Media } from '$lib/modules/anilist'
|
||||
|
||||
import { themes } from '$lib/modules/animethemes'
|
||||
|
|
@ -6,44 +10,76 @@
|
|||
export let media: Media
|
||||
|
||||
const themesRes = themes(media.id)
|
||||
// https://api.animethemes.moe/anime/?fields[audio]=id,basename,link,size&fields[video]=id,basename,link,tags&filter[external_id]=113717&filter[has]=resources&filter[site]=AniList&include=animethemes.animethemeentries.videos,animethemes.animethemeentries.videos.audio,animethemes.song,animethemes.song.artists
|
||||
// https://animethemes.moe/anime/momentary_lily
|
||||
// https://animethemes.moe/anime/ousama_ranking
|
||||
|
||||
let src = ''
|
||||
function playVideo (url?: string) {
|
||||
if (!url) return
|
||||
if (src === url) {
|
||||
src = ''
|
||||
return
|
||||
}
|
||||
src = url
|
||||
}
|
||||
function volume (el: HTMLVideoElement) {
|
||||
el.volume = 0.2
|
||||
el.muted = false
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await themesRes}
|
||||
Loading
|
||||
|
||||
{:then themes}
|
||||
{#if themes?.anime?.[0]?.animethemes?.length}
|
||||
{#each themes.anime[0].animethemes as theme (theme.id)}
|
||||
{theme.type}
|
||||
<div class='flex flex-col gap-2 pt-3'>
|
||||
{#await themesRes}
|
||||
{#each Array.from({ length: 2 }) as _, i (i)}
|
||||
<div class='bg-neutral-950 rounded-md px-7 py-4 gap-4 flex flex-col text-xs'>
|
||||
<div class='flex h-8 items-center'>
|
||||
<div class='w-12'>
|
||||
<div class='bg-primary/5 rounded h-2.5 w-4 animate-pulse' />
|
||||
</div>
|
||||
<div class='text-base font-bold flex'>
|
||||
<div class='bg-primary/5 rounded h-2.5 w-32 animate-pulse mr-2' />
|
||||
<div class='bg-primary/5 rounded h-2.5 w-20 animate-pulse' />
|
||||
</div>
|
||||
</div>
|
||||
<div class='flex h-8 items-center text-muted-foreground'>
|
||||
<div class='w-12'>
|
||||
<div class='bg-primary/5 rounded h-2 w-4 animate-pulse' />
|
||||
</div>
|
||||
<div>
|
||||
<div class='bg-primary/5 rounded h-2 w-20 animate-pulse' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{/await}
|
||||
<div class='bg-neutral-950 rounded-md px-7 py-4 gap-4 flex flex-col text-xs'>
|
||||
<div class='flex h-8 items-center'>
|
||||
<div class='w-12'>
|
||||
OP
|
||||
</div>
|
||||
<div class='text-base font-bold'>
|
||||
Oishi Survivor <span class='text-xs text-muted-foreground font-medium'>by</span> HANABIE
|
||||
</div>
|
||||
</div>
|
||||
<div class='flex h-8 items-center text-muted-foreground'>
|
||||
<div class='w-12'>
|
||||
v1
|
||||
</div>
|
||||
<div>
|
||||
Episodes 1-2
|
||||
</div>
|
||||
</div>
|
||||
<div class='flex h-8 items-center text-muted-foreground'>
|
||||
<div class='w-12'>
|
||||
v2
|
||||
</div>
|
||||
<div>
|
||||
Episodes 3-13
|
||||
</div>
|
||||
</div>
|
||||
{:then themes}
|
||||
{#if themes?.anime?.[0]?.animethemes?.length}
|
||||
{#each themes.anime[0].animethemes as theme (theme.id)}
|
||||
<div class='bg-neutral-950 rounded-md px-7 py-4 gap-4 flex flex-col text-xs'>
|
||||
<div class='flex h-8 items-center'>
|
||||
<div class='w-12'>
|
||||
{theme.type}
|
||||
</div>
|
||||
<div class='text-base font-bold'>
|
||||
{theme.song?.title} <span class='text-xs text-muted-foreground font-medium'>by</span> {theme.song?.artists?.map(({ name }) => name).join(', ')}
|
||||
</div>
|
||||
</div>
|
||||
{#each theme.animethemeentries ?? [] as entry (entry.id)}
|
||||
{@const url = entry.videos?.[entry.videos.length - 1]?.link}
|
||||
<div class='flex h-8 items-center text-muted-foreground'>
|
||||
<div class='w-12'>
|
||||
v{entry.version ?? 1}
|
||||
</div>
|
||||
<div>
|
||||
Episodes {entry.episodes}
|
||||
</div>
|
||||
{#if entry.videos?.length}
|
||||
<Button size='icon-sm' class='ml-auto font-bold rounded-full' on:click={() => playVideo(url)}><Play fill='currentColor' size={iconSizes['icon-sm']} /></Button>
|
||||
{/if}
|
||||
</div>
|
||||
{#if src === url}
|
||||
<video class='h-64 rounded-md self-center' controls autoplay {src} use:volume />
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ import type { AnimeThemesResponse } from './types'
|
|||
import { safefetch } from '$lib/utils'
|
||||
|
||||
export function themes (id: number, _fetch = fetch) {
|
||||
return safefetch<AnimeThemesResponse>(_fetch, `https://api.animethemes.moe/anime/?fields[audio]=id,basename,link,size&fields[video]=id,basename,link,tags&filter[external_id]=${id}&filter[has]=resources&filter[site]=AniList&include=animethemes.animethemeentries.videos,animethemes.animethemeentries.videos.audio,animethemes.song,animethemes.song.artists`)
|
||||
return safefetch<AnimeThemesResponse>(_fetch, `https://api.animethemes.moe/anime/?fields[audio]=id,basename,link,size&fields[video]=id,basename,link,tags&filter[external_id]=${id}&filter[has]=resources&filter[site]=AniList&include=animethemes.animethemeentries.videos,animethemes.song,animethemes.song.artists`)
|
||||
}
|
||||
|
|
|
|||
6
src/lib/modules/animethemes/types.d.ts
vendored
6
src/lib/modules/animethemes/types.d.ts
vendored
|
|
@ -17,7 +17,7 @@ export interface Anime {
|
|||
|
||||
export interface AnimeTheme {
|
||||
id?: number
|
||||
sequence?: null
|
||||
sequence?: number
|
||||
slug?: string
|
||||
type?: string
|
||||
song?: Song
|
||||
|
|
@ -27,10 +27,10 @@ export interface AnimeTheme {
|
|||
export interface AnimeThemeEntry {
|
||||
id?: number
|
||||
episodes?: string
|
||||
notes?: null
|
||||
notes?: string
|
||||
nsfw?: boolean
|
||||
spoiler?: boolean
|
||||
version?: null
|
||||
version?: number
|
||||
videos?: Video[]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
<Tabs.List class='flex'>
|
||||
<Tabs.Trigger value='episodes' class='px-8 data-[state=active]:font-bold'>Episodes</Tabs.Trigger>
|
||||
<Tabs.Trigger value='threads' class='px-8 data-[state=active]:font-bold'>Threads</Tabs.Trigger>
|
||||
<Tabs.Trigger value='themes' class='px-8 data-[state=active]:font-bold' disabled>Themes</Tabs.Trigger>
|
||||
<Tabs.Trigger value='themes' class='px-8 data-[state=active]:font-bold'>Themes</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
<Tabs.Content value='episodes' tabindex={-1}>
|
||||
|
|
|
|||
Loading…
Reference in a new issue