mirror of
https://github.com/mmjee/Piped-Material.git
synced 2024-12-06 19:26:36 +01:00
Ported the “Seekbar Preview” feature
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
"marked": "^3.0.8",
|
||||
"mux.js": "^5.14.1",
|
||||
"psychic-tiny-keys": "https://bafybeidtcftvyig2w34aodqfiqiige5zgwjntqtt6ofrqrydf3hydwgv4u.ipfs.cf-ipfs.com/?filename=psychic-tiny-keys-v0.0.1.tar.gz",
|
||||
"quick-lru": "^6.1.1",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"sass-loader": "^10",
|
||||
"shaka-player": "https://f003.backblazeb2.com/file/Bronze8113/shaka-v4.3.4.tar",
|
||||
|
||||
@@ -17,3 +17,11 @@
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.pm-shaka-preview {
|
||||
position: absolute;
|
||||
z-index: 2000;
|
||||
bottom: 0;
|
||||
margin-bottom: 4.5%;
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
style="width: 100%; height: calc(100vh - 48px); background: #000"
|
||||
ref="container"
|
||||
>
|
||||
<canvas height="130" width="230" ref="preview" class="pm-shaka-preview" />
|
||||
<video
|
||||
data-shaka-player
|
||||
style="min-width: 100%;"
|
||||
@@ -15,6 +16,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QuickLRU from 'quick-lru'
|
||||
import shaka from 'shaka-player/dist/shaka-player.ui.js'
|
||||
import 'shaka-player/dist/controls.css'
|
||||
import * as LocaleMatcher from '@formatjs/intl-localematcher'
|
||||
@@ -34,6 +36,8 @@ if (!window.muxjs) {
|
||||
})
|
||||
}
|
||||
|
||||
const ImageLRU = new QuickLRU({ maxSize: 8 })
|
||||
|
||||
export default {
|
||||
props: {
|
||||
video: Object,
|
||||
@@ -80,8 +84,91 @@ export default {
|
||||
this.$refs.videoEl.currentTime = timeInSeconds
|
||||
},
|
||||
|
||||
// Most of the below ‘Storyboard’ code is from Bnyro's PR 2559 in Piped, some minor algorithmic improvements have been added
|
||||
// The ‘Storyboard’ setup – Start
|
||||
setupSeekbarPreview () {
|
||||
if (!this.video.previewFrames) return
|
||||
const seekBar = document.querySelector('.shaka-seek-bar-container')
|
||||
// load the thumbnail preview when the user moves over the seekbar
|
||||
seekBar.addEventListener('mousemove', e => {
|
||||
const position = (this.video.duration * e.clientX) / seekBar.clientWidth
|
||||
this.showSeekbarPreview(position * 1000)
|
||||
})
|
||||
// hide the preview when the user stops hovering the seekbar
|
||||
seekBar.addEventListener('mouseout', () => {
|
||||
this.$refs.preview.style.display = 'none'
|
||||
})
|
||||
},
|
||||
|
||||
async showSeekbarPreview (position) {
|
||||
const frame = this.getFrame(position)
|
||||
const originalImage = await this.getOrLoadImage(frame.url)
|
||||
const seekBar = document.querySelector('.shaka-seek-bar-container')
|
||||
const canvas = this.$refs.preview
|
||||
const ctx = canvas.getContext('2d')
|
||||
|
||||
// get the new sizes for the image to be drawn into the canvas
|
||||
const originalWidth = originalImage.naturalWidth
|
||||
const originalHeight = originalImage.naturalHeight
|
||||
const offsetX = originalWidth * (frame.positionX / frame.framesPerPageX)
|
||||
const offsetY = originalHeight * (frame.positionY / frame.framesPerPageY)
|
||||
const newWidth = originalWidth / frame.framesPerPageX
|
||||
const newHeight = originalHeight / frame.framesPerPageY
|
||||
|
||||
// draw the thumbnail preview into the canvas by cropping only the relevant part
|
||||
ctx.drawImage(originalImage, offsetX, offsetY, newWidth, newHeight, 0, 0, canvas.width, canvas.height)
|
||||
|
||||
// calculate the thumbnail preview offset and display it
|
||||
const centerOffset = position / this.video.duration / 10
|
||||
const left = centerOffset - (canvas.width / seekBar.clientWidth / 1.3) * 100
|
||||
canvas.style.left = `max(2%, min(${left}%, 90%))`
|
||||
canvas.style.display = 'block'
|
||||
},
|
||||
|
||||
// ineffective algorithm to find the thumbnail corresponding to the currently hovered position in the video
|
||||
getFrame (position) {
|
||||
let startPosition = 0
|
||||
const framePage = this.video.previewFrames.at(-1)
|
||||
for (let i = 0; i < framePage.urls.length; i++) {
|
||||
for (let positionY = 0; positionY < framePage.framesPerPageY; positionY++) {
|
||||
for (let positionX = 0; positionX < framePage.framesPerPageX; positionX++) {
|
||||
const endPosition = startPosition + framePage.durationPerFrame
|
||||
if (position >= startPosition && position <= endPosition) {
|
||||
return {
|
||||
url: framePage.urls[i],
|
||||
positionX: positionX,
|
||||
positionY: positionY,
|
||||
framesPerPageX: framePage.framesPerPageX,
|
||||
framesPerPageY: framePage.framesPerPageY
|
||||
}
|
||||
}
|
||||
startPosition = endPosition
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
// creates a new image from an URL
|
||||
async loadImage (url) {
|
||||
const i = new Image()
|
||||
i.src = url
|
||||
await i.decode()
|
||||
return i
|
||||
},
|
||||
|
||||
// The ‘Storyboard’ setup – End
|
||||
|
||||
async getOrLoadImage (url) {
|
||||
let img = ImageLRU.get(url)
|
||||
if (img == null) {
|
||||
img = await this.loadImage(url)
|
||||
ImageLRU.set(url, img)
|
||||
}
|
||||
return img
|
||||
},
|
||||
|
||||
async loadVideo () {
|
||||
console.log('PIPED | LOADING VIDEO')
|
||||
console.log('PM | LOADING VIDEO')
|
||||
const component = this
|
||||
const videoEl = this.$refs.videoEl
|
||||
|
||||
@@ -243,6 +330,7 @@ export default {
|
||||
|
||||
const player = this.$ui.getControls().getPlayer()
|
||||
|
||||
this.setupSeekbarPreview()
|
||||
this.$player = player
|
||||
|
||||
this.$player.configure({
|
||||
|
||||
@@ -5872,6 +5872,11 @@ queue-microtask@^1.2.2:
|
||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||
|
||||
quick-lru@^6.1.1:
|
||||
version "6.1.1"
|
||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-6.1.1.tgz#f8e5bf9010376c126c80c1a62827a526c0e60adf"
|
||||
integrity sha512-S27GBT+F0NTRiehtbrgaSE1idUAJ5bX8dPAQTdylEyNlrdcH5X4Lz7Edz3DYzecbsCluD5zO8ZNEe04z3D3u6Q==
|
||||
|
||||
randombytes@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||
|
||||
Reference in New Issue
Block a user