feat: hide hentai by default
Some checks failed
Check / check (push) Has been cancelled

fix: improve airing schedule results
This commit is contained in:
ThaUnknown 2025-09-29 17:30:21 +02:00
parent bccaac3c24
commit de3da8acf8
No known key found for this signature in database
12 changed files with 31 additions and 25 deletions

View file

@ -1,6 +1,6 @@
{
"name": "ui",
"version": "6.4.149",
"version": "6.4.150",
"license": "BUSL-1.1",
"private": true,
"packageManager": "pnpm@9.15.5",

View file

@ -75,8 +75,7 @@ export default class PictureInPicture {
const renderFrame = (noskip?: number) => {
if (noskip) this.video!.paused ? video.pause() : video.play()
context.drawImage(this.deband?.canvas ?? this.video!, 0, 0)
// @ts-expect-error internal call on canvas
if (canvas.width && canvas.height && this.subtitles.renderer?._canvas) context.drawImage(this.subtitles.renderer._canvas, 0, 0, canvas.width, canvas.height)
if (canvas.width && canvas.height && this.subtitles?.renderer?._canvas) context.drawImage(this.subtitles.renderer._canvas, 0, 0, canvas.width, canvas.height)
loop = this.video!.requestVideoFrameCallback(renderFrame)
}
ctrl.signal.addEventListener('abort', () => {

View file

@ -3,6 +3,8 @@ import Debug from 'debug'
import lavenshtein from 'js-levenshtein'
import { derived, get, readable, writable, type Writable } from 'svelte/store'
import { nsfw } from '../settings/settings'
import { Comments, DeleteEntry, DeleteThreadComment, Entry, Following, type FullMedia, IDMedia, RecrusiveRelations, SaveThreadComment, Schedule, Search, Threads, ToggleFavourite, ToggleLike, UserLists } from './queries'
import urqlClient from './urql-client'
import { currentSeason, currentYear, lastSeason, lastYear, nextSeason, nextYear } from './util'
@ -105,7 +107,7 @@ class AnilistClient {
})
search (variables: VariablesOf<typeof Search>, pause?: boolean) {
return queryStore({ client: this.client, query: Search, variables, pause })
return queryStore({ client: this.client, query: Search, variables: { ...variables, nsfw: get(nsfw) }, pause })
}
async searchCompound (flattenedTitles: Array<{key: string, title: string, year?: string, isAdult: boolean}>) {
@ -199,8 +201,8 @@ class AnilistClient {
return Object.fromEntries(Object.values(res.data ?? {}).flatMap(({ media }) => media).map(media => [media.idMal, media.id]))
}
schedule (ids?: number[], onList = true) {
return queryStore({ client: this.client, query: Schedule, variables: { ids, onList, seasonCurrent: currentSeason, seasonYearCurrent: currentYear, seasonLast: lastSeason, seasonYearLast: lastYear, seasonNext: nextSeason, seasonYearNext: nextYear } })
schedule (ids?: number[], onList: boolean | null = true) {
return queryStore({ client: this.client, query: Schedule, variables: { ids, onList, seasonCurrent: currentSeason, seasonYearCurrent: currentYear, seasonLast: lastSeason, seasonYearLast: lastYear, seasonNext: nextSeason, seasonYearNext: nextYear, formatNot: onList ? null : 'TV_SHORT', nsfw: get(nsfw) } })
}
async toggleFav (id: number) {

View file

@ -153,12 +153,12 @@ export const UserFrag = gql(`
`)
export const Search = gql(`
query Search($page: Int, $perPage: Int, $search: String, $genre: [String], $format: [MediaFormat], $status: [MediaStatus], $statusNot: [MediaStatus], $season: MediaSeason, $seasonYear: Int, $isAdult: Boolean, $sort: [MediaSort], $onList: Boolean, $ids: [Int]) {
query Search($page: Int, $perPage: Int, $search: String, $genre: [String], $format: [MediaFormat], $status: [MediaStatus], $statusNot: [MediaStatus], $season: MediaSeason, $seasonYear: Int, $isAdult: Boolean, $sort: [MediaSort], $onList: Boolean, $ids: [Int], $nsfw: [String]) {
Page(page: $page, perPage: $perPage) {
pageInfo {
hasNextPage
},
media(type: ANIME, format_not: MUSIC, id_in: $ids, search: $search, genre_in: $genre, format_in: $format, status_in: $status, status_not_in: $statusNot, season: $season, seasonYear: $seasonYear, isAdult: $isAdult, sort: $sort, onList: $onList) {
media(type: ANIME, format_not: MUSIC, id_in: $ids, search: $search, genre_in: $genre, format_in: $format, status_in: $status, status_not_in: $statusNot, season: $season, seasonYear: $seasonYear, isAdult: $isAdult, sort: $sort, onList: $onList, genre_not_in: $nsfw) {
...FullMedia
}
}
@ -254,34 +254,34 @@ export const ScheduleMedia = gql(`
`)
export const Schedule = gql(`
query Schedule($seasonCurrent: MediaSeason, $seasonYearCurrent: Int, $seasonLast: MediaSeason, $seasonYearLast: Int, $seasonNext: MediaSeason, $seasonYearNext: Int, $onList: Boolean, $ids: [Int]) {
query Schedule($seasonCurrent: MediaSeason, $seasonYearCurrent: Int, $seasonLast: MediaSeason, $seasonYearLast: Int, $seasonNext: MediaSeason, $seasonYearNext: Int, $onList: Boolean, $ids: [Int], $formatNot: MediaFormat, $nsfw: [String]) {
curr1: Page(page: 1) {
media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, countryOfOrigin: JP, format_not: TV_SHORT, onList: $onList, id_in: $ids) {
media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, format_not: $formatNot, onList: $onList, id_in: $ids, genre_not_in: $nsfw) {
...ScheduleMedia
}
}
curr2: Page(page: 2) {
media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, countryOfOrigin: JP, format_not: TV_SHORT, onList: $onList, id_in: $ids) {
media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, format_not: $formatNot, onList: $onList, id_in: $ids, genre_not_in: $nsfw) {
...ScheduleMedia
}
}
curr3: Page(page: 3) {
media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, countryOfOrigin: JP, format_not: TV_SHORT, onList: $onList, id_in: $ids) {
media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, format_not: $formatNot, onList: $onList, id_in: $ids, genre_not_in: $nsfw) {
...ScheduleMedia
}
}
residue: Page(page: 1) {
media(type: ANIME, season: $seasonLast, seasonYear: $seasonYearLast, episodes_greater: 16, countryOfOrigin: JP, format_not: TV_SHORT, onList: $onList, id_in: $ids) {
media(type: ANIME, season: $seasonLast, seasonYear: $seasonYearLast, episodes_greater: 11, format_not: $formatNot, onList: $onList, id_in: $ids, genre_not_in: $nsfw) {
...ScheduleMedia
}
},
next1: Page(page: 1) {
media(type: ANIME, season: $seasonNext, seasonYear: $seasonYearNext, sort: [START_DATE], countryOfOrigin: JP, format_not: TV_SHORT, onList: $onList, id_in: $ids) {
media(type: ANIME, season: $seasonNext, seasonYear: $seasonYearNext, sort: [START_DATE], format_not: $formatNot, onList: $onList, id_in: $ids, genre_not_in: $nsfw) {
...ScheduleMedia
}
},
next2: Page(page: 2) {
media(type: ANIME, season: $seasonNext, seasonYear: $seasonYearNext, sort: [START_DATE], countryOfOrigin: JP, format_not: TV_SHORT, onList: $onList, id_in: $ids) {
media(type: ANIME, season: $seasonNext, seasonYear: $seasonYearNext, sort: [START_DATE], format_not: $formatNot, onList: $onList, id_in: $ids, genre_not_in: $nsfw) {
...ScheduleMedia
}
}

View file

@ -72,7 +72,7 @@ export default new class AuthAggregator {
// QUERIES/MUTATIONS
schedule (onList = true) {
schedule (onList: boolean | null = true) {
if (this.anilist()) return client.schedule(undefined, onList)
if (this.kitsu()) return kitsu.schedule(onList)
if (this.mal()) return mal.schedule(onList)

View file

@ -417,7 +417,7 @@ export default new class KitsuSync {
// QUERIES/MUTATIONS
schedule (onList = true) {
schedule (onList: boolean | null = true) {
const ids = Object.keys(this.userlist.value).map(id => parseInt(id))
debug('Kitsu schedule called with onList:', onList, 'and ids:', ids)
return client.schedule(onList && ids.length ? ids : undefined)

View file

@ -45,7 +45,7 @@ export default new class LocalSync {
}
}
schedule (onList = true): ReturnType<typeof client.schedule> {
schedule (onList: boolean | null = true): ReturnType<typeof client.schedule> {
const ids = Object.values(this.entries.value).map(({ mediaListEntry }) => mediaListEntry?.id).filter(e => e != null)
return client.schedule(onList && ids.length ? ids : undefined)
}

View file

@ -430,7 +430,7 @@ export default new class MALSync {
// QUERIES/MUTATIONS
schedule (onList = true) {
schedule (onList: boolean | null = true) {
const ids = Object.keys(this.userlist.value).map(id => parseInt(id))
debug('Fetching MAL schedule with IDs:', ids)
return client.schedule(onList && ids.length ? ids : undefined)

View file

@ -42,5 +42,6 @@ export default {
playerSkip: false,
playerSkipFiller: false,
minimalPlayerUI: false,
androidStorageType: 'cache'
androidStorageType: 'cache',
showHentai: false
}

View file

@ -14,6 +14,8 @@ export const settings = persisted('settings', defaults, { beforeRead: value => (
export const debug = persisted('debug-key', '')
export const nsfw = derived(settings, $settings => ($settings.showHentai ? null : ['Hentai']) as ['Hentai'] | null)
debug.subscribe((value) => {
native.debug(value)
Debug.enable(value)

View file

@ -21,7 +21,7 @@
const onList = persisted('schedule-on-list', true)
$: query = authAggregator.schedule($onList)
$: query = authAggregator.schedule($onList || null)
let now = new Date()
$: monthName = now.toLocaleString('en-US', { month: 'long' })
@ -200,7 +200,7 @@
<Tooltip.Content sameWidth={true} class='text-center gap-1.5'>
{#each episodes.slice(5) as episode, i (i)}
{@const status = _list(episode)}
<ButtonPrimitive.Root class={cn('flex items-center h-4 w-full group', +episode.airTime < Date.now() && 'text-neutral-300')} href='/app/anime/{episode.id}'>
<ButtonPrimitive.Root class={cn('flex items-center h-4 w-full group', +episode.airTime < Date.now() && 'text-neutral-400')} href='/app/anime/{episode.id}'>
<div class='font-medium text-nowrap text-ellipsis overflow-hidden pr-2' title={episode.title?.userPreferred}>
{#if status}
<StatusDot variant={status} class='hidden xl:inline-flex' />

View file

@ -52,8 +52,8 @@
<SettingCard let:id title='CSS Variables' description='Used for custom themes. Can change colors, sizes, spacing and more. Supports only variables.'>
<Textarea class='form-control w-60 shrink-0 mw-full bg-dark' placeholder='--accent-color: #e5204c;' bind:value={$variables} {id} />
</SettingCard>
<div class='font-weight-bold text-xl font-bold'>UI Settings</div>
{#if !SUPPORTS.isAndroid}
<div class='font-weight-bold text-xl font-bold'>Rendering Settings</div>
<SettingCard title='ANGLE Backend' description="What ANGLE backend to use for rendering. DON'T CHANGE WITHOUT REASON! On some Windows machines D3D9 might help with flicker. Changing this setting to something your device doesn't support might prevent Hayase from opening which will require a full reinstall. While Vulkan is an available option it might not be fully supported on Linux.">
<SingleCombo bind:value={$settings.angle} items={angle} class='w-40 shrink-0 border-input border' />
</SettingCard>
@ -62,11 +62,13 @@
<SettingCard title='Idle Animation' description='Enable/Disable the 3d idle animation. Changing this setting will restart the app.' let:id>
<Switch bind:checked={$settings.idleAnimation} on:click={native.restart} {id} />
</SettingCard> -->
{:else}
<div class='font-weight-bold text-xl font-bold'>UI Settings</div>
{/if}
<SettingCard title='UI Scale' description='Change the zoom level of the interface.' let:id>
<Slider bind:value min={0.3} max={2.5} step={0.1} class='w-60 shrink-0' on:pointerup={saveScale} />
<div class='text-muted-foreground text-xs'>{Number(value[0]).toFixed(1)}</div>
</SettingCard>
<div class='font-weight-bold text-xl font-bold'>Visibility Settings</div>
<SettingCard let:id title='Show Hentai' description='Shows hentai content throughout the app. If disabled all hentai content will be hidden and not shown in search results, but shown if present in your list.'>
<Switch {id} bind:checked={$settings.showHentai} />
</SettingCard>
</div>