mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-21 07:42:02 +00:00
perf: insanely faster main menu loading
This commit is contained in:
parent
73ba8ed623
commit
bd18755b48
3 changed files with 179 additions and 112 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Miru",
|
"name": "Miru",
|
||||||
"version": "3.4.1",
|
"version": "3.4.2",
|
||||||
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
|
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
|
||||||
"description": "Stream anime torrents, real-time with no waiting for downloads.",
|
"description": "Stream anime torrents, real-time with no waiting for downloads.",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
<script context='module'>
|
<script context='module'>
|
||||||
import { readable } from 'svelte/store'
|
import { readable } from 'svelte/store'
|
||||||
|
import { add } from '@/modules/torrent.js'
|
||||||
|
import { alToken, set } from '../Settings.svelte'
|
||||||
|
import { alRequest, alID } from '@/modules/anilist.js'
|
||||||
|
import { sleep } from '@/modules/util.js'
|
||||||
|
import { resolveFileMedia } from '@/modules/anime.js'
|
||||||
|
import { getRSSContent, getReleasesRSSurl } from '@/lib/RSSView.svelte'
|
||||||
const noop = () => {}
|
const noop = () => {}
|
||||||
async function getVal (set) {
|
async function getVal (set) {
|
||||||
const res = await fetch('https://gh.miru.workers.dev/')
|
const res = await fetch('https://gh.miru.workers.dev/')
|
||||||
|
|
@ -10,27 +16,39 @@
|
||||||
getVal(set)
|
getVal(set)
|
||||||
return noop
|
return noop
|
||||||
})
|
})
|
||||||
</script>
|
const getSeason = d => seasons[Math.floor((d.getMonth() / 12) * 4) % 4]
|
||||||
|
|
||||||
<script>
|
|
||||||
import Search from './Search.svelte'
|
|
||||||
import Section from './Section.svelte'
|
|
||||||
import Gallery from './Gallery.svelte'
|
|
||||||
import { add } from '@/modules/torrent.js'
|
|
||||||
import { alToken, set } from '../Settings.svelte'
|
|
||||||
import { alRequest, alID } from '@/modules/anilist.js'
|
|
||||||
import { resolveFileMedia } from '@/modules/anime.js'
|
|
||||||
import { getRSSContent, getReleasesRSSurl } from '@/lib/RSSView.svelte'
|
|
||||||
|
|
||||||
let media = []
|
|
||||||
let search = {}
|
|
||||||
export let current = null
|
|
||||||
let page = 1
|
|
||||||
|
|
||||||
let canScroll = true
|
|
||||||
let hasNext = true
|
let hasNext = true
|
||||||
let container = null
|
function processMedia (res) {
|
||||||
|
hasNext = res?.data?.Page.pageInfo.hasNextPage
|
||||||
|
return res?.data?.Page.media.map(media => {
|
||||||
|
return { media }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let search = {}
|
||||||
|
let lastRSSDate = 0
|
||||||
|
async function releasesCards (page, limit, force, val) {
|
||||||
|
const doc = await getRSSContent(getReleasesRSSurl(val))
|
||||||
|
if (doc) {
|
||||||
|
const pubDate = doc.querySelector('pubDate').textContent
|
||||||
|
if (force || lastRSSDate !== pubDate) {
|
||||||
|
lastRSSDate = pubDate
|
||||||
|
const index = (page - 1) * limit
|
||||||
|
const items = [...doc.querySelectorAll('item')].slice(index, index + limit)
|
||||||
|
hasNext = items.length === limit
|
||||||
|
const media = await resolveFileMedia(items.map(item => item.querySelector('title').textContent))
|
||||||
|
media.forEach((mediaInformation, index) => {
|
||||||
|
mediaInformation.onclick = () => {
|
||||||
|
add(items[index].querySelector('link').textContent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
media.hasNext = hasNext
|
||||||
|
return media
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const seasons = ['WINTER', 'SPRING', 'SUMMER', 'FALL']
|
||||||
function sanitiseObject (object) {
|
function sanitiseObject (object) {
|
||||||
const safe = {}
|
const safe = {}
|
||||||
for (const [key, value] of Object.entries(object)) {
|
for (const [key, value] of Object.entries(object)) {
|
||||||
|
|
@ -57,80 +75,14 @@
|
||||||
return condition
|
return condition
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
async function infiniteScroll () {
|
|
||||||
if (current && canScroll && hasNext && this.scrollTop + this.clientHeight > this.scrollHeight - 800) {
|
|
||||||
canScroll = false
|
|
||||||
const res = sections[current].load(++page)
|
|
||||||
media.push(res)
|
|
||||||
media = media
|
|
||||||
await res
|
|
||||||
canScroll = hasNext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadCurrent (initial = true) {
|
|
||||||
page = 1
|
|
||||||
canScroll = false
|
|
||||||
const res = sections[current].load(1, 50, initial)
|
|
||||||
media = [res]
|
|
||||||
await res
|
|
||||||
canScroll = hasNext
|
|
||||||
}
|
|
||||||
|
|
||||||
$: load(current)
|
|
||||||
async function load (current) {
|
|
||||||
if (sections[current]) {
|
|
||||||
loadCurrent()
|
|
||||||
} else {
|
|
||||||
if (container) container.scrollTop = 0
|
|
||||||
media = []
|
|
||||||
canScroll = true
|
|
||||||
lastDate = null
|
|
||||||
search = {
|
|
||||||
format: '',
|
|
||||||
genre: '',
|
|
||||||
season: '',
|
|
||||||
sort: '',
|
|
||||||
status: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let lastDate = null
|
let lastDate = null
|
||||||
|
|
||||||
function processMedia (res) {
|
|
||||||
hasNext = res?.data?.Page.pageInfo.hasNextPage
|
|
||||||
return res?.data?.Page.media.map(media => {
|
|
||||||
return { media }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let lastRSSDate = 0
|
|
||||||
async function releasesCards (page, limit, force, val) {
|
|
||||||
const doc = await getRSSContent(getReleasesRSSurl(val))
|
|
||||||
if (doc) {
|
|
||||||
const pubDate = doc.querySelector('pubDate').textContent
|
|
||||||
if (force || lastRSSDate !== pubDate) {
|
|
||||||
lastRSSDate = pubDate
|
|
||||||
const index = (page - 1) * limit
|
|
||||||
const items = [...doc.querySelectorAll('item')].slice(index, index + limit)
|
|
||||||
hasNext = items.length === limit
|
|
||||||
const media = await resolveFileMedia(items.map(item => item.querySelector('title').textContent))
|
|
||||||
media.forEach((mediaInformation, index) => {
|
|
||||||
mediaInformation.onclick = () => {
|
|
||||||
add(items[index].querySelector('link').textContent)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
media.hasNext = hasNext
|
|
||||||
return media
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const seasons = ['WINTER', 'SPRING', 'SUMMER', 'FALL']
|
|
||||||
const getSeason = d => seasons[Math.floor((d.getMonth() / 12) * 4) % 4]
|
|
||||||
let sections = {
|
let sections = {
|
||||||
continue: {
|
continue: {
|
||||||
title: 'Continue Watching',
|
title: 'Continue Watching',
|
||||||
|
preview: () => {
|
||||||
|
return sections.continue.load(1, 6)
|
||||||
|
},
|
||||||
load: (page = 1, perPage = 50, initial = false) => {
|
load: (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) search.sort = 'UPDATED_TIME_DESC'
|
if (initial) search.sort = 'UPDATED_TIME_DESC'
|
||||||
return alRequest({ method: 'UserLists', status_in: ['CURRENT', 'REPEATING'], page }).then(res => {
|
return alRequest({ method: 'UserLists', status_in: ['CURRENT', 'REPEATING'], page }).then(res => {
|
||||||
|
|
@ -148,6 +100,9 @@
|
||||||
},
|
},
|
||||||
planning: {
|
planning: {
|
||||||
title: 'Your List',
|
title: 'Your List',
|
||||||
|
preview: () => {
|
||||||
|
return sections.planning.load(1, 6)
|
||||||
|
},
|
||||||
load: (page = 1, perPage = 50, initial = false) => {
|
load: (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) search.sort = 'UPDATED_TIME_DESC'
|
if (initial) search.sort = 'UPDATED_TIME_DESC'
|
||||||
return alRequest({ method: 'UserLists', page, perPage, status_in: 'PLANNING' }).then(res => {
|
return alRequest({ method: 'UserLists', page, perPage, status_in: 'PLANNING' }).then(res => {
|
||||||
|
|
@ -159,6 +114,13 @@
|
||||||
},
|
},
|
||||||
trending: {
|
trending: {
|
||||||
title: 'Trending Now',
|
title: 'Trending Now',
|
||||||
|
preview: () => {
|
||||||
|
const self = sections.trending
|
||||||
|
if (!self.previewData) {
|
||||||
|
self.previewData = self.load(1, 6)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
},
|
||||||
load: async (page = 1, perPage = 50, initial = false) => {
|
load: async (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) search.sort = 'TRENDING_DESC'
|
if (initial) search.sort = 'TRENDING_DESC'
|
||||||
await alID
|
await alID
|
||||||
|
|
@ -167,6 +129,13 @@
|
||||||
},
|
},
|
||||||
seasonal: {
|
seasonal: {
|
||||||
title: 'Popular This Season',
|
title: 'Popular This Season',
|
||||||
|
preview: () => {
|
||||||
|
const self = sections.seasonal
|
||||||
|
if (!self.previewData) {
|
||||||
|
self.previewData = self.load(1, 6)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
},
|
||||||
load: async (page = 1, perPage = 50, initial = false) => {
|
load: async (page = 1, perPage = 50, initial = false) => {
|
||||||
const date = new Date()
|
const date = new Date()
|
||||||
if (initial) {
|
if (initial) {
|
||||||
|
|
@ -182,6 +151,13 @@
|
||||||
},
|
},
|
||||||
popular: {
|
popular: {
|
||||||
title: 'All Time Popular',
|
title: 'All Time Popular',
|
||||||
|
preview: () => {
|
||||||
|
const self = sections.popular
|
||||||
|
if (!self.previewData) {
|
||||||
|
self.previewData = self.load(1, 6)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
},
|
||||||
load: async (page = 1, perPage = 50, initial = false) => {
|
load: async (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) search.sort = 'POPULARITY_DESC'
|
if (initial) search.sort = 'POPULARITY_DESC'
|
||||||
await alID
|
await alID
|
||||||
|
|
@ -190,6 +166,13 @@
|
||||||
},
|
},
|
||||||
romance: {
|
romance: {
|
||||||
title: 'Romance',
|
title: 'Romance',
|
||||||
|
preview: () => {
|
||||||
|
const self = sections.romance
|
||||||
|
if (!self.previewData) {
|
||||||
|
self.previewData = self.load(1, 6)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
},
|
||||||
load: async (page = 1, perPage = 50, initial = false) => {
|
load: async (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) {
|
if (initial) {
|
||||||
search.sort = 'TRENDING_DESC'
|
search.sort = 'TRENDING_DESC'
|
||||||
|
|
@ -201,6 +184,13 @@
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
title: 'Action',
|
title: 'Action',
|
||||||
|
preview: () => {
|
||||||
|
const self = sections.action
|
||||||
|
if (!self.previewData) {
|
||||||
|
self.previewData = self.load(1, 6)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
},
|
||||||
load: async (page = 1, perPage = 50, initial = false) => {
|
load: async (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) {
|
if (initial) {
|
||||||
search.sort = 'TRENDING_DESC'
|
search.sort = 'TRENDING_DESC'
|
||||||
|
|
@ -212,6 +202,13 @@
|
||||||
},
|
},
|
||||||
adventure: {
|
adventure: {
|
||||||
title: 'Adventure',
|
title: 'Adventure',
|
||||||
|
preview: () => {
|
||||||
|
const self = sections.adventure
|
||||||
|
if (!self.previewData) {
|
||||||
|
self.previewData = self.load(1, 6)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
},
|
||||||
load: async (page = 1, perPage = 50, initial = false) => {
|
load: async (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) {
|
if (initial) {
|
||||||
search.sort = 'TRENDING_DESC'
|
search.sort = 'TRENDING_DESC'
|
||||||
|
|
@ -223,6 +220,13 @@
|
||||||
},
|
},
|
||||||
fantasy: {
|
fantasy: {
|
||||||
title: 'Fantasy',
|
title: 'Fantasy',
|
||||||
|
preview: () => {
|
||||||
|
const self = sections.fantasy
|
||||||
|
if (!self.previewData) {
|
||||||
|
self.previewData = self.load(1, 6)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
},
|
||||||
load: async (page = 1, perPage = 50, initial = false) => {
|
load: async (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) {
|
if (initial) {
|
||||||
search.sort = 'TRENDING_DESC'
|
search.sort = 'TRENDING_DESC'
|
||||||
|
|
@ -234,6 +238,13 @@
|
||||||
},
|
},
|
||||||
comedy: {
|
comedy: {
|
||||||
title: 'Comedy',
|
title: 'Comedy',
|
||||||
|
preview: () => {
|
||||||
|
const self = sections.comedy
|
||||||
|
if (!self.previewData) {
|
||||||
|
self.previewData = self.load(1, 6)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
},
|
||||||
load: async (page = 1, perPage = 50, initial = false) => {
|
load: async (page = 1, perPage = 50, initial = false) => {
|
||||||
if (initial) {
|
if (initial) {
|
||||||
search.sort = 'TRENDING_DESC'
|
search.sort = 'TRENDING_DESC'
|
||||||
|
|
@ -284,22 +295,90 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let i = 0; i < set.rssFeeds.length; ++i) {
|
for (let i = set.rssFeeds.length - 1; i >= 0; --i) {
|
||||||
const [title, val] = set.rssFeeds[i]
|
const [title, val] = set.rssFeeds[i]
|
||||||
sections = {
|
const section = {
|
||||||
['releases-' + i]: {
|
title,
|
||||||
title,
|
load: async (page = 1, perPage = 20, initial = false, force = true) => {
|
||||||
releases: true,
|
if (initial) search.sort = 'START_DATE_DESC'
|
||||||
load: async (page = 1, perPage = 20, initial = false, force = true) => {
|
return customFilter(await releasesCards(page, Math.min(perPage, 13), force, val))
|
||||||
if (initial) search.sort = 'START_DATE_DESC'
|
|
||||||
return customFilter(await releasesCards(page, Math.min(perPage, 13), force, val))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
preview: async () => {
|
||||||
|
const self = sections['releases-' + i]
|
||||||
|
if (!self.previewData) {
|
||||||
|
await sleep(i * 3000) // stagger lists by 3 seconds
|
||||||
|
self.previewData = self.load(1, 6, false, false)
|
||||||
|
setInterval(async () => {
|
||||||
|
const newData = await self.load(1, 6, false, false)
|
||||||
|
if (newData) self.previewData = newData
|
||||||
|
}, 15000)
|
||||||
|
}
|
||||||
|
return self.previewData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sections = {
|
||||||
|
['releases-' + i]: section,
|
||||||
...sections
|
...sections
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Search from './Search.svelte'
|
||||||
|
import Section from './Section.svelte'
|
||||||
|
import Gallery from './Gallery.svelte'
|
||||||
|
|
||||||
|
let media = []
|
||||||
|
export let current = null
|
||||||
|
let page = 1
|
||||||
|
|
||||||
|
let canScroll = true
|
||||||
|
let container = null
|
||||||
|
|
||||||
|
function infiniteScroll () {
|
||||||
|
if (current && canScroll && hasNext && this.scrollTop + this.clientHeight > this.scrollHeight - 800) {
|
||||||
|
infiniteScrollLoad()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function infiniteScrollLoad () {
|
||||||
|
canScroll = false
|
||||||
|
const res = sections[current].load(++page)
|
||||||
|
media.push(res)
|
||||||
|
media = media
|
||||||
|
await res
|
||||||
|
canScroll = hasNext
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadCurrent (initial = true) {
|
||||||
|
page = 1
|
||||||
|
canScroll = false
|
||||||
|
const res = sections[current].load(1, 50, initial)
|
||||||
|
media = [res]
|
||||||
|
await res
|
||||||
|
canScroll = hasNext
|
||||||
|
if ((await res).length < 12 && hasNext) infiniteScrollLoad()
|
||||||
|
}
|
||||||
|
|
||||||
|
$: load(current)
|
||||||
|
async function load (current) {
|
||||||
|
if (sections[current]) {
|
||||||
|
loadCurrent()
|
||||||
|
} else {
|
||||||
|
if (container) container.scrollTop = 0
|
||||||
|
media = []
|
||||||
|
canScroll = true
|
||||||
|
lastDate = null
|
||||||
|
search = {
|
||||||
|
format: '',
|
||||||
|
genre: '',
|
||||||
|
season: '',
|
||||||
|
sort: '',
|
||||||
|
status: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<div class='d-flex h-full flex-column overflow-y-scroll root' on:scroll={infiniteScroll} bind:this={container}>
|
<div class='d-flex h-full flex-column overflow-y-scroll root' on:scroll={infiniteScroll} bind:this={container}>
|
||||||
<div class='h-full py-10'>
|
<div class='h-full py-10'>
|
||||||
<Search bind:media bind:search bind:current {loadCurrent} />
|
<Search bind:media bind:search bind:current {loadCurrent} />
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { onDestroy } from 'svelte'
|
import Cards from './Cards.svelte'
|
||||||
|
export let opts
|
||||||
import Cards from './Cards.svelte'
|
const cards = opts.preview()
|
||||||
export let opts
|
|
||||||
let cards = opts.load(1, 6)
|
|
||||||
let interval = null
|
|
||||||
if (opts.releases) {
|
|
||||||
interval = setInterval(async () => {
|
|
||||||
const media = await opts.load(1, 6, false, false)
|
|
||||||
if (media) cards = media
|
|
||||||
}, 30000)
|
|
||||||
}
|
|
||||||
onDestroy(() => {
|
|
||||||
if (interval) clearInterval(interval)
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span class='d-flex px-20 align-items-end pointer text-decoration-none text-muted' on:click={opts.onclick}>
|
<span class='d-flex px-20 align-items-end pointer text-decoration-none text-muted' on:click={opts.onclick}>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue