feat: dev and build configs

fix: subtitles not rendering in portrait
fix: notch inset safe areas
chore: better code structure for capacitor
feat: capacitor AL login
This commit is contained in:
ThaUnknown 2023-11-19 20:10:03 +01:00
parent 94155bdd59
commit 11356d1646
18 changed files with 183 additions and 70 deletions

View file

@ -6,6 +6,7 @@ android/app/*
android/app/src/*
!android/app/src/main
android/app/src/main/*
!android/app/src/main/AndroidManifest.xml
!android/app/src/main/java
android/app/src/main/java/*
!android/app/src/main/java/watch

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<!-- added scheme rest is generated -->
<data android:scheme="miru" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
</application>
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View file

@ -1,4 +1,6 @@
let config = {
const mode = process.env.NODE_ENV?.trim() || 'development'
const config = {
appId: 'watch.miru',
appName: 'Miru',
webDir: 'build',
@ -16,21 +18,10 @@ let config = {
}
}
switch (process.env.NODE_ENV) {
case 'qa':
config = {
...config
}
break
default:
config = {
...config
// server: {
// url: 'http://localhost:5001/index.html',
// cleartext: true
// }
}
break
if (mode === 'development') {
config.server = {
url: 'http://localhost:5001/index.html',
cleartext: true
}
}
module.exports = config

View file

@ -2,19 +2,19 @@
"name": "capacitor",
"private": true,
"scripts": {
"build:app": "build:web && build:android",
"build:web": "cross-env NODE_ENV=production webpack build",
"build:app": "cross-env NODE_ENV=production run-s build:web build:assets build:android",
"build:web": "webpack build",
"build:android": "cap build android",
"build:ios": "run-s build:app cap-run:ios",
"cap:android-emulator": "cap run android --target=Pixel_XL_API_33 --external --public-host=10.5.0.2 && dev:localhost-bind",
"cap:localhost-bind": "adb reverse tcp:5001 tcp:5001",
"cap:android": "run-s cap:android-emulator cap:localhost-bind",
"cap:assets": "capacitor-assets generate --iconBackgroundColor #17191c --iconBackgroundColorDark #17191c --splashBackgroundColor #17191c --splashBackgroundColorDark #17191c --android",
"cap:ios": "cap sync ios && cap open ios",
"build:ios": "cap build ios",
"build:assets": "capacitor-assets generate --iconBackgroundColor #17191c --iconBackgroundColorDark #17191c --splashBackgroundColor #17191c --splashBackgroundColorDark #17191c --android",
"dev:adb-port": "adb reverse tcp:5001 tcp:5001",
"dev:ios": "run-p dev:start cap-run:ios",
"dev:android": "cap run android",
"dev:android-port": "run-s dev:android dev:adb-port",
"dev:preview": "vite preview",
"dev:start": "run-p dev:webpack cap:android",
"dev:webpack": "webpack serve"
"dev:start": "run-p dev:webpack dev:android-port",
"dev:webpack": "webpack serve",
"test:e2e": "cross-env NODE_ENV=production run-s build:web dev:android"
},
"devDependencies": {
"@capacitor/assets": "^3.0.1",
@ -36,6 +36,8 @@
},
"dependencies": {
"@capacitor/android": "^5.5.1",
"@capacitor/app": "^5.0.6",
"@capacitor/browser": "^5.1.0",
"@capacitor/cli": "^5.5.1",
"@capacitor/core": "^5.5.1",
"@capacitor/ios": "^5.5.1",

View file

@ -0,0 +1,57 @@
/* globals navigationbar */
import { StatusBar, Style } from '@capacitor/status-bar'
import { SafeArea } from 'capacitor-plugin-safe-area'
import { App } from '@capacitor/app'
import { Browser } from '@capacitor/browser'
import { ipcRendererUI, main } from './ipc.js'
main.on('open', url => Browser.open({ url }))
App.addListener('appUrlOpen', ({ url }) => handleProtocol(url))
// schema: miru://key/value
const protocolMap = {
auth: token => sendToken(token),
anime: id => ipcRendererUI.emit('open-anime', id),
w2g: link => ipcRendererUI.emit('w2glink', link),
schedule: () => ipcRendererUI.emit('schedule'),
donate: () => Browser.open({ url: 'https://github.com/sponsors/ThaUnknown/' })
}
const protocolRx = /miru:\/\/([a-z0-9]+)\/(.*)/i
function handleProtocol (text) {
const match = text.match(protocolRx)
if (match) protocolMap[match[1]]?.(match[2])
}
function sendToken (line) {
let token = line.split('access_token=')[1].split('&token_type')[0]
if (token) {
if (token.endsWith('/')) token = token.slice(0, -1)
ipcRendererUI.emit('altoken', token)
}
}
App.getLaunchUrl().then(res => {
if (res) handleProtocol(res.url)
})
SafeArea.addListener('safeAreaChanged', updateInsets)
screen.orientation.addEventListener('change', updateInsets)
async function updateInsets () {
const { insets } = await SafeArea.getSafeAreaInsets()
for (const [key, value] of Object.entries(insets)) {
document.documentElement.style.setProperty(`--safe-area-${key}`, `${value}px`)
}
}
updateInsets()
StatusBar.hide()
StatusBar.setStyle({ style: Style.Dark })
StatusBar.setOverlaysWebView({ overlay: true })
navigationbar.setUp(true)
// cordova screen orientation plugin is also used, and it patches global screen.orientation.lock

View file

@ -1,26 +1,29 @@
import EventEmitter from 'events'
const ipcRendererUI = new EventEmitter()
export const ipcRendererUI = new EventEmitter()
export const main = new EventEmitter()
export default {
emit: (event, data) => {
// ipcRendererUI.emit(event, data)
if (event === 'portRequest') portRequest(data)
main.emit(event, data)
},
on: (event, callback) => {
ipcRendererUI.on(event, (event, ...args) => callback(...args))
ipcRendererUI.on(event, (...args) => callback(...args))
},
once: (event, callback) => {
ipcRendererUI.once(event, (event, ...args) => callback(...args))
ipcRendererUI.once(event, (...args) => callback(...args))
},
off: event => {
ipcRendererUI.removeAllListeners(event)
}
}
main.on('portRequest', portRequest)
async function portRequest (data) {
const { port1, port2 } = new MessageChannel()
window.port = {
globalThis.port = {
onmessage: cb => {
port2.onmessage = ({ type, data }) => cb({ type, data })
},
@ -28,7 +31,7 @@ async function portRequest (data) {
port2.postMessage(a, b)
}
}
await window.controller
await globalThis.controller
ipcRendererUI.emit('port', { ports: [port2] })
ipcRendererWebTorrent.emit('port', { ports: [port1] })
}
@ -37,7 +40,7 @@ export const ipcRendererWebTorrent = new EventEmitter()
const [_platform, arch] = navigator.platform.split(' ')
window.version = {
globalThis.version = {
platform: globalThis.cordova?.platformId,
arch,
version: globalThis.cordova?.version

2
capacitor/src/main.js Normal file
View file

@ -0,0 +1,2 @@
import './webtorrent.js'
import './capacitor.js'

5
capacitor/src/support.js Normal file
View file

@ -0,0 +1,5 @@
// feature support list, overriden per environment
export const SUPPORTS = {
offscreenRender: false
}

View file

@ -1,24 +1,5 @@
/* globals navigationbar */
import TorrentClient from 'common/modules/webtorrent.js'
import { ipcRendererWebTorrent } from './ipc.js'
import { StatusBar, Style } from '@capacitor/status-bar'
import { SafeArea } from 'capacitor-plugin-safe-area'
SafeArea.addListener('safeAreaChanged', data => {
const { insets } = data
for (const [key, value] of Object.entries(insets)) {
document.documentElement.style.setProperty(
`--safe-area-${key}`,
`${value}px`
)
}
})
StatusBar.hide()
StatusBar.setStyle({ style: Style.Dark })
StatusBar.setOverlaysWebView({ overlay: true })
navigationbar.setUp(true)
globalThis.chrome.runtime = { lastError: false, id: 'something' }
@ -33,11 +14,8 @@ const controller = (async () => {
resolve(reg)
return true
}
return false
}
if (!checkState(worker)) {
worker.addEventListener('statechange', ({ target }) => checkState(target))
}
if (!checkState(worker)) worker.addEventListener('statechange', ({ target }) => checkState(target))
})
})()
globalThis.controller = controller

View file

@ -7,7 +7,7 @@ const mode = process.env.NODE_ENV?.trim() || 'development'
/** @type {import('webpack').Configuration} */
const capacitorConfig = {
entry: [join(__dirname, 'src', 'webtorrent.js')],
entry: [join(__dirname, 'src', 'main.js')],
mode,
plugins: [
new webpack.ProvidePlugin({
@ -38,6 +38,7 @@ const alias = {
'bittorrent-dht': false,
'webtorrent/lib/utp.cjs': false,
'@/modules/ipc.js': join(__dirname, 'src', 'ipc.js'),
'@/modules/support.js': join(__dirname, 'src', 'support.js'),
net: join(__dirname, 'src', 'chrome-net.js'),
dgram: join(__dirname, 'src', 'chrome-dgram.js'),
http: 'stream-http',

View file

@ -60,7 +60,7 @@
}
@media (min-width: 769px) {
.page-wrapper {
padding-left: env(safe-area-inset-left, var(--safe-area-left)) !important;
padding-left: max(var(--safe-area-left), env(safe-area-inset-left, 0)) !important;
}
}
</style>

View file

@ -59,4 +59,9 @@
.navbar {
left: unset !important
}
@media (pointer: none), (pointer: coarse) {
.navbar {
display: none;
}
}
</style>

View file

@ -3,6 +3,7 @@ import { toTS, subRx, videoRx } from './util.js'
import { settings } from '@/modules/settings.js'
import { client } from '@/modules/torrent.js'
import clipboard from './clipboard.js'
import { SUPPORTS } from '@/modules/support.js'
const defaultHeader = `[Script Info]
Title: English (US)
@ -158,6 +159,7 @@ export default class Subtitles {
video: this.video,
subContent: defaultHeader,
fonts: this.fonts,
offscreenRender: SUPPORTS.offscreenRender,
fallbackFont: settings.value.font?.name || 'roboto medium',
availableFonts: {
'roboto medium': './Roboto.ttf'

View file

@ -0,0 +1,5 @@
// feature support list, overriden per environment
export const SUPPORTS = {
offscreenRender: true
}

View file

@ -149,14 +149,14 @@ export const defaults = {
rssQuality: '1080',
rssFeedsNew: [['New Releases', 'SubsPlease']],
rssAutoplay: true,
torrentSpeed: 10,
torrentSpeed: 5,
torrentPersist: false,
torrentDHT: false,
torrentPeX: false,
torrentPort: 0,
dhtPort: 0,
missingFont: true,
maxConns: 20,
maxConns: 50,
subtitleLanguage: 'eng',
audioLanguage: 'jpn',
enableDoH: false,

View file

@ -932,7 +932,7 @@
on:loadedmetadata={autoPlay}
on:loadedmetadata={checkAudio}
on:loadedmetadata={clearLoadInterval}
on:leavepictureinpicture={() => (pip = false)} />
on:leavepictureinpicture={() => { pip = false }} />
{#if stats}
<div class='position-absolute top-0 bg-tp p-10 m-15 text-monospace rounded z-50'>
<button class='close' type='button' use:click={toggleStats}><span>×</span></button>
@ -949,10 +949,10 @@
{/if}
<div class='top z-40 row'>
<div class='stats col-4 pl-20'>
<div class='font-weight-bold overflow-hidden text-truncate'>
<div class='font-weight-bold overflow-hidden text-truncate d-none d-md-block'>
{#if media.title}{media.title}{/if}
</div>
<div class='font-weight-normal overflow-hidden text-truncate font-size-16 text-muted'>
<div class='font-weight-normal overflow-hidden text-truncate font-size-16 text-muted d-none d-md-block'>
{#if media.episode}Episode {media.episode}{/if}
{#if media.episode && media.episodeTitle}{' - '}{/if}
{#if media.episodeTitle}{media.episodeTitle}{/if}
@ -1375,9 +1375,10 @@
.bottom .ctrl[data-name='toggleFullscreen'] {
display: none;
}
.top {
padding-top: env(safe-area-inset-top, var(--safe-area-top)) !important;
@media (orientation: portrait) {
.top {
padding-top: max(var(--safe-area-top), env(safe-area-inset-top, 0)) !important;
}
}
}

View file

@ -8,5 +8,4 @@ async function storageQuota (directory) {
return bsize * bavail
}
// @ts-ignore
window.client = new TorrentClient(ipcRenderer, storageQuota, 'node')
globalThis.client = new TorrentClient(ipcRenderer, storageQuota, 'node')

View file

@ -59,6 +59,12 @@ importers:
'@capacitor/android':
specifier: ^5.5.1
version: 5.5.1(@capacitor/core@5.5.1)
'@capacitor/app':
specifier: ^5.0.6
version: 5.0.6(@capacitor/core@5.5.1)
'@capacitor/browser':
specifier: ^5.1.0
version: 5.1.0(@capacitor/core@5.5.1)
'@capacitor/cli':
specifier: ^5.5.1
version: 5.5.1
@ -292,6 +298,14 @@ packages:
'@capacitor/core': 5.5.1
dev: false
/@capacitor/app@5.0.6(@capacitor/core@5.5.1):
resolution: {integrity: sha512-6ZXVdnNmaYILasC/RjQw+yfTmq2ZO7Q3v5lFcDVfq3PFGnybyYQh+RstBrYri+376OmXOXxBD7E6UxBhrMzXGA==}
peerDependencies:
'@capacitor/core': ^5.0.0
dependencies:
'@capacitor/core': 5.5.1
dev: false
/@capacitor/assets@3.0.1(@types/node@20.8.7)(typescript@4.9.5):
resolution: {integrity: sha512-VTJ3ICFuw1IoR3w6bLjpc7VC9slkNBNO4eCVFN0BAltzH04q52J//JUJ4h0F/gEd0cAKtvIcPJXH5aW6uM9JXA==}
engines: {node: '>=10.3.0'}
@ -318,6 +332,14 @@ packages:
- typescript
dev: true
/@capacitor/browser@5.1.0(@capacitor/core@5.5.1):
resolution: {integrity: sha512-7togqchk2Tvq4SmLaWhcrd4x48ES/GEZsceM+29aun7WhxQEVcDU0cJsVdSU2LNFwNhWgPV2GW90etVd1B3OdQ==}
peerDependencies:
'@capacitor/core': ^5.0.0
dependencies:
'@capacitor/core': 5.5.1
dev: false
/@capacitor/cli@5.5.1:
resolution: {integrity: sha512-/oGd2IIc+k1H/fc7tUzP7vqMtZi0gNcJ4/4wUE2kzAnETxxxHXMM/2V62KfjCby/OOAzJbtI7n5OPlnWE9un1A==}
engines: {node: '>=16.0.0'}