diff --git a/app/index.html b/app/index.html
index 015d7e6..151dfda 100644
--- a/app/index.html
+++ b/app/index.html
@@ -776,6 +776,53 @@
+
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
diff --git a/app/js/animeHandler.js b/app/js/animeHandler.js
index 6b5252f..4c0d61d 100644
--- a/app/js/animeHandler.js
+++ b/app/js/animeHandler.js
@@ -303,24 +303,20 @@ mutation ($id: Int, $status: MediaListStatus, $episode: Int, $repeat: Int) {
}
let alResponse
async function searchAnime (a) { // search bar functionality
- const frag = document.createDocumentFragment()
+ const cards = []
const browse = document.querySelector('.browse')
browse.innerHTML = ''
- browse.appendChild(skeletonCard)
+ // browse.appendChild(skeletonCard) // TODO: fix
a ? alResponse = await alRequest({ method: 'SearchName', name: a }) : alResponse = await alRequest({ method: 'Trending' })
try {
alResponse.data.Page.media.forEach(media => {
- const template = cardCreator({ media: media })
- template.onclick = () => {
- viewAnime(media)
- }
- frag.appendChild(template)
+ cards.push(cardCreator({ media: media, onclick: () => viewAnime(media) }))
})
} catch (e) {
console.error(e)
}
browse.innerHTML = ''
- browse.appendChild(frag)
+ browse.append(...cards)
}
// these really shouldnt be global
@@ -482,53 +478,6 @@ function countdown (s) {
(d || h || m) && tmp.push(m + 'm')
return tmp.join(' ')
}
-function cardCreator (opts) {
- const template = document.createElement('div')
- template.classList.add('card', 'm-0', 'p-0')
- if (opts?.media) {
- template.innerHTML = `
-
-
-

-
-
-
-
${opts.media.title.userPreferred}${opts.episodeNumber ? ' - ' + opts.episodeNumber : ''}
- ${opts.schedule && opts.media.nextAiringEpisode ? "
EP " + opts.media.nextAiringEpisode.episode + ' in ' + countdown(opts.media.nextAiringEpisode.timeUntilAiring) + '' : ''}
-
- ${(opts.media.format ? (opts.media.format === 'TV' ? '' + opts.media.format + ' Show' : '' + opts.media.format.toLowerCase().replace(/_/g, ' ')) : '') + ''}
- ${opts.media.episodes ? '' + opts.media.episodes + ' Episodes' : opts.media.duration ? '' + opts.media.duration + ' Minutes' : ''}
- ${opts.media.status ? '' + opts.media.status.toLowerCase().replace(/_/g, ' ') + '' : ''}
- ${opts.media.season || opts.media.seasonYear ? '' + ((opts.media.season.toLowerCase() || '') + ' ') + (opts.media.seasonYear || '') + '' : ''}
-
-
-
- ${opts.media.description}
-
-
- ${opts.media.genres.map(key => (`${key} `)).join('')}
-
-
-
- `
- } else {
- template.innerHTML = `
-
-
-
-
- ${opts?.parseObject ? `
${opts.parseObject.anime_title + ' - ' + opts.parseObject.episode_number}
` : '
'}
-
-
-
-
-
- `
- }
- return template
-}
-const skeletonCard = cardCreator({})
const DOMPARSER = new DOMParser().parseFromString.bind(new DOMParser())
@@ -713,8 +662,9 @@ function getRSSurl () {
return settings.torrent4 + settings.torrent1 // add custom RSS
}
}
-async function releasesCards (items, frag, limit) {
+async function releasesCards (items, limit) {
const mediaItems = []
+ const cards = []
for (let l = 0; l < (limit || items.length); l++) {
const i = items[l].querySelector.bind(items[l])
mediaItems.push(resolveFileMedia({ fileName: i('title').innerHTML, method: 'SearchName', isRelease: true }))
@@ -722,25 +672,25 @@ async function releasesCards (items, frag, limit) {
await Promise.all(mediaItems).then(results => {
results.forEach((mediaInformation, index) => {
const o = items[index].querySelector.bind(items[index])
- template = cardCreator(mediaInformation)
- template.onclick = () => client.addTorrent(o('link').innerHTML, { media: mediaInformation, episode: mediaInformation.episode })
- frag.appendChild(template)
+ mediaInformation.onclick = () => client.addTorrent(o('link').innerHTML, { media: mediaInformation, episode: mediaInformation.episode })
+ cards.push(cardCreator(mediaInformation))
})
})
localStorage.setItem('store', JSON.stringify(store))
+ return cards
}
async function releasesRss (limit) {
- const frag = document.createDocumentFragment()
+ let cards
await fetch(getRSSurl()).then(res => res.text().then(async xmlTxt => {
try {
const doc = DOMPARSER(xmlTxt, 'text/xml')
const items = doc.querySelectorAll('item')
- await releasesCards(items, frag, limit)
+ cards = await releasesCards(items, limit)
} catch (e) {
console.error(e)
}
}))
- return frag
+ return cards
}
let alID // login icon
async function loadAnime () {
diff --git a/app/js/interface.js b/app/js/interface.js
index 659376e..2750c11 100644
--- a/app/js/interface.js
+++ b/app/js/interface.js
@@ -10,10 +10,10 @@ async function loadHomePage () {
},
releases: async function () {
gallerySkeleton(browseGallery)
- const frag = await releasesRss()
- browseGallery.innerHTML = ''
+ const cards = await releasesRss()
+ browseGallery.textContent = ''
+ browseGallery.append(...cards)
browse.classList.remove('loading')
- browseGallery.appendChild(frag)
browseGallery.scrollTop = 0
browse.onscroll = undefined
},
@@ -57,12 +57,11 @@ async function loadHomePage () {
releases: async function () { // this could be cleaner, but oh well
await fetch(getRSSurl()).then(res => res.text().then(async xmlTxt => {
const doc = DOMPARSER(xmlTxt, 'text/xml')
- const pubDate = doc.querySelector('pubDate').innerHTML
+ const pubDate = doc.querySelector('pubDate').textContent
if (lastRSSDate !== pubDate) {
if (lastRSSDate) {
- homeReleases.innerHTML = ''
- homeReleases.appendChild(gallerySkeletonFrag(5))
- resolveFileMedia({ fileName: doc.querySelector('item').querySelector('title').innerHTML, method: 'SearchName', isRelease: true }).then(mediaInformation => {
+ homeReleases.append(...gallerySkeletonFrag(5))
+ resolveFileMedia({ fileName: doc.querySelector('item').querySelector('title').textContent, method: 'SearchName', isRelease: true }).then(mediaInformation => {
if (settings.other1) {
const notification = new Notification(mediaInformation.media.title.userPreferred, {
body: `Episode ${mediaInformation.episode} was just released!`,
@@ -70,17 +69,16 @@ async function loadHomePage () {
})
notification.onclick = async () => {
window.parent.focus()
- client.addTorrent(doc.querySelector('item').querySelector('link').innerHTML, { media: mediaInformation, episode: mediaInformation.episode })
+ client.addTorrent(doc.querySelector('item').querySelector('link').textContent, { media: mediaInformation, episode: mediaInformation.episode })
store[mediaInformation.parseObject.anime_title] = await alRequest({ id: mediaInformation.media.id, method: 'SearchIDSingle' }).then(res => res.data.Media)
}
}
})
}
- const frag = document.createDocumentFragment()
lastRSSDate = pubDate
- await releasesCards(doc.querySelectorAll('item'), frag, 5)
- homeReleases.innerHTML = ''
- homeReleases.appendChild(frag)
+ const cards = await releasesCards(doc.querySelectorAll('item'), 5)
+ homeReleases.textContent = ''
+ homeReleases.append(...cards)
}
}))
setTimeout(homePreviewFunctions.releases, 30000)
@@ -107,11 +105,11 @@ async function loadHomePage () {
}
}
const gallerySkeletonFrag = function (limit) {
- const frag = document.createDocumentFragment()
- for (let i = 0; i < limit; i++) {
- frag.appendChild(cardCreator({}))
+ const cards = []
+ while (limit--) {
+ cards.push(skeletonCard.cloneNode(true))
}
- return frag
+ return cards
}
let loadTimeout
let lastDate
@@ -120,8 +118,7 @@ async function loadHomePage () {
function gallerySkeleton (gallery) {
browse.classList.add('loading')
- gallery.innerHTML = ''
- gallery.appendChild(gallerySkeletonFrag(10))
+ gallery.append(...gallerySkeletonFrag(10))
}
function galleryAppend (opts) {
if (opts.page === 1) {
@@ -139,26 +136,24 @@ async function loadHomePage () {
}
}
if (!opts.page || opts.page === 1) {
- opts.gallery.innerHTML = ''
+ opts.gallery.textContent = ''
}
- const frag = document.createDocumentFragment()
const date = new Date()
+ const cards = []
opts.media.forEach(media => {
if (opts.schedule) {
if (media.timeUntilAiring && (!lastDate || (new Date(+date + media.timeUntilAiring * 1000).getDay() !== lastDate.getDay()))) {
const div = document.createElement('div')
lastDate = new Date(+date + media.timeUntilAiring * 1000)
div.classList.add('day-row', 'font-size-24', 'font-weight-bold', 'h-50', 'd-flex', 'align-items-end')
- div.innerHTML = lastDate.toLocaleDateString('en-US', { weekday: 'long' })
- frag.appendChild(div)
+ div.textContent = lastDate.toLocaleDateString('en-US', { weekday: 'long' })
+ cards.push(div)
}
media = media.media
}
- const template = cardCreator({ media: media, schedule: opts.schedule })
- template.onclick = () => viewAnime(media)
- frag.appendChild(template)
+ cards.push(cardCreator({ media: media, schedule: opts.schedule, onclick: () => viewAnime(media) }))
})
- opts.gallery.appendChild(frag)
+ opts.gallery.append(...cards)
canScroll = true
}
@@ -173,10 +168,40 @@ async function loadHomePage () {
navHome.onclick = () => {
lastRSSDate = undefined
for (const item of homePreviewElements) {
- item.innerHTML = ''
- item.appendChild(gallerySkeletonFrag(5))
+ item.textContent = ''
+ item.append(...gallerySkeletonFrag(5))
homePreviewFunctions[item.dataset.function]()
}
- document.querySelector('.browse').innerHTML = ''
+ document.querySelector('.browse').textContent = ''
+ }
+}
+
+const skeletonCard = skeletonCardTemplate.cloneNode(true).content
+const bareCard = bareCardTemplate.cloneNode(true).content
+const fullCard = fullCardTemplate.cloneNode(true).content
+function cardCreator (opts) {
+ if (opts.media) {
+ const card = fullCard.cloneNode(true)
+ const nodes = card.querySelectorAll('*')
+ nodes[0].onclick = () => opts.onclick()
+ nodes[0].style = `--color:${opts.media.coverImage.color || '#1890ff'};`
+ nodes[3].src = opts.media.coverImage.extraLarge || ''
+ nodes[6].textContent = [opts.media.title.userPreferred, opts.episodeNumber].filter(s => s).join(' - ')
+ if (opts.schedule && opts.media.nextAiringEpisode) nodes[7] = opts.media.nextAiringEpisode.episode + ' in ' + countdown(opts.media.nextAiringEpisode.timeUntilAiring)
+ nodes[8].innerHTML = '' + [
+ opts.media.format === 'TV' ? 'TV Show' : opts.media.format?.toLowerCase().replace(/_/g, ' '),
+ opts.media.episodes ? opts.media.episodes + ' Episodes' : opts.media.duration ? opts.media.duration + ' Minutes' : undefined,
+ opts.media.status?.toLowerCase().replace(/_/g, ' '),
+ [opts.media.season?.toLowerCase(), opts.media.seasonYear].filter(s => s).join(' ')
+ ].filter(s => s).join('') + ''
+ nodes[13].innerHTML = opts.media.description
+ nodes[14].innerHTML = opts.media.genres.map(key => (`${key} `)).join('')
+ return card
+ } else if (opts.parseObject) {
+ const card = bareCard.cloneNode(true)
+ card.querySelector('h5').textContent = [opts.parseObject.anime_title, opts.parseObject.episode_number].filter(s => s).join(' - ')
+ return card
+ } else {
+ return skeletonCard.cloneNode(true)
}
}
diff --git a/app/js/player.js b/app/js/player.js
index 221060a..469ddec 100644
--- a/app/js/player.js
+++ b/app/js/player.js
@@ -987,8 +987,7 @@ Style: Default,${options.defaultSSAStyles || 'Roboto Medium,26,&H00FFFFFF,&H0000
const frag = document.createDocumentFragment()
for (const file of this.videoFiles) {
const mediaInformation = await resolveFileMedia({ fileName: file.name, method: 'SearchName' })
- const template = cardCreator(mediaInformation)
- template.onclick = () => {
+ mediaInformation.onclick = () => {
this.cleanupVideo()
this.buildVideo(torrent, {
media: mediaInformation,
@@ -1039,8 +1038,8 @@ Style: Default,${options.defaultSSAStyles || 'Roboto Medium,26,&H00FFFFFF,&H0000
localStorage.setItem('offlineTorrents', JSON.stringify(this.offlineTorrents))
}
const mediaInformation = await resolveFileMedia({ fileName: torrent.name, method: 'SearchName' })
+ mediaInformation.onclick = () => this.addTorrent(torrent, { media: mediaInformation, episode: mediaInformation.episode })
const template = cardCreator(mediaInformation)
- template.onclick = () => this.addTorrent(torrent, { media: mediaInformation, episode: mediaInformation.episode })
document.querySelector('.downloads').appendChild(template)
})
}