mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-03-29 08:08:42 +00:00
feat: new better RSS View
This commit is contained in:
parent
4e68d5349f
commit
1dd08046d8
6 changed files with 129 additions and 36 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Miru",
|
||||
"version": "4.1.14",
|
||||
"version": "4.1.15",
|
||||
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
|
||||
"description": "Stream anime torrents, real-time with no waiting for downloads.",
|
||||
"main": "build/main.js",
|
||||
|
|
|
|||
|
|
@ -21,8 +21,11 @@
|
|||
--gray-color-light: hsl(var(--gray-color-light-hsl));
|
||||
--gray-color-light-hsl: var(--gray-color-base-hue), 10%, 28%;
|
||||
--gray-color-base-hue: 216;
|
||||
--secondary-color: #fff;
|
||||
--secondary-color-light: #ddd;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
--dm-button-secondary-bg-color: #fff !important;
|
||||
--dm-button-secondary-bg-color-hover: #ddd !important;
|
||||
}
|
||||
|
||||
.material-symbols-outlined {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { fastPrettyBytes } from '../util.js'
|
|||
import { exclusions } from '../rss.js'
|
||||
import { set } from '@/views/Settings.svelte'
|
||||
import { alRequest } from '../anilist.js'
|
||||
import anitomyscript from 'anitomyscript'
|
||||
|
||||
export default async function tosho ({ media, episode }) {
|
||||
const json = await getAniDBFromAL(media)
|
||||
|
|
@ -17,7 +18,13 @@ export default async function tosho ({ media, episode }) {
|
|||
|
||||
if (!entries.length && !movie) entries = await getToshoEntries(media, aniDBEpisode, json)
|
||||
|
||||
return mapBestRelease(mapTosho2dDeDupedEntry(entries))
|
||||
const mapped = mapBestRelease(mapTosho2dDeDupedEntry(entries))
|
||||
|
||||
const parseObjects = await anitomyscript(mapped.map(({ title }) => title))
|
||||
|
||||
for (const i in parseObjects) mapped[i].parseObject = parseObjects[i]
|
||||
|
||||
return mapped
|
||||
}
|
||||
|
||||
window.tosho = tosho
|
||||
|
|
@ -100,7 +107,7 @@ async function getToshoEntries (media, episode, { mappings }, quality) {
|
|||
// look for batches and movies
|
||||
const movie = isMovie(media)
|
||||
if (mappings.anidb_id && media.status === 'FINISHED' && (movie || media.episodes !== 1)) {
|
||||
promises.push(fetchBatches({ episodeCount: media.episodes, id: mappings.anidb_id, quality }))
|
||||
promises.push(fetchBatches({ episodeCount: media.episodes, id: mappings.anidb_id, quality, movie }))
|
||||
console.log('fetching batch', quality, movie)
|
||||
if (!movie) {
|
||||
const courRelation = getSplitCourRelation(media)
|
||||
|
|
@ -204,12 +211,17 @@ function buildQuery (quality) {
|
|||
return query
|
||||
}
|
||||
|
||||
async function fetchBatches ({ episodeCount, id, quality }) {
|
||||
async function fetchBatches ({ episodeCount, id, quality, movie }) {
|
||||
const queryString = buildQuery(quality)
|
||||
const torrents = await fetch(set.toshoURL + 'json?order=size-d&aid=' + id + queryString)
|
||||
|
||||
// safe if AL includes EP 0 or doesn't
|
||||
const batches = (await torrents.json()).filter(entry => entry.num_files >= episodeCount)
|
||||
if (!movie) {
|
||||
for (const batch of batches) {
|
||||
batch.batch = true
|
||||
}
|
||||
}
|
||||
console.log({ batches })
|
||||
return batches
|
||||
}
|
||||
|
|
@ -234,6 +246,7 @@ function mapTosho2dDeDupedEntry (entries) {
|
|||
dupe.leechers ||= entry.leechers >= 100000 ? 0 : entry.leechers
|
||||
dupe.downloads ||= entry.torrent_downloaded_count
|
||||
dupe.size ||= entry.total_size && fastPrettyBytes(entry.total_size)
|
||||
dupe.verified ||= !!entry.anidb_fid
|
||||
dupe.date ||= entry.timestamp && new Date(entry.timestamp * 1000)
|
||||
} else {
|
||||
deduped[entry.info_hash] = {
|
||||
|
|
@ -244,6 +257,8 @@ function mapTosho2dDeDupedEntry (entries) {
|
|||
leechers: entry.leechers >= 100000 ? 0 : entry.leechers,
|
||||
downloads: entry.torrent_downloaded_count,
|
||||
size: entry.total_size && fastPrettyBytes(entry.total_size),
|
||||
verified: !!entry.anidb_fid,
|
||||
batch: entry.batch,
|
||||
date: entry.timestamp && new Date(entry.timestamp * 1000)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,37 +71,111 @@
|
|||
}
|
||||
let modal
|
||||
$: table && modal?.focus()
|
||||
const termMapping = {
|
||||
5.1: '5.1',
|
||||
'5.1CH': '5.1',
|
||||
'TRUEHD5.1': 'TrueHD 5.1',
|
||||
AAC: 'AAC',
|
||||
AACX2: 'AAC',
|
||||
AACX3: 'AAC',
|
||||
AACX4: 'AAC',
|
||||
AC3: 'AC3',
|
||||
EAC3: 'EAC3',
|
||||
'E-AC-3': 'EAC3',
|
||||
FLAC: 'FLAC',
|
||||
FLACX2: 'FLAC',
|
||||
FLACX3: 'FLAC',
|
||||
FLACX4: 'FLAC',
|
||||
VORBIS: 'Vorbis',
|
||||
DUALAUDIO: 'Dual Audio',
|
||||
'Dual Audio': 'Dual Audio',
|
||||
'10BIT': '10 Bit',
|
||||
'10BITS': '10 Bit',
|
||||
'10-BIT': '10 Bit',
|
||||
'10-BITS': '10 Bit',
|
||||
HI10: '10 Bit',
|
||||
HI10P: '10 Bit',
|
||||
HI444: 'HI444',
|
||||
HI444P: 'HI444',
|
||||
HI444PP: 'HI444',
|
||||
H265: 'HEVC',
|
||||
'H.265': 'HEVC',
|
||||
X265: 'HEVC',
|
||||
HEVC: 'HEVC',
|
||||
AV1: 'AV1'
|
||||
}
|
||||
function sanitiseTerms ({ video_term: video, audio_term: audio, video_resolution: resolution }) {
|
||||
if (!Array.isArray(video)) video = [video]
|
||||
if (!Array.isArray(audio)) audio = [audio]
|
||||
|
||||
const terms = []
|
||||
|
||||
if (resolution) terms.push({ text: resolution, color: '#c6ec58' })
|
||||
for (const text of audio) {
|
||||
if (termMapping[text]) terms.push({ text: termMapping[text], color: '#f67255' })
|
||||
}
|
||||
for (const text of video) {
|
||||
if (termMapping[text]) terms.push({ text: termMapping[text], color: '#0c8ce9' })
|
||||
}
|
||||
|
||||
return terms
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class='modal z-40' class:show={table} id='viewAnime'>
|
||||
{#if table}
|
||||
<div class='modal-dialog p-20' on:pointerup|self={close} on:keydown={checkClose} tabindex='-1' role='button' bind:this={modal}>
|
||||
<div class='modal-content w-auto'>
|
||||
<button class='close pointer z-30 right-0 position-absolute' type='button' use:click={close}> × </button>
|
||||
<table class='table table-hover'>
|
||||
<div class='modal-dialog' on:pointerup|self={close} on:keydown={checkClose} tabindex='-1' role='button' bind:this={modal}>
|
||||
<div class='modal-content w-auto h-full mx-20 p-0 rounded overflow-x-hidden overflow-y-scroll'>
|
||||
<div class='w-full bg-dark-light d-flex px-15 py-10 position-sticky top-0 z-10'>
|
||||
<div class='material-symbols-outlined text-danger symbol-bold' title='Badges Are a Rough Guess of Information And Might Not Be Representative of Actual Data'>
|
||||
warning
|
||||
</div>
|
||||
<button class='btn btn-square bg-dark rounded-circle ml-auto pointer' type='button' use:click={close}> × </button>
|
||||
</div>
|
||||
<table class='table table-hover font-size-14 position-relative'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope='col'>#</th>
|
||||
<th scope='col'>Name</th>
|
||||
<th scope='col'>Size</th>
|
||||
<th scope='col'>Seed</th>
|
||||
<th scope='col'>Leech</th>
|
||||
<th scope='col'>Downloads</th>
|
||||
<th scope='col'>Released</th>
|
||||
<th scope='col'>Play</th>
|
||||
<tr class='border-0'>
|
||||
<td class='py-15 pl-20 pr-0' />
|
||||
<td class='py-15 px-20'>Name</td>
|
||||
<td class='py-15 px-20'>Size</td>
|
||||
<td class='py-15 px-20'>Seed</td>
|
||||
<td class='py-15 px-20'>Leech</td>
|
||||
<td class='py-15 px-20'>Downloads</td>
|
||||
<td class='py-15 px-20'>Released</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class='results pointer'>
|
||||
{#each table as row, index}
|
||||
<tr class:text-primary={row.best} use:click={() => play(row)}>
|
||||
<th>{index + 1}</th>
|
||||
<td>{row.title}</td>
|
||||
<td>{row.size}</td>
|
||||
<td>{row.seeders ?? '?'}</td>
|
||||
<td>{row.leechers ?? '?'}</td>
|
||||
<td>{row.downloads ?? '?'}</td>
|
||||
<td>{since(row.date)}</td>
|
||||
<td class='material-symbols-outlined font-size-20'>play_arrow</td>
|
||||
<tbody class='pointer'>
|
||||
{#each table as row}
|
||||
<tr class='border-0' class:text-secondary={row.best} use:click={() => play(row)}>
|
||||
<td class='py-10 pl-20 pr-0'>
|
||||
{#if row.best}
|
||||
<div class='material-symbols-outlined font-size-24 symbol-bold' title='Best Release'>
|
||||
star
|
||||
</div>
|
||||
{:else if row.verified}
|
||||
<div class='text-success material-symbols-outlined font-size-24 symbol-bold' title='Verified'>
|
||||
verified
|
||||
</div>
|
||||
{:else if row.batch}
|
||||
<div class='text-light material-symbols-outlined font-size-24 symbol-bold' title='Batch'>
|
||||
database
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
<td class='py-10 px-20'>{row.title}
|
||||
<div class='d-flex flex-row text-dark font-weight-bold font-size-12'>
|
||||
{#each sanitiseTerms(row.parseObject) as { text, color }}
|
||||
<div style={'background:' + color} class='rounded px-15 mr-10 mt-5'>
|
||||
{text}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</td>
|
||||
<td class='py-10 px-20 text-nowrap'>{row.size}</td>
|
||||
<td class='py-10 px-20'>{row.seeders ?? '?'}</td>
|
||||
<td class='py-10 px-20'>{row.leechers ?? '?'}</td>
|
||||
<td class='py-10 px-20'>{row.downloads ?? '?'}</td>
|
||||
<td class='py-10 px-20 text-nowrap'>{since(row.date)}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
|
|
@ -112,9 +186,10 @@
|
|||
</div>
|
||||
|
||||
<style>
|
||||
.close {
|
||||
top: 4rem !important;
|
||||
left: unset;
|
||||
right: 2.5rem !important;
|
||||
.modal-content {
|
||||
margin: 8rem 6rem 0 6rem !important
|
||||
}
|
||||
.symbol-bold {
|
||||
font-variation-settings: 'wght' 500;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
items.value = []
|
||||
key = {}
|
||||
loadSearchData()
|
||||
}, 150)
|
||||
}, 300)
|
||||
|
||||
let canScroll = true
|
||||
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@
|
|||
</ToggleList>
|
||||
</div>
|
||||
<div class='col-5 d-flex flex-column pl-20'>
|
||||
<EpisodeList id={media.id} userProgress={media.mediaListEntry?.progress} episodeCount={media.episodes} duration={media.duration} {play} />
|
||||
<EpisodeList id={media.id} userProgress={media.mediaListEntry && media.mediaListEntry.status === 'CURRENT' && media.mediaListEntry.progress} episodeCount={media.episodes} duration={media.duration} {play} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue