player work and optimisation

This commit is contained in:
ThaUnknown 2021-03-26 19:19:07 +01:00
parent 147aa7d5aa
commit b6d7860999
7 changed files with 14644 additions and 95 deletions

14540
app/css/halfmoon.css Normal file

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,15 @@
/*PLAYER*/
.immersed {
cursor: none
}
.immersed .controls,
.immersed .stats {
opacity: 0;
}
#player:target {
bottom: 0;
right: 0;
@ -23,16 +32,8 @@
transition: none !important;
}
.immersed {
cursor: none
}
.immersed .controls,
.immersed .stats {
opacity: 0;
}
#player {
will-change: width, right, bottom, position, display;
position: fixed;
display: var(--miniplayer-display);
bottom: 2rem;
@ -214,7 +215,8 @@
#player:target>a,
#progress+img[src=" "],
video[src=""],
#player.pip video {
#player.pip video,
#bcap[disabled], #baudio[disabled] {
display: none !important
}

View file

@ -19,7 +19,7 @@
<meta property="og:image" content="logo.png">
<title>Miru</title>
<link href="https://cdn.jsdelivr.net/npm/halfmoon@1.1.1/css/halfmoon-variables.min.css" rel="stylesheet">
<link href="css/halfmoon.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="css/misc.css" rel="stylesheet">
<link href="css/player.css" rel="stylesheet">
@ -216,12 +216,11 @@
<input class="ctrl" type="range" value="100" id="volume" step="any" data-name="setVolume">
</div>
<div class="audio-tracks dropdown dropup with-arrow">
<span class="material-icons ctrl" title="Audio Tracks [T]" id="baudio"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-name="showAudio"
disabled>
<span class="material-icons" title="Audio Tracks [T]" id="baudio" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" disabled>
queue_music
</span>
<div class="dropdown-menu dropdown-menu-left" aria-labelledby="baudio" id="audioTracksMenu">
<div class="dropdown-menu dropdown-menu-left ctrl custom-radio p-10 pb-5 text-capitalize" aria-labelledby="baudio" data-name="selectAudio">
</div>
</div>
<span class="ts" id="elapsed">00:00</span>
@ -231,11 +230,11 @@
</div>
<span class="ts" id="remaining">00:00</span>
<div class="subtitles dropdown dropup with-arrow">
<span class="material-icons ctrl" title="Subtitles [C]" id="bcap" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" data-name="showCaptions" disabled>
<span class="material-icons" title="Subtitles [C]" id="bcap" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" disabled>
subtitles
</span>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="bcap" id="subMenu">
<div class="dropdown-menu dropdown-menu-right ctrl custom-radio p-10 pb-5 text-capitalize" aria-labelledby="bcap" data-name="selectCaptions">
</div>
</div>
<span class="material-icons ctrl" title="Popout Window [P]" id="bpip" data-name="togglePopout">

View file

@ -711,7 +711,7 @@ async function releasesCards (items, frag, limit) {
results.forEach((mediaInformation, index) => {
const o = items[index].querySelector.bind(items[index])
template = cardCreator(mediaInformation)
template.onclick = () => addTorrent(o('link').innerHTML, { media: mediaInformation.media, episode: mediaInformation.episode })
template.onclick = () => client.addTorrent(o('link').innerHTML, { media: mediaInformation.media, episode: mediaInformation.episode })
frag.appendChild(template)
})
})

View file

@ -64,7 +64,7 @@ async function loadHomePage () {
})
notification.onclick = async () => {
window.parent.focus()
addTorrent(doc.querySelector('item').querySelector('link').innerHTML, { media: mediaInformation.media, episode: mediaInformation.episode })
client.addTorrent(doc.querySelector('item').querySelector('link').innerHTML, { media: mediaInformation.media, episode: mediaInformation.episode })
store[mediaInformation.parseObject.anime_title] = await alRequest({ id: mediaInformation.media.id, method: 'SearchIDSingle' }).then(res => res.data.Media)
}
}

View file

@ -63,11 +63,11 @@ class TorrentPlayer extends WebTorrent {
this.controls.setProgress.addEventListener('input', (e) => this.setProgress(e.target.value))
this.controls.setProgress.addEventListener('mouseup', (e) => this.dragBarEnd(e.target.value))
this.controls.setProgress.addEventListener('thouchend', (e) => this.dragBarEnd(e.target.value))
this.controls.setProgress.addEventListener('click', (e) => this.dragBarEnd(e.target.value))
this.controls.setProgress.addEventListener('mousedown', (e) => this.dragBarStart(e.target.value))
this.video.addEventListener('timeupdate', (e) => {
if (this.immerseTimeout && document.location.hash === '#player') this.setProgress(e.target.currentTime / e.target.duration * 100)
})
this.video.addEventListener('ended', (e) => this.setProgress(e.target.value))
this.player = options.player
this.playerWrapper = options.playerWrapper
@ -92,7 +92,16 @@ Style: Default,${options.defaultSSAStyles}
`
}
this.video.addEventListener('loadedmetadata', () => this.video.audioTracks?.length > 1 ? this.controls.showAudio.removeAttribute('disabled') : this.controls.showAudio.setAttribute('disabled', ''))
this.video.addEventListener('loadedmetadata', () => {
if (this.video.audioTracks?.length > 1) {
baudio.removeAttribute('disabled') // TODO: fix
for (const track of this.video.audioTracks) {
this.createRadioElement(track, 'audio')
}
} else {
baudio.setAttribute('disabled', '') // TODO: fix
}
})
this.completed = undefined
this.onWatched = options.onWatched
@ -162,6 +171,7 @@ Style: Default,${options.defaultSSAStyles}
this.videoExtensions = ['.3g2', '.3gp', '.asf', '.avi', '.dv', '.flv', '.gxf', '.m2ts', '.m4a', '.m4b', '.m4p', '.m4r', '.m4v', '.mkv', '.mov', '.mp4', '.mpd', '.mpeg', '.mpg', '.mxf', '.nut', '.ogm', '.ogv', '.swf', '.ts', '.vob', '.webm', '.wmv', '.wtv']
this.videoFiles = undefined
this.updateDisplay()
this.currentTorrent = undefined
this.offlineTorrents = JSON.parse(localStorage.getItem('offlineTorrents')) || {}
// adds all offline store torrents to the client
@ -308,7 +318,7 @@ Style: Default,${options.defaultSSAStyles}
this.video.src = `/app/webtorrent/${torrent.infoHash}/${encodeURI(this.currentFile.path)}`
this.video.load()
if (this.videoFiles.length > 1) bpl.removeAttribute('disabled')
if (this.videoFiles.length > 1) bpl.removeAttribute('disabled') // TODO: fix
if (this.currentFile.done) {
this.postDownload()
@ -342,7 +352,7 @@ Style: Default,${options.defaultSSAStyles}
type: 'image/jpg'
}]
})
if (parseInt(this.nowPlaying[1]) >= this.nowPlaying[0].episodes) bnext.setAttribute('disabled', '')
if (parseInt(this.nowPlaying[1]) >= this.nowPlaying[0].episodes) bnext.setAttribute('disabled', '') // TODO: fix
let streamingEpisode
if (this.nowPlaying[0].streamingEpisodes.length >= Number(this.nowPlaying[1])) {
streamingEpisode = this.nowPlaying[0].streamingEpisodes.filter(episode => episodeRx.exec(episode.title) && Number(episodeRx.exec(episode.title)[1]) === Number(this.nowPlaying[1]))[0]
@ -405,7 +415,7 @@ Style: Default,${options.defaultSSAStyles}
video: undefined
}
nowPlayingDisplay.innerHTML = '' // TODO: fix
this.controls.showCaptions.setAttribute('disabled', '')
bcap.setAttribute('disabled', '') // TODO: fix
this.controls.openPlaylist.setAttribute('disabled', '')
this.controls.playNext.removeAttribute('disabled')
navNowPlaying.classList.add('d-none') // TODO: fix
@ -678,79 +688,60 @@ Style: Default,${options.defaultSSAStyles}
}
updateDisplay () {
this.player.style.setProperty('--download', this.selectedFile.progress * 100 + '%')
peers.innerHTML = this.selectedTorrent.numPeers
downSpeed.innerHTML = this.prettyBytes(this.selectedTorrent.downloadSpeed) + '/s'
upSpeed.innerHTML = this.prettyBytes(this.selectedTorrent.uploadSpeed) + '/s'
if (this.currentTorrent && this.currentFile) {
this.player.style.setProperty('--download', this.currentFile.progress * 100 + '%')
peers.innerHTML = this.currentTorrent.numPeers
downSpeed.innerHTML = this.prettyBytes(this.currentTorrent.downloadSpeed) + '/s'
upSpeed.innerHTML = this.prettyBytes(this.currentTorrent.uploadSpeed) + '/s'
}
window.requestAnimationFrame(() => setTimeout(() => this.updateDisplay(), 200))
}
showAudio () {
createRadioElement (track, type) {
// type: captions audio
const frag = document.createDocumentFragment()
for (const track of this.video.audioTracks) {
const template = document.createElement('a')
template.classList.add('dropdown-item', 'pointer', 'text-capitalize')
template.innerHTML = (track.language || (!Object.values(this.video.audioTracks).some(track => track.language === 'eng' || track.language === 'en') ? 'eng' : track.label)) + (track.label ? ' - ' + track.label : '')
track.enabled === true ? template.classList.add('text-white') : template.classList.add('text-muted')
template.onclick = () => this.selectAudio(track.id)
frag.appendChild(template)
const input = document.createElement('input')
const label = document.createElement('label')
input.name = `${type}-radio-set`
input.type = 'radio'
input.id = type === 'captions' ? `${type}-${track?.number || 'off'}-radio` : `${type}-${track.id}-radio`
input.value = type === 'captions' ? track?.number || null : track.id
input.checked = type === 'captions' ? track?.number === this.subtitleData.current : track.enabled
label.htmlFor = type === 'captions' ? `${type}-${track?.number || 'off'}-radio` : `${type}-${track.id}-radio`
label.textContent = track
? type === 'captions'
? (track.language || (!Object.values(this.subtitleData.headers).some(header => header.language === 'eng' || header.language === 'en') ? 'eng' : header.type)) + (track.name ? ' - ' + track.name : '')
: (track.language || (!Object.values(this.video.audioTracks).some(track => track.language === 'eng' || track.language === 'en') ? 'eng' : track.label)) + (track.label ? ' - ' + track.label : '')
: 'OFF'
frag.appendChild(input)
frag.appendChild(label)
if (type === 'captions') {
this.controls.selectCaptions.appendChild(frag)
} else {
this.controls.selectAudio.appendChild(frag)
}
audioTracksMenu.innerHTML = ''
audioTracksMenu.appendChild(frag)
}
selectAudio (id) {
for (const track of this.video.audioTracks) {
track.id === id ? track.enabled = true : track.enabled = false
}
this.seek(-0.5) // stupid fix because video freezes up when chaging tracks
this.showAudio()
}
// subtitles, generates content every single time its opened because fuck knows when the parser will find new shit
// this needs to go.... really badly
showCaptions () {
const frag = document.createDocumentFragment()
const off = document.createElement('a')
off.classList.add('dropdown-item', 'pointer')
this.subtitleData.current ? off.classList.add('text-muted') : off.classList.add('text-white')
off.innerHTML = 'OFF'
off.onclick = () => this.selectCaptions()
frag.appendChild(off)
for (const track of this.subtitleData.headers) {
if (track) {
const template = document.createElement('a')
template.classList.add('dropdown-item', 'pointer', 'text-capitalize')
template.innerHTML = (track.language || (!Object.values(this.subtitleData.headers).some(header => header.language === 'eng' || header.language === 'en') ? 'eng' : header.type)) + (track.name ? ' - ' + track.name : '')
if (this.subtitleData.current === track.number) {
template.classList.add('text-white')
} else {
template.classList.add('text-muted')
}
template.onclick = () => this.selectCaptions(track.number)
frag.appendChild(template)
if (id !== undefined) {
for (const track of this.video.audioTracks) {
track.id === id ? track.enabled = true : track.enabled = false
}
this.seek(-0.5) // stupid fix because video freezes up when chaging tracks
}
const timeOffset = document.createElement('div')
timeOffset.classList.add('btn-group', 'w-full', 'pt-5')
timeOffset.setAttribute('role', 'group')
timeOffset.innerHTML = `<button class="btn" type="button" onclick="client.subtitleData.renderer.timeOffset+=1">-1s</button>
<button class="btn" type="button" onclick="client.subtitleData.renderer.timeOffset-=1">+1s</button>`
frag.appendChild(timeOffset)
subMenu.innerHTML = ''
subMenu.appendChild(frag)
}
selectCaptions (trackNumber) {
this.subtitleData.current = trackNumber
this.showCaptions()
if (!this.subtitleData.timeout) {
this.subtitleData.timeout = setTimeout(() => {
this.subtitleData.timeout = undefined
if (this.subtitleData.renderer) {
this.subtitleData.renderer.setTrack(trackNumber ? this.subtitleData.headers[trackNumber].header.slice(0, -1) + Array.from(this.subtitleData.tracks[trackNumber]).join('\n') : this.subtitleData.headers[3].header.slice(0, -1))
}
}, 1000)
if (trackNumber !== undefined) {
this.subtitleData.current = trackNumber
if (!this.subtitleData.timeout) {
this.subtitleData.timeout = setTimeout(() => {
this.subtitleData.timeout = undefined
if (this.subtitleData.renderer) {
this.subtitleData.renderer.setTrack(trackNumber ? this.subtitleData.headers[trackNumber].header.slice(0, -1) + Array.from(this.subtitleData.tracks[trackNumber]).join('\n') : this.subtitleData.headers[3].header.slice(0, -1))
}
}, 1000)
}
}
}
@ -793,7 +784,7 @@ Style: Default,${options.defaultSSAStyles}
this.subtitleData.stream = undefined
this.selectCaptions(this.subtitleData.current)
parser = undefined
this.controls.showCaptions.removeAttribute('disabled')
bcap.removeAttribute('disabled') // TODO: fix
if (!this.video.paused) {
this.video.pause()
this.playVideo()
@ -811,13 +802,19 @@ Style: Default,${options.defaultSSAStyles}
handleSubtitleParser (parser, skipFile) {
parser.once('tracks', tracks => {
this.controls.showCaptions.removeAttribute('disabled')
bcap.removeAttribute('disabled') // TODO: fix
tracks.forEach(track => {
if (!this.subtitleData.tracks[track.number]) {
// overwrite webvtt or other header with custom one
if (track.type !== 'ass') track.header = this.subtitleData.defaultHeader
if (!this.subtitleData.current) this.subtitleData.current = track.number
if (!this.subtitleData.tracks[track.number]) this.subtitleData.tracks[track.number] = new Set()
this.subtitleData.headers[track.number] = track
if (track.type !== 'ass') track.header = this.subtitleData.defaultHeader
if (!this.subtitleData.current) {
this.subtitleData.current = track.number
this.createRadioElement(undefined, 'captions')
}
this.subtitleData.tracks[track.number] = new Set()
this.subtitleData.headers[track.number] = track
this.createRadioElement(track, 'captions')
}
})
})
parser.on('subtitle', (subtitle, trackNumber) => {
@ -898,7 +895,14 @@ Style: Default,${options.defaultSSAStyles}
} else if (client.get(torrentID)) {
this.playTorrent(client.get(torrentID), opts)
} else {
this.add(torrentID, settings.torrent5 ? { store: IdbChunkStore } : {}, torrent => {
this.add(torrentID, {
store: settings.torrent5 ? IdbChunkStore : undefined,
announce: [
'wss://tracker.openwebtorrent.com',
'wss://tracker.sloppyta.co:443/announce',
'wss://hub.bugout.link:443/announce'
]
}, torrent => {
this.playTorrent(torrent, opts)
if (this.streamedDownload) torrent.deselect(0, torrent.pieces.length - 1, false)
})
@ -958,7 +962,12 @@ Style: Default,${options.defaultSSAStyles}
offlineDownload (torrentID, skipVerify) {
const torrent = this.add(torrentID, {
store: IdbChunkStore,
skipVerify: skipVerify
skipVerify: skipVerify,
announce: [
'wss://tracker.openwebtorrent.com',
'wss://tracker.sloppyta.co:443/announce',
'wss://hub.bugout.link:443/announce'
]
})
torrent.on('metadata', async () => {
console.log(torrent)

View file

@ -248,7 +248,6 @@ class SubtitlesOctopus {
self.resize()
} else {
self.video.addEventListener('loadedmetadata', function (e) {
e.target.removeEventListener(e.type, arguments.callee)
self.resize()
}, false)
}