Skip to content

Commit

Permalink
feat: PiP on mobile
Browse files Browse the repository at this point in the history
feat: better mobile seeking
  • Loading branch information
ThaUnknown committed Jul 11, 2024
1 parent 84b0a55 commit ccb0512
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 9 deletions.
2 changes: 2 additions & 0 deletions capacitor/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
1 change: 1 addition & 0 deletions capacitor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"capacitor-plugin-safe-area": "^2.0.5",
"common": "workspace:*",
"cordova-plugin-navigationbar": "^1.0.31",
"cordova-plugin-pip": "^0.0.2",
"cordova-plugin-screen-orientation": "^3.0.4",
"es6-promise-plugin": "^4.2.2"
}
Expand Down
16 changes: 15 additions & 1 deletion capacitor/src/capacitor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* globals navigationbar */
/* globals navigationbar, PictureInPicture */
import { StatusBar, Style } from '@capacitor/status-bar'
import { SafeArea } from 'capacitor-plugin-safe-area'
import { App } from '@capacitor/app'
Expand Down Expand Up @@ -91,3 +91,17 @@ StatusBar.setOverlaysWebView({ overlay: true })
navigationbar.setUp(true)

// cordova screen orientation plugin is also used, and it patches global screen.orientation.lock

// hook into pip request, and use our own pip implementation, then instantly report exit pip
// this is more like DOM PiP, rather than video PiP
HTMLVideoElement.prototype.requestPictureInPicture = function () {
PictureInPicture.enter(this.videoWidth, this.videoHeight, success => {
this.dispatchEvent(new Event('leavepictureinpicture'))
if (success) document.querySelector('.content-wrapper').requestFullscreen()
}, err => {
this.dispatchEvent(new Event('leavepictureinpicture'))
console.error(err)
})

return Promise.resolve({})
}
15 changes: 7 additions & 8 deletions common/views/Player/Player.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@
if (!subs?.renderer) {
if (video !== document.pictureInPictureElement) {
video.requestPictureInPicture()
resetImmerse()
pip = true
} else {
document.exitPictureInPicture()
Expand All @@ -433,6 +434,7 @@
canvasVideo.remove()
}
pip = true
resetImmerse()
canvasVideo.srcObject = stream
canvasVideo.onloadedmetadata = () => {
canvasVideo.play()
Expand Down Expand Up @@ -612,7 +614,7 @@
if (!noSubs) subs.renderer.resize(video.videoWidth, video.videoHeight)
const renderFrame = () => {
context.drawImage(deband ? deband.canvas : video, 0, 0)
if (!noSubs) context.drawImage(subs.renderer?._canvas, 0, 0, canvas.width, canvas.height)
if (!noSubs && canvas.width && canvas.height) context.drawImage(subs.renderer?._canvas, 0, 0, canvas.width, canvas.height)
loop = video.requestVideoFrameCallback(renderFrame)
}
renderFrame()
Expand Down Expand Up @@ -1107,11 +1109,9 @@
<!-- eslint-disable-next-line svelte/valid-compile -->
<div class='w-full h-full position-absolute toggle-immerse d-none' on:dblclick={toggleFullscreen} on:click|self={toggleImmerse} />
<div class='w-full h-full position-absolute mobile-focus-target d-none' use:click={() => { page = 'player' }} />
<span class='material-symbols-outlined ctrl' class:text-muted={!hasLast} class:disabled={!hasLast} use:click={playLast}> skip_previous </span>
<span class='material-symbols-outlined ctrl' use:click={rewind}> fast_rewind </span>
<span class='material-symbols-outlined ctrl h-full align-items-center justify-content-end w-150 mw-full mr-auto' use:click={rewind}> fast_rewind </span>
<span class='material-symbols-outlined ctrl' data-name='playPause' use:click={playPause}> {ended ? 'replay' : paused ? 'play_arrow' : 'pause'} </span>
<span class='material-symbols-outlined ctrl' use:click={forward}> fast_forward </span>
<span class='material-symbols-outlined ctrl' class:text-muted={!hasNext} class:disabled={!hasNext} use:click={playNext}> skip_next </span>
<span class='material-symbols-outlined ctrl h-full align-items-center w-150 mw-full ml-auto' use:click={forward}> fast_forward </span>
<div class='position-absolute bufferingDisplay' />
{#if currentSkippable}
<button class='skip btn text-dark position-absolute bottom-0 right-0 mr-20 mb-5 font-weight-bold' use:click={skip}>
Expand All @@ -1136,10 +1136,10 @@
<div class='d-flex'>
<span class='material-symbols-outlined ctrl' title='Play/Pause [Space]' data-name='playPause' use:click={playPause}> {ended ? 'replay' : paused ? 'play_arrow' : 'pause'} </span>
{#if hasLast}
<span class='material-symbols-outlined ctrl' title='Last [B]' data-name='playLast' use:click={playLast}> skip_previous </span>
<span class='material-symbols-outlined ctrl' title='Last [B]' use:click={playLast}> skip_previous </span>
{/if}
{#if hasNext}
<span class='material-symbols-outlined ctrl' title='Next [N]' data-name='playNext' use:click={playNext}> skip_next </span>
<span class='material-symbols-outlined ctrl' title='Next [N]' use:click={playNext}> skip_next </span>
{/if}
<div class='d-flex w-auto volume'>
<span class='material-symbols-outlined ctrl' title='Mute [M]' data-name='toggleMute' use:click={toggleMute}> {muted ? 'volume_off' : 'volume_up'} </span>
Expand Down Expand Up @@ -1526,7 +1526,6 @@
@media (pointer: none), (pointer: coarse) {
.bottom .ctrl[data-name='playPause'],
.bottom .ctrl[data-name='playNext'],
.bottom .volume,
.bottom .keybinds {
display: none !important;
Expand Down
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ccb0512

Please sign in to comment.