mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-05 08:49:42 +00:00
feat: subtitle delay keybinds and info, keybind descriptions
This commit is contained in:
parent
14720a07c6
commit
bb9f7a79d0
6 changed files with 63 additions and 21 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ui",
|
||||
"version": "6.3.45",
|
||||
"version": "6.3.46",
|
||||
"license": "BUSL-1.1",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.14.4",
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@
|
|||
<script lang='ts'>
|
||||
export let clickable = false
|
||||
|
||||
export let pointerOver: (bind: Bind | undefined) => void
|
||||
|
||||
let dragged: HTMLDivElement | null = null
|
||||
function draggable (node: HTMLDivElement, code: KeyCode) {
|
||||
const ctrl = new AbortController()
|
||||
|
|
@ -113,7 +115,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class='svelte-keybinds'>
|
||||
<div class='svelte-keybinds' on:pointerleave>
|
||||
{#each Object.values(keys) as key (key.name)}
|
||||
{@const { size, dark, name } = key}
|
||||
<div
|
||||
|
|
@ -123,6 +125,7 @@
|
|||
class='w-{size ?? 50}'
|
||||
{...$$restProps}
|
||||
use:draggable={name}
|
||||
on:pointerover={() => pointerOver($binds[name])}
|
||||
on:click={(e) => clickable && runBind(e, name)}>
|
||||
<slot prop={$binds[name]} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@
|
|||
let fullscreenElement: HTMLElement | null = null
|
||||
|
||||
export let id = ''
|
||||
|
||||
let keybindDesc: unknown = null
|
||||
</script>
|
||||
|
||||
<Dialog.Root portal={wrapper} bind:open>
|
||||
|
|
@ -82,17 +84,17 @@
|
|||
<div on:pointerdown|self={close} class='size-full flex justify-center items-center flex-col overflow-y-scroll text-[6px] lg:text-xs' use:dragScroll>
|
||||
{#if showKeybinds}
|
||||
<div class='bg-black py-3 px-4 rounded-md text-sm lg:text-lg font-bold mb-4'>
|
||||
Drag and drop binds to change them
|
||||
{keybindDesc ?? 'Drag and drop binds to change them'}
|
||||
</div>
|
||||
<Keybinds let:prop={item} autosave={true} clickable={true}>
|
||||
<Keybinds let:prop={item} autosave={true} clickable={true} on:pointerleave={() => { keybindDesc = null }} pointerOver={item => { keybindDesc = item?.desc }}>
|
||||
{#if item?.type}
|
||||
<div class='size-full flex justify-center p-1.5 lg:p-3' title={item.desc}>
|
||||
<div class='size-full flex justify-center p-1.5 lg:p-3'>
|
||||
{#if item.icon}
|
||||
<svelte:component this={item.icon} size='2rem' class='h-full' fill={item.id === 'play_arrow' ? 'currentColor' : 'none'} />
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class='size-full content-center text-center lg:text-lg' title={item?.desc}>{item?.id ?? ''}</div>
|
||||
<div class='size-full content-center text-center lg:text-lg'>{item?.id ?? ''}</div>
|
||||
{/if}
|
||||
</Keybinds>
|
||||
{:else}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
import ChevronDown from 'lucide-svelte/icons/chevron-down'
|
||||
import ChevronUp from 'lucide-svelte/icons/chevron-up'
|
||||
import Contrast from 'lucide-svelte/icons/contrast'
|
||||
import DecimalsArrowLeft from 'lucide-svelte/icons/decimals-arrow-left'
|
||||
import DecimalsArrowRight from 'lucide-svelte/icons/decimals-arrow-right'
|
||||
import FastForward from 'lucide-svelte/icons/fast-forward'
|
||||
import List from 'lucide-svelte/icons/list'
|
||||
import Maximize from 'lucide-svelte/icons/maximize'
|
||||
|
|
@ -622,6 +624,20 @@
|
|||
id: 'schedule',
|
||||
type: 'icon',
|
||||
desc: 'Reset Playback Rate'
|
||||
},
|
||||
Semicolon: {
|
||||
fn: () => { subtitleDelay -= 0.1 },
|
||||
icon: DecimalsArrowLeft,
|
||||
type: 'icon',
|
||||
id: 'subtitle_delay_minus',
|
||||
desc: 'Decrease Subtitle Delay'
|
||||
},
|
||||
Quote: {
|
||||
fn: () => { subtitleDelay += 0.1 },
|
||||
icon: DecimalsArrowRight,
|
||||
type: 'icon',
|
||||
id: 'subtitle_delay_plus',
|
||||
desc: 'Increase Subtitle Delay'
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -736,6 +752,7 @@
|
|||
Resolution: {stats.resolution}<br />
|
||||
Buffer health: {stats.buffer}<br />
|
||||
Playback speed: x{stats.speed?.toFixed(1)}<br />
|
||||
Subtitle delay: {subtitleDelay} sec
|
||||
</div>
|
||||
{/if}
|
||||
<Options {wrapper} bind:openSubs {video} {seekTo} {selectAudio} {selectVideo} {fullscreen} {chapters} {subtitles} {videoFiles} {selectFile} {pip} bind:playbackRate bind:subtitleDelay
|
||||
|
|
|
|||
9
src/lib/modules/auth/kitsu-types.d.ts
vendored
9
src/lib/modules/auth/kitsu-types.d.ts
vendored
|
|
@ -7,9 +7,16 @@ export interface OAuth {
|
|||
token_type: string
|
||||
}
|
||||
|
||||
export interface KitsuError {
|
||||
export type KitsuError = {
|
||||
error: string
|
||||
error_description: string
|
||||
} | {
|
||||
errors: Array<{
|
||||
code: string
|
||||
status: string
|
||||
title: string
|
||||
detail: string
|
||||
}>
|
||||
}
|
||||
|
||||
export interface Resource<T> {
|
||||
|
|
|
|||
|
|
@ -118,9 +118,6 @@ export default new class KitsuSync {
|
|||
body: body ? JSON.stringify(body) : undefined
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Kitsu API Error: ${res.status} ${res.statusText}`)
|
||||
}
|
||||
if (method === 'DELETE') return undefined as T
|
||||
|
||||
const json = await res.json() as object | KitsuError
|
||||
|
|
@ -128,6 +125,11 @@ export default new class KitsuSync {
|
|||
if ('error' in json) {
|
||||
toast.error('Kitsu Error', { description: json.error_description })
|
||||
console.error(json)
|
||||
} else if ('errors' in json) {
|
||||
for (const error of json.errors) {
|
||||
toast.error('Kitsu Error', { description: error.detail })
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
return json as T | KitsuError
|
||||
|
|
@ -172,10 +174,10 @@ export default new class KitsuSync {
|
|||
refresh_token: this.auth.value?.refresh_token
|
||||
}
|
||||
)
|
||||
if ('error' in data) {
|
||||
this.auth.value = undefined
|
||||
} else {
|
||||
if ('access_token' in data) {
|
||||
this.auth.value = data
|
||||
} else {
|
||||
this.auth.value = undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -190,10 +192,10 @@ export default new class KitsuSync {
|
|||
}
|
||||
)
|
||||
|
||||
if ('error' in data) {
|
||||
this.auth.value = undefined
|
||||
} else {
|
||||
if ('access_token' in data) {
|
||||
this.auth.value = data
|
||||
} else {
|
||||
this.auth.value = undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,7 +218,7 @@ export default new class KitsuSync {
|
|||
}
|
||||
)
|
||||
|
||||
if ('error' in res || !res.data[0]) return
|
||||
if ('error' in res || 'errors' in res || !res.data[0]) return
|
||||
|
||||
this._entriesToML(res)
|
||||
|
||||
|
|
@ -323,7 +325,7 @@ export default new class KitsuSync {
|
|||
}
|
||||
)
|
||||
|
||||
if ('error' in data) return
|
||||
if (!('data' in data)) return
|
||||
|
||||
this.favorites.value[kitsuAnimeId] = data.data.id
|
||||
}
|
||||
|
|
@ -343,7 +345,7 @@ export default new class KitsuSync {
|
|||
}
|
||||
)
|
||||
|
||||
if ('error' in data) return
|
||||
if (!('data' in data)) return
|
||||
|
||||
this.userlist.value[alId] = this._kitsuEntryToAl(data.data)
|
||||
}
|
||||
|
|
@ -356,11 +358,12 @@ export default new class KitsuSync {
|
|||
}
|
||||
)
|
||||
|
||||
if ('error' in data) return
|
||||
if (!('data' in data)) return
|
||||
|
||||
this.userlist.value[alId] = this._kitsuEntryToAl(data.data)
|
||||
}
|
||||
|
||||
// TODO: use kitsu's own API for this instead?
|
||||
async _getKitsuId (alId: number) {
|
||||
const kitsuId = this.ALToKitsu[alId.toString()]
|
||||
if (kitsuId) return kitsuId
|
||||
|
|
@ -431,7 +434,17 @@ export default new class KitsuSync {
|
|||
}
|
||||
|
||||
following (id: number) {
|
||||
// TODO
|
||||
return null
|
||||
// TODO: this doesnt work
|
||||
// this._get<Res<KEntry, Anime | Mapping>>(
|
||||
// ENDPOINTS.API_USER_LIBRARY,
|
||||
// {
|
||||
// 'filter[following]': true,
|
||||
// 'filter[user_id]': this.viewer.value?.id,
|
||||
// 'filter[animeId]': 42765,
|
||||
// include: 'anime.mappings,user'
|
||||
// }
|
||||
// )
|
||||
}
|
||||
|
||||
async entry (variables: VariablesOf<typeof Entry>) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue