mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-07 04:19:24 +00:00
feat: nicer notifications
This commit is contained in:
parent
2597e00f45
commit
4ca90751e6
16 changed files with 114 additions and 168 deletions
|
|
@ -48,6 +48,7 @@
|
|||
"svelte-keybinds": "1.0.5",
|
||||
"svelte-loader": "^3.1.9",
|
||||
"svelte-miniplayer": "1.0.3",
|
||||
"svelte-sonner": "^0.1.1",
|
||||
"webpack": "^5.85.0",
|
||||
"webpack-cli": "^5.1.3",
|
||||
"webpack-dev-server": "^4.15.0",
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ devDependencies:
|
|||
svelte-miniplayer:
|
||||
specifier: 1.0.3
|
||||
version: 1.0.3
|
||||
svelte-sonner:
|
||||
specifier: ^0.1.1
|
||||
version: 0.1.1(svelte@4.0.4)
|
||||
webpack:
|
||||
specifier: ^5.85.0
|
||||
version: 5.86.0(webpack-cli@5.1.4)
|
||||
|
|
@ -5485,6 +5488,14 @@ packages:
|
|||
resolution: {integrity: sha512-++IvuENs/3x0SbHZ/jWNqfq+hmU/ZT73V/ETwn6TqCbHF7asXsZFxVcgyIL1lMaQMKxe227HrYghYRVNJXeFVw==}
|
||||
dev: true
|
||||
|
||||
/svelte-sonner@0.1.1(svelte@4.0.4):
|
||||
resolution: {integrity: sha512-jQ/coEZvJxImxxsT5FPnHeXitGx5wQRhAkAz6C8DY8yM1qFPvFowG6mDtC0KPPDEKlHCmocbWigk6zrG27OO/Q==}
|
||||
peerDependencies:
|
||||
svelte: ^4.0.0
|
||||
dependencies:
|
||||
svelte: 4.0.4
|
||||
dev: true
|
||||
|
||||
/svelte@4.0.4:
|
||||
resolution: {integrity: sha512-DDJavyX1mpNFLZ7jU9FwBKouemh6CJHZXwePBa5GXSaW5GuHZ361L2/1uznBqOCxu2UsUoWu8wRsB2iB8QG5sQ==}
|
||||
engines: {node: '>=16'}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
import ViewTrailer from './views/ViewAnime/ViewTrailer.svelte'
|
||||
import RSSView from './views/RSSView.svelte'
|
||||
import Menubar from './components/Menubar.svelte'
|
||||
import Toasts from './components/Toasts.svelte'
|
||||
import IspBlock from './views/IspBlock.svelte'
|
||||
import { Toaster, toast } from 'svelte-sonner'
|
||||
|
||||
setContext('view', view)
|
||||
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
</script>
|
||||
|
||||
<div id='player' />
|
||||
<Toasts />
|
||||
<Toaster visibleToasts={3} position='top-right' theme='dark' richColors duration={10000} />
|
||||
<div class='page-wrapper with-sidebar with-transitions bg-dark' data-sidebar-type='overlayed-all'>
|
||||
<div class='sticky-alerts' />
|
||||
<IspBlock />
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { alID } from '@/modules/anilist.js'
|
||||
import { media } from '../views/Player/MediaHandler.svelte'
|
||||
import { platformMap } from '../views/Settings.svelte'
|
||||
import { addToast } from './Toasts.svelte'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { click } from '@/modules/click.js'
|
||||
const view = getContext('view')
|
||||
export let page
|
||||
|
|
@ -17,11 +17,9 @@
|
|||
} else {
|
||||
window.IPC.emit('open', 'https://anilist.co/api/v2/oauth/authorize?client_id=4254&response_type=token') // Change redirect_url to miru://auth
|
||||
if (platformMap[window.version.platform] === 'Linux') {
|
||||
addToast({
|
||||
text: "If your linux distribution doesn't support custom protocol handlers, you can simply paste the full URL into the app.",
|
||||
title: 'Support Notification',
|
||||
type: 'secondary',
|
||||
duration: '300000'
|
||||
toast('Support Notification', {
|
||||
description: "If your linux distribution doesn't support custom protocol handlers, you can simply paste the full URL into the app.",
|
||||
duration: 300000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
<script context='module'>
|
||||
import { writable } from 'svelte/store'
|
||||
import { click } from '@/modules/click.js'
|
||||
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)
|
||||
}, opts.duration || 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} use:click={toast.click}>
|
||||
<button class='close' type='button' use: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;
|
||||
}
|
||||
.sticky-alerts {
|
||||
top: 2.5rem
|
||||
}
|
||||
|
||||
@keyframes fly-in {
|
||||
from {
|
||||
right: -50rem;
|
||||
}
|
||||
|
||||
to {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -28,6 +28,20 @@
|
|||
--dm-button-secondary-bg-color-hover: #ddd !important;
|
||||
}
|
||||
|
||||
[data-sonner-toaster][data-theme='dark'] {
|
||||
--normal-bg: var(--dark-color) !important;
|
||||
--normal-border: none !important;
|
||||
--normal-text: var(--dm-base-text-color) !important;
|
||||
|
||||
/* --success-bg: var(--success-color) !important; */
|
||||
--success-border: none !important;
|
||||
/* --success-text: var(--lm-base-text-color) !important; */
|
||||
|
||||
/* --error-bg: hsl(358, 76%, 10%); */
|
||||
--error-border: none !important;
|
||||
/* --error-text: hsl(358, 100%, 81%); */
|
||||
}
|
||||
|
||||
.material-symbols-outlined {
|
||||
font-family: "Material Symbols Outlined Variable";
|
||||
font-weight: normal;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { writable } from 'simple-store-svelte'
|
|||
import Bottleneck from 'bottleneck'
|
||||
|
||||
import { alToken } from '../views/Settings.svelte'
|
||||
import { addToast } from '../components/Toasts.svelte'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { sleep } from './util.js'
|
||||
|
||||
const codes = {
|
||||
|
|
@ -106,10 +106,8 @@ if (alToken) {
|
|||
|
||||
function printError (error) {
|
||||
console.warn(error)
|
||||
addToast({
|
||||
text: /* html */`Failed making request to anilist!<br>Try again in a minute.<br>${error.status || 429} - ${error.message || codes[error.status || 429]}`,
|
||||
title: 'Search Failed',
|
||||
type: 'danger',
|
||||
toast.error('Search Failed', {
|
||||
description: `Failed making request to anilist!\nTry again in a minute.\n${error.status || 429} - ${error.message || codes[error.status || 429]}`,
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { DOMPARSER, PromiseBatch, binarySearch } from './util.js'
|
|||
import { alRequest, alSearch } from './anilist.js'
|
||||
import anitomyscript from 'anitomyscript'
|
||||
import { media } from '../views/Player/MediaHandler.svelte'
|
||||
import { addToast } from '../components/Toasts.svelte'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { view } from '@/App.svelte'
|
||||
|
||||
import { playAnime } from '../views/RSSView.svelte'
|
||||
|
|
@ -15,7 +15,17 @@ window.addEventListener('paste', ({ clipboardData }) => { // WAIT image lookup o
|
|||
const item = clipboardData.items[0]
|
||||
if (!item) return
|
||||
const { type } = item
|
||||
if (type.startsWith('image')) return traceAnime(item.getAsFile())
|
||||
if (type.startsWith('image')) {
|
||||
const promise = traceAnime(item.getAsFile())
|
||||
toast.promise(promise, {
|
||||
description: 'You can also paste an URL to an image.',
|
||||
loading: 'Looking up anime for image...',
|
||||
success: 'Found anime for image!',
|
||||
error: 'Couldn\'t find anime for specified image! Try to remove black bars, or use a more detailed image.'
|
||||
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!type.startsWith('text')) return
|
||||
item.getAsString(text => {
|
||||
if (torrentRx.exec(text)) {
|
||||
|
|
@ -28,26 +38,19 @@ window.addEventListener('paste', ({ clipboardData }) => { // WAIT image lookup o
|
|||
} else if (imageRx.exec(text)) {
|
||||
src = text
|
||||
}
|
||||
if (src) traceAnime(src)
|
||||
if (src) {
|
||||
const promise = traceAnime(src)
|
||||
toast.promise(promise, {
|
||||
description: 'You can also paste an URL to an image.',
|
||||
loading: 'Looking up anime for image...',
|
||||
success: 'Found anime for image!',
|
||||
error: 'Couldn\'t find anime for specified image! Try to remove black bars, or use a more detailed image.'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
export async function traceAnime (image) { // WAIT lookup logic
|
||||
if (image instanceof Blob) {
|
||||
const reader = new FileReader()
|
||||
reader.onload = e => {
|
||||
addToast({
|
||||
title: 'Looking up anime for image',
|
||||
text: /* html */`You can also paste an URL to an image!<br><img class="w-200 rounded pt-5" src="${e.target.result}">`
|
||||
})
|
||||
}
|
||||
reader.readAsDataURL(image)
|
||||
} else {
|
||||
addToast({
|
||||
title: 'Looking up anime for image',
|
||||
text: /* html */`<img class="w-200 rounded pt-5" src="${image}">`
|
||||
})
|
||||
}
|
||||
let options
|
||||
let url = `https://api.trace.moe/search?cutBorders&url=${image}`
|
||||
if (image instanceof Blob) {
|
||||
|
|
@ -60,14 +63,12 @@ export async function traceAnime (image) { // WAIT lookup logic
|
|||
}
|
||||
const res = await fetch(url, options)
|
||||
const { result } = await res.json()
|
||||
if (result && result[0].similarity >= 0.85) {
|
||||
if (result?.[0].similarity >= 0.85) {
|
||||
const res = await alRequest({ method: 'SearchIDSingle', id: result[0].anilist })
|
||||
view.set(res.data.Media)
|
||||
} else {
|
||||
addToast({
|
||||
text: 'Couldn\'t find anime for specified image! Try to remove black bars, or use a more detailed image.',
|
||||
title: 'Search Failed',
|
||||
type: 'danger'
|
||||
throw new Error('Search Failed', {
|
||||
message: 'Couldn\'t find anime for specified image! Try to remove black bars, or use a more detailed image.'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -315,10 +316,8 @@ export async function resolveSeason (opts) {
|
|||
const obj = { media, episode: episode - offset, offset, increment, rootMedia, failed: true }
|
||||
if (!force) {
|
||||
console.warn('Error in parsing!', obj)
|
||||
addToast({
|
||||
text: /* html */`Failed resolving anime episode!<br>${media.title.userPreferred} - ${episode - offset}`,
|
||||
title: 'Parsing Error',
|
||||
type: 'secondary'
|
||||
toast('Parsing Error', {
|
||||
description: `Failed resolving anime episode!\n${media.title.userPreferred} - ${episode - offset}`
|
||||
})
|
||||
}
|
||||
return obj
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ export default async function tosho ({ media, episode }) {
|
|||
found.seeders = complete
|
||||
}
|
||||
|
||||
if (!mapped?.length) throw new Error('no entries found')
|
||||
|
||||
return mapped
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { DOMPARSER } from '@/modules/util.js'
|
||||
import { set } from '@/views/Settings.svelte'
|
||||
import { addToast } from '@/components/Toasts.svelte'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { add } from '@/modules/torrent.js'
|
||||
import { resolveFileMedia, getEpisodeMetadataForMedia } from './anime.js'
|
||||
import { hasNextPage } from '@/modules/sections.js'
|
||||
|
|
@ -49,19 +49,15 @@ export async function getRSSContent (url) {
|
|||
try {
|
||||
const res = await fetch(url)
|
||||
if (!res.ok) {
|
||||
addToast({
|
||||
text: 'Failed fetching RSS!<br>' + res.statusText,
|
||||
title: 'Search Failed',
|
||||
type: 'danger'
|
||||
toast.error('Search Failed', {
|
||||
description: 'Failed fetching RSS!\n' + res.statusText
|
||||
})
|
||||
console.error('Failed to fetch rss', res.statusText)
|
||||
}
|
||||
return DOMPARSER(await res.text(), 'text/xml')
|
||||
} catch (e) {
|
||||
addToast({
|
||||
text: 'Failed fetching RSS!<br>' + e.message,
|
||||
title: 'Search Failed',
|
||||
type: 'danger'
|
||||
toast.error('Search Failed', {
|
||||
description: 'Failed fetching RSS!\n' + e.message
|
||||
})
|
||||
console.error('Failed to fetch rss', e)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { set } from '@/views/Settings.svelte'
|
||||
|
||||
export default function scroll (t, { speed = 120, smooth = 10 } = {}) {
|
||||
export default function (t, { speed = 120, smooth = 10 } = {}) {
|
||||
if (!set.smoothScroll) return
|
||||
let moving = false
|
||||
let pos = 0
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import { alEntry } from '@/modules/anilist.js'
|
||||
import Subtitles from '@/modules/subtitles.js'
|
||||
import { toTS, videoRx, fastPrettyBytes } from '@/modules/util.js'
|
||||
import { addToast } from '../../components/Toasts.svelte'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { getChaptersAniSkip } from '@/modules/anime.js'
|
||||
import Seekbar from 'perfect-seekbar'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
|
@ -71,10 +71,8 @@
|
|||
function checkAudio () {
|
||||
if ('audioTracks' in HTMLVideoElement.prototype) {
|
||||
if (!video.audioTracks.length) {
|
||||
addToast({
|
||||
text: "This torrent's audio codec is not supported, try a different release by disabling Autoplay Torrents in RSS settings.",
|
||||
title: 'Audio Codec Unsupported',
|
||||
type: 'danger'
|
||||
toast.error('Audio Codec Unsupported', {
|
||||
description: "This torrent's audio codec is not supported, try a different release by disabling Autoplay Torrents in RSS settings."
|
||||
})
|
||||
} else if (video.audioTracks.length > 1) {
|
||||
const preferredTrack = [...video.audioTracks].find(({ language }) => language === set.audioLanguage)
|
||||
|
|
@ -335,10 +333,8 @@
|
|||
})
|
||||
])
|
||||
canvas.remove()
|
||||
addToast({
|
||||
text: 'Saved screenshot to clipboard.',
|
||||
title: 'Screenshot',
|
||||
type: 'success'
|
||||
toast.success('Screenshot', {
|
||||
description: 'Saved screenshot to clipboard.'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -830,31 +826,25 @@
|
|||
break
|
||||
case target.error.MEDIA_ERR_NETWORK:
|
||||
console.warn('A network error caused the video download to fail part-way.', target.error)
|
||||
addToast({
|
||||
text: 'A network error caused the video download to fail part-way. Click here to reload the video.',
|
||||
title: 'Video Network Error',
|
||||
type: 'danger',
|
||||
toast.error('Video Network Error', {
|
||||
description: 'A network error caused the video download to fail part-way. Click here to reload the video.',
|
||||
duration: 1000000,
|
||||
click: () => target.load()
|
||||
onClick: () => target.load()
|
||||
})
|
||||
break
|
||||
case target.error.MEDIA_ERR_DECODE:
|
||||
console.warn('The video playback was aborted due to a corruption problem or because the video used features your browser did not support.', target.error)
|
||||
addToast({
|
||||
text: 'The video playback was aborted due to a corruption problem. Click here to reload the video.',
|
||||
title: 'Video Decode Error',
|
||||
type: 'danger',
|
||||
toast.error('Video Decode Error', {
|
||||
description: 'The video playback was aborted due to a corruption problem. Click here to reload the video.',
|
||||
duration: 1000000,
|
||||
click: () => target.load()
|
||||
onClick: () => target.load()
|
||||
})
|
||||
break
|
||||
case target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
|
||||
if (target.error.message !== 'MEDIA_ELEMENT_ERROR: Empty src attribute') {
|
||||
console.warn('The video could not be loaded, either because the server or network failed or because the format is not supported.', target.error)
|
||||
addToast({
|
||||
text: 'The video could not be loaded, either because the server or network failed or because the format is not supported. Try a different release by disabling Autoplay Torrents in RSS settings.',
|
||||
title: 'Video Codec Unsupported',
|
||||
type: 'danger',
|
||||
toast.error('Video Codec Unsupported', {
|
||||
description: 'The video could not be loaded, either because the server or network failed or because the format is not supported. Try a different release by disabling Autoplay Torrents in RSS settings.',
|
||||
duration: 300000
|
||||
})
|
||||
}
|
||||
|
|
@ -881,8 +871,7 @@
|
|||
on:keypress={resetImmerse}
|
||||
on:mouseleave={immersePlayer}>
|
||||
{#if showKeybinds && !miniplayer}
|
||||
<div class='position-absolute bg-tp w-full h-full z-50 font-size-12 p-20 d-flex align-items-center justify-content-center'>
|
||||
<button class='btn btn-square rounded-circle bg-dark font-size-16 top-0 right-0 m-10 position-absolute' type='button' use:click={() => (showKeybinds = false)}>×</button>
|
||||
<div class='position-absolute bg-tp w-full h-full z-50 font-size-12 p-20 d-flex align-items-center justify-content-center pointer' on:pointerup|self={() => (showKeybinds = false)} tabindex='-1' role='button'>
|
||||
<Keybinds let:prop={item} autosave={true} clickable={true}>
|
||||
<div class:material-symbols-outlined={item?.type} class='bind'>{item?.id || ''}</div>
|
||||
</Keybinds>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script context='module'>
|
||||
import { since } from '@/modules/util.js'
|
||||
import { set } from './Settings.svelte'
|
||||
import { addToast } from '../components/Toasts.svelte'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { findInCurrent } from './Player/MediaHandler.svelte'
|
||||
import getRSSEntries from '@/modules/providers/tosho.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
|
@ -73,15 +73,19 @@
|
|||
|
||||
async function loadRss ({ media, episode }) {
|
||||
if (!media) return
|
||||
const entries = await getRSSEntries({ media, episode })
|
||||
if (!entries?.length) {
|
||||
addToast({
|
||||
text: /* html */`Couldn't find torrent for ${media.title.userPreferred} Episode ${parseInt(episode)}! Try specifying a torrent manually.`,
|
||||
title: 'Search Failed',
|
||||
type: 'danger'
|
||||
})
|
||||
return
|
||||
const promise = getRSSEntries({ media, episode })
|
||||
toast.promise(promise, {
|
||||
loading: `Looking for torrents for ${media.title.userPreferred} Episode ${parseInt(episode)}...`,
|
||||
success: `Found torrents for ${media.title.userPreferred} Episode ${parseInt(episode)}.`,
|
||||
error: `Couldn't find torrents for ${media.title.userPreferred} Episode ${parseInt(episode)}! Try specifying a torrent manually.`
|
||||
})
|
||||
let entries
|
||||
try {
|
||||
entries = await promise
|
||||
} catch (e) {
|
||||
return e
|
||||
}
|
||||
|
||||
entries.sort((a, b) => b.seeders - a.seeders)
|
||||
if (settings.rssAutoplay) {
|
||||
const best = entries.find(entry => entry.best)
|
||||
|
|
@ -103,10 +107,8 @@
|
|||
function play (entry) {
|
||||
$media = $rss
|
||||
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'
|
||||
toast('Availability Warning', {
|
||||
description: 'This release is poorly seeded and likely will have playback issues such as buffering!'
|
||||
})
|
||||
}
|
||||
add(entry.link)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script context='module'>
|
||||
import { addToast } from '../components/Toasts.svelte'
|
||||
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { click } from '@/modules/click.js'
|
||||
export let alToken = localStorage.getItem('ALtoken') || null
|
||||
const defaults = {
|
||||
|
|
@ -64,17 +65,14 @@
|
|||
window.IPC.on('update-available', () => {
|
||||
if (!wasUpdated) {
|
||||
wasUpdated = true
|
||||
addToast({
|
||||
title: 'Auto Updater',
|
||||
text: 'A new version of Miru is available. Downloading!'
|
||||
toast('Auto Updater', {
|
||||
description: 'A new version of Miru is available. Downloading!'
|
||||
})
|
||||
}
|
||||
})
|
||||
window.IPC.on('update-downloaded', () => {
|
||||
addToast({
|
||||
title: 'Auto Updater',
|
||||
text: 'A new version of Miru has downloaded. You can restart to update!',
|
||||
type: 'success'
|
||||
toast.success('Auto Updater', {
|
||||
description: 'A new version of Miru has downloaded. You can restart to update!'
|
||||
})
|
||||
})
|
||||
function checkUpdate () {
|
||||
|
|
@ -158,10 +156,8 @@
|
|||
}
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
addToast({
|
||||
text: /* html */`${error.message}<br>Try using a different font.`,
|
||||
title: 'File Error',
|
||||
type: 'secondary',
|
||||
toast.error('File Error', {
|
||||
description: `${error.message}<br>Try using a different font.`,
|
||||
duration: 8000
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { getContext, setStatus } from 'svelte'
|
||||
import { getMediaMaxEp, formatMap, playMedia } from '@/modules/anime.js'
|
||||
import { playAnime } from '../RSSView.svelte'
|
||||
import { addToast } from '../../components/Toasts.svelte'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { alRequest } from '@/modules/anilist.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
import Details from './Details.svelte'
|
||||
|
|
@ -64,11 +64,9 @@
|
|||
}
|
||||
function copyToClipboard (text) {
|
||||
navigator.clipboard.writeText(text)
|
||||
addToast({
|
||||
title: 'Copied to clipboard',
|
||||
text: 'Copied share URL to clipboard',
|
||||
type: 'primary',
|
||||
duration: '5000'
|
||||
toast('Copied to clipboard', {
|
||||
description: 'Copied share URL to clipboard',
|
||||
duration: 5000
|
||||
})
|
||||
}
|
||||
function openInBrowser (url) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { alID } from '@/modules/anilist.js'
|
||||
import { add, client } from '@/modules/torrent.js'
|
||||
import { generateRandomHexCode } from '@/modules/util.js'
|
||||
import { addToast } from '../../components/Toasts.svelte'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { page } from '@/App.svelte'
|
||||
import P2PT from 'p2pt'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
|
@ -148,11 +148,9 @@
|
|||
function invite () {
|
||||
if (p2pt) {
|
||||
navigator.clipboard.writeText(`https://miru.watch/w2g/${p2pt.identifierString}`)
|
||||
addToast({
|
||||
title: 'Copied to clipboard',
|
||||
text: 'Copied invite URL to clipboard',
|
||||
type: 'primary',
|
||||
duration: '5000'
|
||||
toast('Copied to clipboard', {
|
||||
description: 'Copied invite URL to clipboard',
|
||||
duration: 5000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue