mirror of
https://github.com/NoCrypt/migu.git
synced 2026-04-21 00:22:08 +00:00
paste a bunch of code
This commit is contained in:
parent
70f804ea7f
commit
ce393b8fc3
5 changed files with 541 additions and 4 deletions
|
|
@ -1,11 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
import Search from './Search.svelte'
|
import Search from './Search.svelte'
|
||||||
import Section from './Section.svelte'
|
import Section from './Section.svelte'
|
||||||
|
// TODO: add AL account detection for hiding
|
||||||
const sections = [
|
const sections = [
|
||||||
{
|
{
|
||||||
title: 'Continue Watching',
|
title: 'Continue Watching',
|
||||||
click: () => {},
|
click: () => {},
|
||||||
cards: new Promise(() => {})
|
cards: new Promise(() => {}),
|
||||||
|
hide: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'New Releases',
|
title: 'New Releases',
|
||||||
|
|
@ -15,7 +17,8 @@
|
||||||
{
|
{
|
||||||
title: 'Your List',
|
title: 'Your List',
|
||||||
click: () => {},
|
click: () => {},
|
||||||
cards: new Promise(() => {})
|
cards: new Promise(() => {}),
|
||||||
|
hide: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Trending Now',
|
title: 'Trending Now',
|
||||||
|
|
@ -39,8 +42,10 @@
|
||||||
<div class="h-full py-10">
|
<div class="h-full py-10">
|
||||||
<Search />
|
<Search />
|
||||||
<div>
|
<div>
|
||||||
{#each sections as opts, i (i)}
|
{#each sections as opts (opts.title)}
|
||||||
<Section {opts} />
|
{#if !opts.hide}
|
||||||
|
<Section {opts} />
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,282 @@
|
||||||
|
/* global halfmoon */
|
||||||
|
|
||||||
|
const alID = 'TODO: add al id'
|
||||||
|
|
||||||
|
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: ''
|
||||||
|
})
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function alEntry (filemedia) {
|
||||||
|
if (filemedia.media && localStorage.getItem('ALtoken')) {
|
||||||
|
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) {
|
||||||
|
const query = `
|
||||||
|
mutation ($id: Int, $status: MediaListStatus, $episode: Int, $repeat: Int) {
|
||||||
|
SaveMediaListEntry (mediaId: $id, status: $status, progress: $episode, repeat: $repeat) {
|
||||||
|
id,
|
||||||
|
status,
|
||||||
|
progress,
|
||||||
|
repeat
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
const variables = {
|
||||||
|
repeat: 0,
|
||||||
|
id: filemedia.media.id,
|
||||||
|
status: 'CURRENT',
|
||||||
|
episode: filemedia.episodeNumber || 1
|
||||||
|
}
|
||||||
|
if (filemedia.episodeNumber === filemedia.media.episodes || filemedia.episodes === 1) {
|
||||||
|
variables.status = 'COMPLETED'
|
||||||
|
if (res.data.MediaList.status === 'COMPLETED') {
|
||||||
|
variables.repeat = res.data.MediaList.repeat + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Bearer ' + localStorage.getItem('ALtoken'),
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Accept: 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
query: query,
|
||||||
|
variables: variables
|
||||||
|
})
|
||||||
|
}
|
||||||
|
handleRequest(options)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function alRequest (opts) {
|
||||||
|
let query
|
||||||
|
const variables = {
|
||||||
|
type: 'ANIME',
|
||||||
|
sort: opts.sort || 'TRENDING_DESC',
|
||||||
|
page: opts.page || 1,
|
||||||
|
perPage: opts.perPage || 30,
|
||||||
|
status_in: opts.status_in || '[CURRENT,PLANNING]',
|
||||||
|
chunk: opts.chunk || 1,
|
||||||
|
perchunk: opts.perChunk || 30
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Accept: 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const queryObjects = `
|
||||||
|
id,
|
||||||
|
title {
|
||||||
|
romaji,
|
||||||
|
english,
|
||||||
|
native,
|
||||||
|
userPreferred
|
||||||
|
},
|
||||||
|
description(
|
||||||
|
asHtml: true
|
||||||
|
),
|
||||||
|
season,
|
||||||
|
seasonYear,
|
||||||
|
format,
|
||||||
|
status,
|
||||||
|
episodes,
|
||||||
|
duration,
|
||||||
|
averageScore,
|
||||||
|
genres,
|
||||||
|
coverImage {
|
||||||
|
extraLarge,
|
||||||
|
medium,
|
||||||
|
color
|
||||||
|
},
|
||||||
|
countryOfOrigin,
|
||||||
|
isAdult,
|
||||||
|
bannerImage,
|
||||||
|
synonyms,
|
||||||
|
nextAiringEpisode {
|
||||||
|
timeUntilAiring,
|
||||||
|
episode
|
||||||
|
},
|
||||||
|
trailer {
|
||||||
|
id,
|
||||||
|
site
|
||||||
|
},
|
||||||
|
streamingEpisodes {
|
||||||
|
title,
|
||||||
|
thumbnail
|
||||||
|
},
|
||||||
|
mediaListEntry {
|
||||||
|
progress
|
||||||
|
},
|
||||||
|
source,
|
||||||
|
studios(isMain: true) {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
relations {
|
||||||
|
edges {
|
||||||
|
relationType(version:2)
|
||||||
|
node {
|
||||||
|
id,
|
||||||
|
title {
|
||||||
|
userPreferred
|
||||||
|
},
|
||||||
|
coverImage {
|
||||||
|
medium
|
||||||
|
},
|
||||||
|
type,
|
||||||
|
status,
|
||||||
|
format,
|
||||||
|
episodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
if (opts.status) variables.status = opts.status
|
||||||
|
if (localStorage.getItem('ALtoken')) options.headers.Authorization = localStorage.getItem('ALtoken')
|
||||||
|
switch (opts.method) {
|
||||||
|
case 'SearchName': {
|
||||||
|
variables.search = opts.name
|
||||||
|
query = `
|
||||||
|
query ($page: Int, $perPage: Int, $sort: [MediaSort], $type: MediaType, $search: String, $status: [MediaStatus]) {
|
||||||
|
Page (page: $page, perPage: $perPage) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
},
|
||||||
|
media(type: $type, search: $search, sort: $sort, status_in: $status) {
|
||||||
|
${queryObjects}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
break
|
||||||
|
} case 'SearchIDSingle': {
|
||||||
|
variables.id = opts.id
|
||||||
|
query = `
|
||||||
|
query ($id: Int, $type: MediaType) {
|
||||||
|
Media (id: $id, type: $type) {
|
||||||
|
${queryObjects}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
break
|
||||||
|
} case 'SearchIDS': {
|
||||||
|
variables.id = opts.id
|
||||||
|
query = `
|
||||||
|
query ($id: [Int], $type: MediaType, $page: Int, $perPage: Int) {
|
||||||
|
Page (page: $page, perPage: $perPage) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
},
|
||||||
|
media (id_in: $id, type: $type) {
|
||||||
|
${queryObjects}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
break
|
||||||
|
} case 'Viewer': {
|
||||||
|
query = `
|
||||||
|
query {
|
||||||
|
Viewer {
|
||||||
|
avatar {
|
||||||
|
medium
|
||||||
|
},
|
||||||
|
name,
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
break
|
||||||
|
} case 'UserLists': {
|
||||||
|
variables.id = opts.id
|
||||||
|
query = `
|
||||||
|
query ($page: Int, $perPage: Int, $id: Int, $type: MediaType, $status_in: [MediaListStatus]){
|
||||||
|
Page (page: $page, perPage: $perPage) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
},
|
||||||
|
mediaList (userId: $id, type: $type, status_in: $status_in) {
|
||||||
|
media {
|
||||||
|
${queryObjects}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
break
|
||||||
|
} case 'SearchIDStatus': {
|
||||||
|
variables.id = alID
|
||||||
|
variables.mediaId = opts.id
|
||||||
|
query = `
|
||||||
|
query ($id: Int, $mediaId: Int){
|
||||||
|
MediaList(userId: $id, mediaId: $mediaId) {
|
||||||
|
status,
|
||||||
|
progress,
|
||||||
|
repeat
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
break
|
||||||
|
} case 'AiringSchedule': {
|
||||||
|
const date = new Date()
|
||||||
|
const diff = date.getDay() >= 1 ? date.getDay() - 1 : 6 - date.getDay()
|
||||||
|
date.setDate(date.getDate() - diff)
|
||||||
|
date.setHours(0, 0, 0, 0)
|
||||||
|
variables.from = date.getTime() / 1000
|
||||||
|
variables.to = (date.getTime() + 7 * 24 * 60 * 60 * 1000) / 1000
|
||||||
|
query = `
|
||||||
|
query ($page: Int, $perPage: Int, $from: Int, $to: Int) {
|
||||||
|
Page (page: $page, perPage: $perPage) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
},
|
||||||
|
airingSchedules(airingAt_greater: $from, airingAt_lesser: $to) {
|
||||||
|
episode,
|
||||||
|
timeUntilAiring,
|
||||||
|
airingAt,
|
||||||
|
media{
|
||||||
|
${queryObjects}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
break
|
||||||
|
} case 'Search': {
|
||||||
|
variables.genre = opts.genre
|
||||||
|
variables.search = opts.search
|
||||||
|
variables.year = opts.year
|
||||||
|
variables.season = opts.season
|
||||||
|
variables.format = opts.format
|
||||||
|
variables.status = opts.status
|
||||||
|
variables.sort = opts.sort || 'SEARCH_MATCH'
|
||||||
|
query = `
|
||||||
|
query ($page: Int, $perPage: Int, $sort: [MediaSort], $type: MediaType, $search: String, $status: MediaStatus, $season: MediaSeason, $year: Int, $genre: String, $format: MediaFormat, $startDate: FuzzyDateInt) {
|
||||||
|
Page (page: $page, perPage: $perPage) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
},
|
||||||
|
media(type: $type, search: $search, sort: $sort, status: $status, season: $season, seasonYear: $year, genre: $genre, format: $format, startDate_greater: $startDate) {
|
||||||
|
${queryObjects}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
options.body = JSON.stringify({
|
||||||
|
query: query.replace(/\s/g, ''),
|
||||||
|
variables: variables
|
||||||
|
})
|
||||||
|
|
||||||
|
return await handleRequest(options)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
/* global halfmoon */
|
||||||
|
import { client } from './torrent.js'
|
||||||
|
import { DOMPARSER } from './util.js'
|
||||||
|
import { alRequest } from './anilist.js'
|
||||||
|
import { nyaaRss } from './rss.js'
|
||||||
|
import anitomyscript from 'anitomyscript'
|
||||||
|
|
||||||
|
const torrentRx = /(^magnet:){1}|(^[A-F\d]{8,40}$){1}|(.*\.torrent$){1}/i
|
||||||
|
const imageRx = /\.(jpeg|jpg|gif|png|webp)/i
|
||||||
|
window.addEventListener('paste', async e => { // WAIT image lookup on paste, or add torrent on paste
|
||||||
|
const item = e.clipboardData.items[0]
|
||||||
|
if (item && item.type.indexOf('image') === 0) {
|
||||||
|
e.preventDefault()
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('image', item.getAsFile())
|
||||||
|
traceAnime(formData, 'file')
|
||||||
|
} else if (item && item.type === 'text/plain') {
|
||||||
|
item.getAsString(text => {
|
||||||
|
if (torrentRx.exec(text)) {
|
||||||
|
e.preventDefault()
|
||||||
|
client.playTorrent(text)
|
||||||
|
} else if (imageRx.exec(text)) {
|
||||||
|
e.preventDefault()
|
||||||
|
traceAnime(text)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (item && item.type === 'text/html') {
|
||||||
|
item.getAsString(text => {
|
||||||
|
const img = DOMPARSER(text, 'text/html').querySelectorAll('img')[0]
|
||||||
|
if (img) {
|
||||||
|
e.preventDefault()
|
||||||
|
traceAnime(img.src)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
function traceAnime (image, type) { // WAIT lookup logic
|
||||||
|
if (type === 'file') {
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = e => {
|
||||||
|
halfmoon.initStickyAlert({
|
||||||
|
content: `Looking up anime for image.<br><img class="w-200 rounded pt-5" src="${e.target.result}">`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(image.get('image'))
|
||||||
|
} else {
|
||||||
|
halfmoon.initStickyAlert({
|
||||||
|
content: `Looking up anime for image.<br><img class="w-200 rounded pt-5" src="${image}">`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let options
|
||||||
|
let url = `https://api.trace.moe/search?cutBorders&url=${image}`
|
||||||
|
if (type === 'file') {
|
||||||
|
options = {
|
||||||
|
method: 'POST',
|
||||||
|
body: image
|
||||||
|
}
|
||||||
|
url = 'https://api.trace.moe/search'
|
||||||
|
}
|
||||||
|
fetch(url, options).then(res => res.json()).then(async ({ result }) => {
|
||||||
|
if (result && result[0].similarity >= 0.85) {
|
||||||
|
// const res = await alRequest({ method: 'SearchIDSingle', id: result[0].anilist })
|
||||||
|
// viewMedia(res.data.Media, result[0].episode)
|
||||||
|
// TODO: view media
|
||||||
|
} else {
|
||||||
|
halfmoon.initStickyAlert({
|
||||||
|
content: 'Couldn\'t find anime for specified image! Try to remove black bars, or use a more detailed image.',
|
||||||
|
title: 'Search Failed',
|
||||||
|
alertType: 'alert-danger',
|
||||||
|
fillType: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export const episodeRx = /Episode (\d+) - (.*)/
|
||||||
|
|
||||||
|
export async function nyaaSearch (media, episode, isOffline) {
|
||||||
|
if (parseInt(episode) < 10) {
|
||||||
|
episode = `0${episode}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const table = document.querySelector('tbody.results')
|
||||||
|
const results = await nyaaRss(media, episode, isOffline)
|
||||||
|
|
||||||
|
if (results.children.length === 0) {
|
||||||
|
halfmoon.initStickyAlert({
|
||||||
|
content: `Couldn't find torrent for ${media.title.userPreferred} Episode ${parseInt(episode)}! Try specifying a torrent manually.`,
|
||||||
|
title: 'Search Failed',
|
||||||
|
alertType: 'alert-danger',
|
||||||
|
fillType: ''
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
table.innerHTML = ''
|
||||||
|
table.appendChild(results)
|
||||||
|
halfmoon.toggleModal('tsearch')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve anime name based on file name and store it
|
||||||
|
|
||||||
|
export async function resolveFileMedia (opts) {
|
||||||
|
// opts.fileName opts.isRelease
|
||||||
|
|
||||||
|
async function resolveTitle (title) {
|
||||||
|
if (!(title in relations)) {
|
||||||
|
// resolve name and shit
|
||||||
|
const method = { name: title, method: 'SearchName', perPage: 1, status: ['RELEASING', 'FINISHED'], sort: 'SEARCH_MATCH', startDate: 10000000 }
|
||||||
|
let res = await alRequest(method)
|
||||||
|
if (!res.data.Page.media[0]) {
|
||||||
|
const index = method.name.search(/S\d/)
|
||||||
|
method.name = ((index !== -1 && method.name.slice(0, index) + method.name.slice(index + 1, method.name.length)) || method.name).replace('(TV)', '').replace(/ (19[5-9]\d|20[0-6]\d)/, '').replace('-', '')
|
||||||
|
method.status = ['RELEASING', 'FINISHED']
|
||||||
|
res = await alRequest(method)
|
||||||
|
}
|
||||||
|
if (res.data.Page.media[0]) {
|
||||||
|
relations[title] = res.data.Page.media[0].id
|
||||||
|
} else {
|
||||||
|
relations[title] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const parsePromises = opts.fileName.constructor === Array
|
||||||
|
? opts.fileName.map(name => anitomyscript(name))
|
||||||
|
: [anitomyscript(opts.fileName)]
|
||||||
|
const parseObjs = await Promise.all(parsePromises)
|
||||||
|
await Promise.all([...new Set(parseObjs.map(obj => obj.anime_title))].map(title => resolveTitle(title)))
|
||||||
|
const assoc = {}
|
||||||
|
for (let ids = [...new Set(parseObjs.map(obj => relations[obj.anime_title]))]; ids.length; ids = ids.slice(50)) {
|
||||||
|
for await (const media of (await alRequest({ method: 'SearchIDS', id: ids.slice(0, 50), perPage: 50 })).data.Page.media) {
|
||||||
|
assoc[media.id] = media
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fileMedias = []
|
||||||
|
for (const praseObj of parseObjs) {
|
||||||
|
let episode
|
||||||
|
let media = assoc[relations[praseObj.anime_title]]
|
||||||
|
async function resolveSeason (opts) {
|
||||||
|
// opts.media, opts.episode, opts.increment, opts.offset
|
||||||
|
let epMin, epMax
|
||||||
|
if (opts.episode.constructor === Array) { // support batch episode ranges
|
||||||
|
epMin = Number(opts.episode[0])
|
||||||
|
epMax = Number(opts.episode[opts.episode.length - 1])
|
||||||
|
} else {
|
||||||
|
epMin = epMax = Number(opts.episode)
|
||||||
|
}
|
||||||
|
let tempMedia, increment
|
||||||
|
if (opts.media.relations.edges.some(edge => edge.relationType === 'PREQUEL' && (edge.node.format === 'TV' || 'TV_SHORT')) && !opts.increment) {
|
||||||
|
// media has prequel and we dont want to move up in the tree
|
||||||
|
tempMedia = opts.media.relations.edges.filter(edge => edge.relationType === 'PREQUEL' && (edge.node.format === 'TV' || 'TV_SHORT'))[0].node
|
||||||
|
} else if (opts.media.relations.edges.some(edge => edge.relationType === 'SEQUEL' && (edge.node.format === 'TV' || 'TV_SHORT'))) {
|
||||||
|
// media doesnt have prequel, or we want to move up in the tree
|
||||||
|
tempMedia = opts.media.relations.edges.filter(edge => edge.relationType === 'SEQUEL' && (edge.node.format === 'TV' || 'TV_SHORT'))[0].node
|
||||||
|
increment = true
|
||||||
|
}
|
||||||
|
if (tempMedia?.episodes && epMax - (opts.offset + media.episodes) > (media.nextAiringEpisode?.episode || media.episodes)) {
|
||||||
|
// episode is still out of bounds
|
||||||
|
const nextEdge = await alRequest({ method: 'SearchIDSingle', id: tempMedia.id })
|
||||||
|
await resolveSeason({ media: nextEdge.data.Media, episode: opts.episode, offset: opts.offset + nextEdge.data.Media.episodes, increment: increment })
|
||||||
|
} else if (tempMedia?.episodes && epMax - (opts.offset + media.episodes) <= (media.nextAiringEpisode?.episode || media.episodes) && epMin - (opts.offset + media.episodes) > 0) {
|
||||||
|
// episode is in range, seems good! overwriting media to count up "seasons"
|
||||||
|
if (opts.episode.constructor === Array) {
|
||||||
|
episode = `${praseObj.episode_number[0] - (opts.offset + media.episodes)} ~ ${praseObj.episode_number[praseObj.episode_number.length - 1] - (opts.offset + media.episodes)}`
|
||||||
|
} else {
|
||||||
|
episode = opts.episode - (opts.offset + media.episodes)
|
||||||
|
}
|
||||||
|
if (opts.increment || increment) {
|
||||||
|
const nextEdge = await alRequest({ method: 'SearchIDSingle', id: tempMedia.id })
|
||||||
|
media = nextEdge.data.Media
|
||||||
|
}
|
||||||
|
} 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: ''
|
||||||
|
})
|
||||||
|
// 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])}`
|
||||||
|
} else {
|
||||||
|
episode = Number(opts.episode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve episode, if movie, dont.
|
||||||
|
if ((media?.format !== 'MOVIE' || (media.episodes || media.nextAiringEpisode.episode)) && praseObj.episode_number) {
|
||||||
|
if (praseObj.episode_number.constructor === Array) {
|
||||||
|
// is an episode range
|
||||||
|
if (parseInt(praseObj.episode_number[0]) === 1) {
|
||||||
|
// if it starts with #1 and overflows then it includes more than 1 season in a batch, cant fix this cleanly, name is parsed per file basis so this shouldnt be an issue
|
||||||
|
episode = `${praseObj.episode_number[0]} ~ ${praseObj.episode_number[praseObj.episode_number.length - 1]}`
|
||||||
|
} else {
|
||||||
|
if ((media?.episodes || media?.nextAiringEpisode?.episode) && parseInt(praseObj.episode_number[praseObj.episode_number.length - 1]) > (media.episodes || media.nextAiringEpisode.episode)) {
|
||||||
|
// if highest value is bigger than episode count or latest streamed episode +1 for safety, parseint to math.floor a number like 12.5 - specials - in 1 go
|
||||||
|
await resolveSeason({ media: media, episode: praseObj.episode_number, offset: 0 })
|
||||||
|
} else {
|
||||||
|
// cant find ep count or range seems fine
|
||||||
|
episode = `${Number(praseObj.episode_number[0])} ~ ${Number(praseObj.episode_number[praseObj.episode_number.length - 1])}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((media?.episodes || media?.nextAiringEpisode?.episode) && parseInt(praseObj.episode_number) > (media.episodes || media.nextAiringEpisode.episode)) {
|
||||||
|
// value bigger than episode count
|
||||||
|
await resolveSeason({ media: media, episode: praseObj.episode_number, offset: 0 })
|
||||||
|
} else {
|
||||||
|
// cant find ep count or episode seems fine
|
||||||
|
episode = Number(praseObj.episode_number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const streamingEpisode = media?.streamingEpisodes.filter(episode => episodeRx.exec(episode.title) && Number(episodeRx.exec(episode.title)[1]) === Number(praseObj.episode_number))[0]
|
||||||
|
fileMedias.push({
|
||||||
|
mediaTitle: media?.title.userPreferred,
|
||||||
|
episodeNumber: episode,
|
||||||
|
episodeTitle: streamingEpisode && episodeRx.exec(streamingEpisode.title)[2],
|
||||||
|
episodeThumbnail: streamingEpisode?.thumbnail,
|
||||||
|
mediaCover: media?.coverImage.medium,
|
||||||
|
name: 'Miru',
|
||||||
|
parseObject: praseObj,
|
||||||
|
media: media
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return fileMedias.length === 1 ? fileMedias[0] : fileMedias
|
||||||
|
}
|
||||||
|
|
||||||
|
export const relations = JSON.parse(localStorage.getItem('relations')) || {}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export const client = null
|
||||||
|
|
@ -1,3 +1,20 @@
|
||||||
|
/* global halfmoon */
|
||||||
|
halfmoon.showModal = id => {
|
||||||
|
const t = document.getElementById(id)
|
||||||
|
t && t.classList.add('show')
|
||||||
|
}
|
||||||
|
|
||||||
|
halfmoon.hideModal = id => {
|
||||||
|
const t = document.getElementById(id)
|
||||||
|
t && t.classList.remove('show')
|
||||||
|
}
|
||||||
|
|
||||||
|
// export const searchParams = new URLSearchParams(location.href)
|
||||||
|
// if (searchParams.get('access_token')) {
|
||||||
|
// localStorage.setItem('ALtoken', searchParams.get('access_token'))
|
||||||
|
// window.location = '/app/#home'
|
||||||
|
// }
|
||||||
|
|
||||||
export function countdown (s) {
|
export function countdown (s) {
|
||||||
const d = Math.floor(s / (3600 * 24))
|
const d = Math.floor(s / (3600 * 24))
|
||||||
s -= d * 3600 * 24
|
s -= d * 3600 * 24
|
||||||
|
|
@ -11,3 +28,7 @@ export function countdown (s) {
|
||||||
if (d || h || m) tmp.push(m + 'm')
|
if (d || h || m) tmp.push(m + 'm')
|
||||||
return tmp.join(' ')
|
return tmp.join(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DOMPARSER = new DOMParser().parseFromString.bind(new DOMParser())
|
||||||
|
|
||||||
|
export const sleep = t => new Promise(resolve => setTimeout(resolve, t))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue