mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-20 14:22:09 +00:00
feat: toasts, show errors for RSS fetch fails, show ratelimit errors, show resolving warnings, show low seeder warnings, fix viewanime progress
This commit is contained in:
parent
4d40b9c182
commit
c6d5c0b4c9
8 changed files with 103 additions and 36 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Miru",
|
||||
"version": "0.9.2",
|
||||
"version": "0.10.1",
|
||||
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
import ViewAnime from './lib/ViewAnime.svelte'
|
||||
import RSSView from './lib/RSSView.svelte'
|
||||
import Menubar from './lib/Menubar.svelte'
|
||||
import Toasts from './lib/Toasts.svelte'
|
||||
|
||||
let view = writable(null)
|
||||
setContext('view', view)
|
||||
|
|
@ -23,6 +24,7 @@
|
|||
|
||||
</script>
|
||||
|
||||
<Toasts />
|
||||
<ViewAnime />
|
||||
<RSSView />
|
||||
<div class="page-wrapper with-navbar with-sidebar with-transitions" data-sidebar-type="overlayed-sm-and-down" data-sidebar-hidden={$sidebar || null}>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { DOMPARSER } from '@/modules/util.js'
|
||||
import { updateMedia } from './pages/Player.svelte'
|
||||
import { set } from './pages/Settings.svelte'
|
||||
import { addToast } from '@/lib/Toasts.svelte'
|
||||
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
|
|
@ -10,7 +11,7 @@
|
|||
const settings = set
|
||||
|
||||
export function playAnime(media, episode = 1) {
|
||||
episode = isNaN(episode) ? 1 : episode;
|
||||
episode = isNaN(episode) ? 1 : episode
|
||||
rss.set({ media, episode })
|
||||
}
|
||||
|
||||
|
|
@ -25,12 +26,11 @@
|
|||
throw Error(res.statusText)
|
||||
})
|
||||
.catch(error => {
|
||||
// halfmoon.initStickyAlert({
|
||||
// content: 'Failed fetching RSS!<br>' + error,
|
||||
// title: 'Search Failed',
|
||||
// alertType: 'alert-danger',
|
||||
// fillType: ''
|
||||
// })
|
||||
addToast({
|
||||
text: 'Failed fetching RSS!<br>' + error,
|
||||
title: 'Search Failed',
|
||||
alertType: 'danger'
|
||||
})
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
|
|
@ -101,8 +101,7 @@
|
|||
media: media
|
||||
}
|
||||
if (settings.rssAutoplay) {
|
||||
updateMedia(fileMedia)
|
||||
add(entries[0].link)
|
||||
play(entries[0])
|
||||
} else {
|
||||
table = entries
|
||||
}
|
||||
|
|
@ -110,9 +109,16 @@
|
|||
function close() {
|
||||
table = null
|
||||
}
|
||||
function play(link) {
|
||||
function play(entry) {
|
||||
updateMedia(fileMedia)
|
||||
add(link)
|
||||
if (entry.seeders !== '?' && entry.seeders <= 15) {
|
||||
addToast({
|
||||
text: 'This release is poorly seeded and likely will have playback issues such as buffering!',
|
||||
title: 'Availability Warning',
|
||||
type: 'secondary'
|
||||
})
|
||||
}
|
||||
add(entry.link)
|
||||
table = null
|
||||
}
|
||||
</script>
|
||||
|
|
@ -138,7 +144,7 @@
|
|||
</thead>
|
||||
<tbody class="results pointer">
|
||||
{#each table as row, index}
|
||||
<tr on:click={() => play(row.link)}>
|
||||
<tr on:click={() => play(row)}>
|
||||
<th>{index + 1}</th>
|
||||
<td>{row.title}</td>
|
||||
<td>{row.size}</td>
|
||||
|
|
|
|||
52
src/renderer/src/lib/Toasts.svelte
Normal file
52
src/renderer/src/lib/Toasts.svelte
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<script context="module">
|
||||
import { writable } from 'svelte/store'
|
||||
const toasts = writable({})
|
||||
let index = 0
|
||||
export function addToast(opts) {
|
||||
// type, click, title, text
|
||||
toasts.update(toasts => {
|
||||
const i = ++index
|
||||
toasts[i] = opts
|
||||
setTimeout(() => {
|
||||
close(i)
|
||||
}, 10000)
|
||||
return toasts
|
||||
})
|
||||
}
|
||||
function close(index) {
|
||||
toasts.update(toasts => {
|
||||
if (toasts[index]) {
|
||||
delete toasts[index]
|
||||
}
|
||||
return toasts
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="sticky-alerts d-flex flex-column-reverse">
|
||||
{#each Object.entries($toasts) as [index, toast] (index)}
|
||||
<div class="alert alert-{toast.type} filled" class:pointer={toast.click} on:click={toast.click}>
|
||||
<button class="close" type="button" on:click={() => close(index)}><span aria-hidden="true">×</span></button>
|
||||
<h4 class="alert-heading">{toast.title}</h4>
|
||||
{@html toast.text}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.alert {
|
||||
display: block !important;
|
||||
animation: 0.3s ease 0s 1 fly-in;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@keyframes fly-in {
|
||||
from {
|
||||
right: -50rem;
|
||||
}
|
||||
|
||||
to {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -7,6 +7,9 @@
|
|||
function close() {
|
||||
$view = null
|
||||
}
|
||||
function checkClose({ keyCode }) {
|
||||
if (keyCode == 27) close()
|
||||
}
|
||||
const detailsMap = [
|
||||
{ property: 'episode', label: 'Airing', icon: 'schedule', custom: 'property' },
|
||||
{ property: 'genres', label: 'Genres', icon: 'theater_comedy' },
|
||||
|
|
@ -24,8 +27,8 @@
|
|||
]
|
||||
function getCustomProperty(detail, media) {
|
||||
if (detail.property === 'episodes') {
|
||||
if (media.progress) {
|
||||
return `Watched <b>${media.progress}</b> of <b>${media.episodes}</b>`
|
||||
if (media.mediaListEntry?.progress) {
|
||||
return `Watched <b>${media.mediaListEntry.progress}</b> of <b>${media.episodes}</b>`
|
||||
}
|
||||
return `${media.episodes} Episodes`
|
||||
} else if (detail.property === 'averageScore') {
|
||||
|
|
@ -50,10 +53,10 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="modal modal-full" class:show={$view} id="viewAnime" tabindex="-1" role="dialog">
|
||||
<div class="modal modal-full" class:show={$view} id="viewAnime" tabindex="-1" role="dialog" on:keydown={checkClose}>
|
||||
{#if $view}
|
||||
<div class="h-full modal-content bg-very-dark p-0 overflow-y-auto">
|
||||
<button class="close pointer z-30 bg-dark shadow-lg border" type="button" on:click={close}>
|
||||
<button class="d-flex justify-content-center align-items-center close pointer z-30 bg-dark shadow-lg border top-20 right-0" type="button" on:click={close}>
|
||||
<span>×</span>
|
||||
</button>
|
||||
<div class="h-md-half w-full position-relative z-20">
|
||||
|
|
@ -114,7 +117,7 @@
|
|||
close()
|
||||
}}>
|
||||
<span class="material-icons mr-10 font-size-24 w-30"> play_arrow </span>
|
||||
<span>{$view.mediaListEntry?.progress ? 'Continue' : 'Play'}</span>
|
||||
<span>{$view.mediaListEntry?.progress ? 'Continue ' + ($view.mediaListEntry?.progress + 1): 'Play'}</span>
|
||||
</button>
|
||||
<button class="btn d-flex align-items-center mb-5 font-weight-bold font-size-16">
|
||||
<span class="material-icons mr-10 font-size-18 w-30"> live_tv </span>
|
||||
|
|
@ -173,7 +176,7 @@
|
|||
<div class="d-flex flex-column justify-content-center text-nowrap">
|
||||
<div class="font-weight-bold">
|
||||
{#if detail.custom === 'property'}
|
||||
{getCustomProperty(detail, $view)}
|
||||
{@html getCustomProperty(detail, $view)}
|
||||
{:else if property.constructor === Array}
|
||||
{property === 'nodes' ? property[0] && property[0].name : property.join(', ').replace(/_/g, ' ').toLowerCase()}
|
||||
{:else}
|
||||
|
|
@ -225,7 +228,11 @@
|
|||
.title {
|
||||
font-size: 4rem;
|
||||
}
|
||||
|
||||
.close {
|
||||
top: 1rem !important;
|
||||
left: unset;
|
||||
right: 2.5rem !important;
|
||||
}
|
||||
.badge {
|
||||
background-color: var(--dm-button-bg-color) !important;
|
||||
padding: 0.6rem 2rem;
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
import { alToken } from '@/lib/pages/Settings.svelte'
|
||||
import { addToast } from '@/lib/Toasts.svelte'
|
||||
|
||||
export const alID =
|
||||
!!alToken &&
|
||||
alRequest({ method: 'Viewer', token: alToken })
|
||||
|
||||
async function handleRequest(opts) {
|
||||
async function handleRequest (opts) {
|
||||
return await fetch('https://graphql.anilist.co', opts).then(async res => {
|
||||
const json = await res.json()
|
||||
if (!res.ok) {
|
||||
for (const error of json.errors) {
|
||||
// halfmoon.initStickyAlert({
|
||||
// content: `Failed making request to anilist!<br>${error.status} - ${error.message}`,
|
||||
// title: 'Search Failed',
|
||||
// alertType: 'alert-danger',
|
||||
// fillType: ''
|
||||
// })
|
||||
addToast({
|
||||
text: `Failed making request to anilist!<br>Try again in a minute.<br>${error.status} - ${error.message}`,
|
||||
title: 'Search Failed',
|
||||
type: 'danger'
|
||||
})
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ async function handleRequest(opts) {
|
|||
})
|
||||
}
|
||||
|
||||
export function alEntry(filemedia) {
|
||||
export function alEntry (filemedia) {
|
||||
if (filemedia.media && alToken && (filemedia.media.nextAiringEpisode?.episode || filemedia.media.episodes) <= filemedia.episodeNumber) {
|
||||
alRequest({ method: 'SearchIDStatus', id: filemedia.media.id }).then(res => {
|
||||
if ((res.errors && res.errors[0].status === 404) || res.data.MediaList.progress <= filemedia.episodeNumber || filemedia.episodes === 1) {
|
||||
|
|
@ -65,7 +65,7 @@ mutation ($id: Int, $status: MediaListStatus, $episode: Int, $repeat: Int) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function alRequest(opts) {
|
||||
export async function alRequest (opts) {
|
||||
let query
|
||||
const variables = {
|
||||
type: 'ANIME',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { add } from './torrent.js'
|
|||
import { DOMPARSER } from './util.js'
|
||||
import { alRequest } from './anilist.js'
|
||||
import anitomyscript from 'anitomyscript'
|
||||
import { addToast } from '@/lib/Toasts.svelte'
|
||||
|
||||
const torrentRx = /(^magnet:){1}|(^[A-F\d]{8,40}$){1}|(.*\.torrent$){1}/i
|
||||
const imageRx = /\.(jpeg|jpg|gif|png|webp)/i
|
||||
|
|
@ -145,12 +146,11 @@ export async function resolveFileMedia (opts) {
|
|||
}
|
||||
} else {
|
||||
console.log('error in parsing!', opts.media, tempMedia)
|
||||
// halfmoon.initStickyAlert({
|
||||
// content: `Failed resolving anime episode!<br>${opts.media.title.userPreferred} - ${epMax}`,
|
||||
// title: 'Parsing Error',
|
||||
// alertType: 'alert-secondary',
|
||||
// fillType: ''
|
||||
// })
|
||||
addToast({
|
||||
text: `Failed resolving anime episode!<br>${opts.media.title.userPreferred} - ${epMax}`,
|
||||
title: 'Parsing Error',
|
||||
type: 'secondary'
|
||||
})
|
||||
// something failed, most likely couldnt find an edge or processing failed, force episode number even if its invalid/out of bounds, better than nothing
|
||||
if (opts.episode.constructor === Array) {
|
||||
episode = `${Number(praseObj.episode_number[0])} ~ ${Number(praseObj.episode_number[praseObj.episode_number.length - 1])}`
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ client.on('torrent', torrent => {
|
|||
files.set(torrent.files)
|
||||
})
|
||||
|
||||
export async function add(torrentID, hide) {
|
||||
export async function add (torrentID, hide) {
|
||||
if (torrentID) {
|
||||
if (client.torrents.length) client.remove(client.torrents[0].infoHash)
|
||||
files.set([])
|
||||
|
|
|
|||
Loading…
Reference in a new issue