diff --git a/materialious/android/app/capacitor.build.gradle b/materialious/android/app/capacitor.build.gradle index 675b2a5b..6f5750f8 100644 --- a/materialious/android/app/capacitor.build.gradle +++ b/materialious/android/app/capacitor.build.gradle @@ -13,6 +13,7 @@ dependencies { implementation project(':capacitor-browser') implementation project(':capacitor-clipboard') implementation project(':capacitor-screen-orientation') + implementation project(':capacitor-status-bar') implementation project(':capgo-inappbrowser') implementation project(':mediagrid-capacitor-native-audio') implementation project(':capacitor-nodejs') diff --git a/materialious/android/capacitor.settings.gradle b/materialious/android/capacitor.settings.gradle index eb22a4ad..5afe2907 100644 --- a/materialious/android/capacitor.settings.gradle +++ b/materialious/android/capacitor.settings.gradle @@ -14,6 +14,9 @@ project(':capacitor-clipboard').projectDir = new File('../node_modules/@capacito include ':capacitor-screen-orientation' project(':capacitor-screen-orientation').projectDir = new File('../node_modules/@capacitor/screen-orientation/android') +include ':capacitor-status-bar' +project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android') + include ':capgo-inappbrowser' project(':capgo-inappbrowser').projectDir = new File('../node_modules/@capgo/inappbrowser/android') diff --git a/materialious/package-lock.json b/materialious/package-lock.json index 364f1a23..f6c19504 100644 --- a/materialious/package-lock.json +++ b/materialious/package-lock.json @@ -16,6 +16,7 @@ "@capacitor/clipboard": "^6.0.1", "@capacitor/core": "^6.1.2", "@capacitor/screen-orientation": "^6.0.2", + "@capacitor/status-bar": "^6.0.1", "@capgo/inappbrowser": "^6.6.8", "@ffmpeg/ffmpeg": "^0.12.10", "@mediagrid/capacitor-native-audio": "^1.0.0", @@ -2200,6 +2201,15 @@ "@capacitor/core": "^6.0.0" } }, + "node_modules/@capacitor/status-bar": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-6.0.1.tgz", + "integrity": "sha512-Usd9hZZQVAqy+jJfL7jRcYI7dcsxN09Na1yttwdl+F1bk3Ztoukk7CGPDm5VgKUSs53ihQBOy1+sczCACxhNiw==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^6.0.0" + } + }, "node_modules/@capgo/inappbrowser": { "version": "6.6.8", "resolved": "https://registry.npmjs.org/@capgo/inappbrowser/-/inappbrowser-6.6.8.tgz", diff --git a/materialious/package.json b/materialious/package.json index 8a6f85cc..d48a739f 100644 --- a/materialious/package.json +++ b/materialious/package.json @@ -51,6 +51,7 @@ "@capacitor/clipboard": "^6.0.1", "@capacitor/core": "^6.1.2", "@capacitor/screen-orientation": "^6.0.2", + "@capacitor/status-bar": "^6.0.1", "@capgo/inappbrowser": "^6.6.8", "@ffmpeg/ffmpeg": "^0.12.10", "@mediagrid/capacitor-native-audio": "^1.0.0", diff --git a/materialious/src/lib/Player.svelte b/materialious/src/lib/Player.svelte index b4d1c17f..48479158 100644 --- a/materialious/src/lib/Player.svelte +++ b/materialious/src/lib/Player.svelte @@ -3,13 +3,15 @@ import { page } from '$app/stores'; import { Capacitor } from '@capacitor/core'; + import { ScreenOrientation } from '@capacitor/screen-orientation'; + import { StatusBar } from '@capacitor/status-bar'; import { AudioPlayer } from '@mediagrid/capacitor-native-audio'; import type { Page } from '@sveltejs/kit'; import { SponsorBlock, type Category, type Segment } from 'sponsorblock-api'; import { onDestroy, onMount } from 'svelte'; import { _ } from 'svelte-i18n'; import { get } from 'svelte/store'; - import type { MediaTimeUpdateEvent, PlayerSrc } from 'vidstack'; + import type { FullscreenChangeEvent, MediaTimeUpdateEvent, PlayerSrc } from 'vidstack'; import type { MediaPlayerElement } from 'vidstack/elements'; import { deleteVideoProgress, getVideoProgress, saveVideoProgress } from './Api'; import type { VideoPlay } from './Api/model'; @@ -26,6 +28,7 @@ miniPlayerSrcStore, playerAlwaysLoopStore, playerAndroidBgPlayer, + playerAndroidLockOrientation, playerAutoPlayStore, playerProxyVideosStore, playerSavePlaybackPositionStore, @@ -344,57 +347,80 @@ await loadPlayerPos(); }); - if ( - Capacitor.getPlatform() === 'android' && - get(playerAndroidBgPlayer) && - data.video.adaptiveFormats.length > 0 - ) { - const highestBitrateAudio = data.video.adaptiveFormats - .filter((format) => format.type.startsWith('audio/')) - .reduce((prev, current) => { - return parseInt(prev.bitrate) > parseInt(current.bitrate) ? prev : current; - }); + if (Capacitor.getPlatform() === 'android' && data.video.adaptiveFormats.length > 0) { + if (get(playerAndroidBgPlayer)) { + const highestBitrateAudio = data.video.adaptiveFormats + .filter((format) => format.type.startsWith('audio/')) + .reduce((prev, current) => { + return parseInt(prev.bitrate) > parseInt(current.bitrate) ? prev : current; + }); - const audioId = { audioId: data.video.videoId }; + const audioId = { audioId: data.video.videoId }; - let isPlayingInBackground = false; + let isPlayingInBackground = false; - await AudioPlayer.create({ - ...audioId, - audioSource: !data.video.fallbackPatch - ? proxyVideoUrl(highestBitrateAudio.url) - : highestBitrateAudio.url, - friendlyTitle: data.video.title, - useForNotification: true, - loop: player.loop, - isBackgroundMusic: false - }); - - AudioPlayer.onAppGainsFocus(audioId, async () => { - if (!isPlayingInBackground) return; - - isPlayingInBackground = false; - - await AudioPlayer.pause(audioId); - - const audioPlayerTime = await AudioPlayer.getCurrentTime(audioId); - - player.currentTime = Math.round(audioPlayerTime.currentTime); - await player.play(); - }); - - AudioPlayer.onAppLosesFocus(audioId, async () => { - if (player.paused) return; - - isPlayingInBackground = true; - await AudioPlayer.play(audioId); - await AudioPlayer.seek({ + await AudioPlayer.create({ ...audioId, - timeInSeconds: Math.round(player.currentTime) + audioSource: !data.video.fallbackPatch + ? proxyVideoUrl(highestBitrateAudio.url) + : highestBitrateAudio.url, + friendlyTitle: data.video.title, + useForNotification: true, + loop: player.loop, + isBackgroundMusic: false }); - }); - await AudioPlayer.initialize(audioId); + AudioPlayer.onAppGainsFocus(audioId, async () => { + if (!isPlayingInBackground) return; + + isPlayingInBackground = false; + + await AudioPlayer.pause(audioId); + + const audioPlayerTime = await AudioPlayer.getCurrentTime(audioId); + + player.currentTime = Math.round(audioPlayerTime.currentTime); + await player.play(); + }); + + AudioPlayer.onAppLosesFocus(audioId, async () => { + if (player.paused) return; + + isPlayingInBackground = true; + await AudioPlayer.play(audioId); + await AudioPlayer.seek({ + ...audioId, + timeInSeconds: Math.round(player.currentTime) + }); + }); + + await AudioPlayer.initialize(audioId); + } + + if (get(playerAndroidLockOrientation)) { + const videoFormats = data.video.adaptiveFormats.filter((format) => + format.type.startsWith('video/') + ); + + const originalOrigination = await ScreenOrientation.orientation(); + player.addEventListener('fullscreen-change', async (event: FullscreenChangeEvent) => { + if (event.detail && videoFormats[0].resolution) { + const widthHeight = videoFormats[0].resolution.split('x'); + + if (widthHeight.length !== 2) return; + + if (Number(widthHeight[0]) > Number(widthHeight[1])) { + await StatusBar.setOverlaysWebView({ overlay: true }); + await ScreenOrientation.lock({ orientation: 'landscape' }); + } else { + await ScreenOrientation.lock({ orientation: 'portrait' }); + } + } else { + await StatusBar.setOverlaysWebView({ overlay: false }); + await ScreenOrientation.lock({ orientation: originalOrigination.type }); + } + }); + } } } else { playerIsLive = true; diff --git a/materialious/src/lib/Settings.svelte b/materialious/src/lib/Settings.svelte index ecb0bc15..60550754 100644 --- a/materialious/src/lib/Settings.svelte +++ b/materialious/src/lib/Settings.svelte @@ -25,6 +25,7 @@ interfaceSearchSuggestionsStore, playerAlwaysLoopStore, playerAndroidBgPlayer, + playerAndroidLockOrientation, playerAutoPlayStore, playerAutoplayNextByDefaultStore, playerListenByDefaultStore, @@ -386,6 +387,22 @@ + +
+ +
{/if} {#if Capacitor.isNativePlatform()} diff --git a/materialious/src/lib/i18n/locales/en.json b/materialious/src/lib/i18n/locales/en.json index a2ad1f6a..6c118fa4 100644 --- a/materialious/src/lib/i18n/locales/en.json +++ b/materialious/src/lib/i18n/locales/en.json @@ -127,7 +127,8 @@ "dash": "Dash", "silenceSkipper": "Silence skipper (Experimental)", "youtubeJsFallback": "Local video processing fallback", - "youtubeJsAlways": "Always use local video processing" + "youtubeJsAlways": "Always use local video processing", + "lockOrientation": "Orientation locked to aspect ratio" }, "bookmarklet": "Bookmarklet", "instanceUrl": "Instance URL", diff --git a/materialious/src/lib/store.ts b/materialious/src/lib/store.ts index 63aa0ca0..c1d0da0d 100644 --- a/materialious/src/lib/store.ts +++ b/materialious/src/lib/store.ts @@ -41,6 +41,7 @@ export const playerMiniPlayerStore = persisted('miniPlayer', true); export const playerYouTubeJsFallback = persisted('youTubeJsFallback', true); export const playerYouTubeJsAlways = persisted('youTubeJsAlways', false); export const playerAndroidBgPlayer = persisted('androidBgPlayer', true); +export const playerAndroidLockOrientation = persisted('androidLockOrientation', true); export const returnYtDislikesStore = persisted('returnYtDislikes', false); export const returnYTDislikesInstanceStore: Writable = persisted(