Skip to content

Commit

Permalink
Merge pull request #99 from ci7lus/chore/wakelock-to-ren
Browse files Browse the repository at this point in the history
スリープ防止(WakeLock)をレンダラーに移す
  • Loading branch information
ci7lus authored Jan 2, 2023
2 parents 6707f01 + b9d91e6 commit 08f472c
Show file tree
Hide file tree
Showing 16 changed files with 106 additions and 77 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@rushstack/eslint-patch": "^1.2.0",
"@tailwindcss/custom-forms": "^0.2.1",
"@tailwindcss/forms": "^0.5.3",
"@types/dom-screen-wake-lock": "^1.0.0",
"@types/mini-css-extract-plugin": "^2.5.1",
"@types/react": "^18.0.24",
"@types/react-dom": "^18.0.8",
Expand Down
7 changes: 6 additions & 1 deletion src/Plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { StateRoot } from "./State"
import {
contentPlayerAudioChannelAtom,
contentPlayerAudioTrackAtom,
contentPlayerIsPlayingAtom,
contentPlayerPositionUpdateTriggerAtom,
contentPlayerScreenshotTriggerAtom,
contentPlayerSpeedAtom,
Expand All @@ -23,6 +22,7 @@ import {
contentPlayerTsFirstPcrSelector,
} from "./atoms/contentPlayerSelectors"
import {
globalContentPlayerIsPlayingFamily,
globalContentPlayerPlayingContentFamily,
globalContentPlayerSelectedServiceFamily,
} from "./atoms/globalFamilies"
Expand Down Expand Up @@ -67,6 +67,10 @@ export const PluginLoader: React.FC<{
fonts: string[]
disabledPluginFileNames: string[]
}> = ({ states, pluginData, fonts, disabledPluginFileNames }) => {
const contentPlayerIsPlayingAtom = globalContentPlayerIsPlayingFamily(
window.id ?? 0
)

const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
if (isLoading === false) {
Expand Down Expand Up @@ -112,6 +116,7 @@ export const PluginLoader: React.FC<{
globalContentPlayerPlayingContentFamily,
globalActiveContentPlayerIdSelector,
globalContentPlayerSelectedServiceFamily,
globalContentPlayerIsPlayingFamily,
contentPlayerPlayingContentAtom:
globalContentPlayerPlayingContentFamily(window.id ?? -1),
contentPlayerServiceSelector,
Expand Down
5 changes: 0 additions & 5 deletions src/atoms/contentPlayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ export const contentPlayerSubtitleEnabledAtom = atom<boolean>({
],
})

export const contentPlayerIsPlayingAtom = atom<boolean>({
key: `${prefix}.isPlaying`,
default: false,
})

export const contentPlayerVolumeAtom = atom<number>({
key: `${prefix}.volume`,
default: 100,
Expand Down
7 changes: 7 additions & 0 deletions src/atoms/globalFamilies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Service } from "../infra/mirakurun/api"

import { ContentPlayerPlayingContent } from "../types/contentPlayer"
import {
globalContentPlayerIsPlayingFamilyKey,
globalContentPlayerPlayingContentFamilyKey,
globalContentPlayerSelectedServiceFamilyKey,
} from "./globalFamilyKeys"
Expand Down Expand Up @@ -44,3 +45,9 @@ export const globalContentPlayerSelectedServiceFamily = atomFamily<
}),
],
})

export const globalContentPlayerIsPlayingFamily = atomFamily<boolean, number>({
key: globalContentPlayerIsPlayingFamilyKey,
default: false,
effects: [syncEffect({ storeKey: RECOIL_SYNC_SHARED_KEY, refine: $.bool() })],
})
2 changes: 2 additions & 0 deletions src/atoms/globalFamilyKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ const prefix = `${pkg.name}.global`
export const globalContentPlayerPlayingContentFamilyKey = `${prefix}.playingContent`

export const globalContentPlayerSelectedServiceFamilyKey = `${prefix}.selectedService`

export const globalContentPlayerIsPlayingFamilyKey = `${prefix}.isPlaying`
52 changes: 49 additions & 3 deletions src/components/contentPlayer/Controller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
contentPlayerAudioTrackAtom,
contentPlayerAudioTracksAtom,
contentPlayerBufferingAtom,
contentPlayerIsPlayingAtom,
contentPlayerIsSeekableAtom,
contentPlayerPlayingPositionAtom,
contentPlayerPlayingTimeAtom,
Expand All @@ -26,7 +25,10 @@ import {
contentPlayerProgramSelector,
contentPlayerServiceSelector,
} from "../../atoms/contentPlayerSelectors"
import { globalContentPlayerSelectedServiceFamily } from "../../atoms/globalFamilies"
import {
globalContentPlayerIsPlayingFamily,
globalContentPlayerSelectedServiceFamily,
} from "../../atoms/globalFamilies"
import { mirakurunServicesAtom } from "../../atoms/mirakurun"
import { controllerSetting, experimentalSetting } from "../../atoms/settings"
import { useRefFromState } from "../../hooks/ref"
Expand All @@ -49,6 +51,10 @@ import "dayjs/locale/ja"
dayjs.locale("ja")

export const CoiledController: React.FC<{ isHide: boolean }> = ({ isHide }) => {
const contentPlayerIsPlayingAtom = globalContentPlayerIsPlayingFamily(
window.id ?? 0
)

const [isVisible, setIsVisible] = useState(false)

const [lastCurMoved, setLastCurMoved] = useState(0)
Expand Down Expand Up @@ -186,7 +192,47 @@ export const CoiledController: React.FC<{ isHide: boolean }> = ({ isHide }) => {
}, [isPlaying])

useEffect(() => {
window.Preload.updateIsPlayingState(isPlaying).catch(console.error)
if (!isPlaying) {
return
}
try {
let isReleased = false
let lock: WakeLockSentinel | null = null
navigator.wakeLock
.request("screen")
.then((locked) => {
lock = locked
if (isReleased) {
lock
.release()
.then(() =>
console.info(
"WakeLock: 既にライフサイクルが終了しているためリリースしました"
)
)
.catch((e) =>
console.warn(
e,
"WakeLock: 既にライフサイクルが終了しているためリリースを試みましたが失敗しました"
)
)
} else {
console.info("WakeLock: 有効になりました")
}
})
.catch((e) => console.warn(e, "WakeLock: 有効にできませんでした"))
return () => {
isReleased = true
if (lock) {
lock
.release()
.then(() => console.info("WakeLock: リリースしました"))
.catch((e) => console.warn(e, "WakeLock: リリースに失敗しました"))
}
}
} catch (error) {
console.error(error, "WakeLock: APIが使用できませんでした")
}
}, [isPlaying])

const startAt = dayjs(program?.startAt).format(
Expand Down
6 changes: 5 additions & 1 deletion src/components/contentPlayer/MirakurunManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { encode as arrayBufferToBase64 } from "base64-arraybuffer"
import React, { useEffect, useRef, useState } from "react"
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"
import {
contentPlayerIsPlayingAtom,
contentPlayerKeyForRestorationAtom,
lastEpgUpdatedAtom,
} from "../../atoms/contentPlayer"
import { contentPlayerServiceSelector } from "../../atoms/contentPlayerSelectors"
import {
globalContentPlayerIsPlayingFamily,
globalContentPlayerPlayingContentFamily,
globalContentPlayerSelectedServiceFamily,
} from "../../atoms/globalFamilies"
Expand All @@ -24,6 +24,10 @@ import { ServiceWithLogoData } from "../../types/mirakurun"
import { generateStreamUrlForMirakurun } from "../../utils/mirakurun"

export const MirakurunManager: React.FC<{}> = () => {
const contentPlayerIsPlayingAtom = globalContentPlayerIsPlayingFamily(
window.id ?? 0
)

const mirakurunSettingValue = useRecoilValue(mirakurunSetting)
const setCompatibility = useSetRecoilState(mirakurunCompatibilityAtom)
const setVersion = useSetRecoilState(mirakurunVersionAtom)
Expand Down
10 changes: 8 additions & 2 deletions src/components/contentPlayer/SubtitleRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { useRecoilValue, useSetRecoilState } from "recoil"
import {
contentPlayerAribSubtitleDataAtom,
contentPlayerDisplayingAribSubtitleDataAtom,
contentPlayerIsPlayingAtom,
contentPlayerIsSeekableAtom,
contentPlayerPositionUpdateTriggerAtom,
contentPlayerSubtitleEnabledAtom,
contentPlayerTsFirstPcrAtom,
} from "../../atoms/contentPlayer"
import { globalContentPlayerPlayingContentFamily } from "../../atoms/globalFamilies"
import {
globalContentPlayerIsPlayingFamily,
globalContentPlayerPlayingContentFamily,
} from "../../atoms/globalFamilies"
import { subtitleSetting } from "../../atoms/settings"
import { SUBTITLE_DEFAULT_FONT } from "../../constants/font"
import { tryBase64ToUint8Array } from "../../utils/string"
Expand All @@ -24,6 +26,10 @@ import {
export const CoiledSubtitleRenderer: React.FC<{
internalPlayingTimeRef: React.MutableRefObject<number>
}> = memo(({ internalPlayingTimeRef }) => {
const contentPlayerIsPlayingAtom = globalContentPlayerIsPlayingFamily(
window.id ?? 0
)

const canvasRef = useRef<HTMLCanvasElement>(null)

const isSubtitleEnabled = useRecoilValue(contentPlayerSubtitleEnabledAtom)
Expand Down
5 changes: 4 additions & 1 deletion src/components/contentPlayer/VideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
contentPlayerAudioTracksAtom,
contentPlayerBufferingAtom,
contentPlayerDisplayingAribSubtitleDataAtom,
contentPlayerIsPlayingAtom,
contentPlayerIsSeekableAtom,
contentPlayerPlayingPositionAtom,
contentPlayerPlayingTimeAtom,
Expand All @@ -32,6 +31,7 @@ import {
contentPlayerServiceSelector,
contentPlayerUrlSelector,
} from "../../atoms/contentPlayerSelectors"
import { globalContentPlayerIsPlayingFamily } from "../../atoms/globalFamilies"
import {
experimentalSetting,
screenshotSetting,
Expand All @@ -47,6 +47,9 @@ export const CoiledVideoPlayer: React.FC<{
internalPlayingTimeRef: React.MutableRefObject<number>
setIsHideController: React.Dispatch<React.SetStateAction<boolean>>
}> = memo(({ internalPlayingTimeRef, setIsHideController }) => {
const contentPlayerIsPlayingAtom = globalContentPlayerIsPlayingFamily(
window.id ?? 0
)
const canvasRef = useRef<HTMLCanvasElement>(null)

const [size, setSize] = useState<[number, number]>([1920, 1080])
Expand Down
1 change: 0 additions & 1 deletion src/constants/ipc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export const REQUEST_INITIAL_DATA = "request-initial-data"
export const RECOIL_STATE_UPDATE = "recoil-state-update"
export const REUQEST_OPEN_WINDOW = "request-open-window"
export const UPDATE_IS_PLAYING_STATE = "update-is-playing-state"
export const EPG_MANAGER = {
REGISTER: "epg-manager-register",
UNREGISTER: "epg-manager-unregister",
Expand Down
54 changes: 13 additions & 41 deletions src/main/index.electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import electron, {
Menu,
shell,
dialog,
powerSaveBlocker,
Notification,
globalShortcut,
session,
Expand All @@ -27,7 +26,10 @@ import Store from "electron-store"
import fontList from "font-list"
import WebChimeraJs from "webchimera.js"
import pkg from "../../package.json"
import { globalContentPlayerPlayingContentFamilyKey } from "../../src/atoms/globalFamilyKeys"
import {
globalContentPlayerIsPlayingFamilyKey,
globalContentPlayerPlayingContentFamilyKey,
} from "../../src/atoms/globalFamilyKeys"
import {
globalActiveContentPlayerIdAtomKey,
globalLastEpgUpdatedAtomKey,
Expand Down Expand Up @@ -55,7 +57,6 @@ import {
SHOW_WINDOW,
TOGGLE_ALWAYS_ON_TOP,
TOGGLE_FULL_SCREEN,
UPDATE_IS_PLAYING_STATE,
REQUEST_SCREENSHOT_BASE_PATH,
ON_SCREENSHOT_REQUEST,
UPDATE_GLOBAL_SCREENSHOT_ACCELERATOR,
Expand Down Expand Up @@ -89,8 +90,6 @@ const contentPlayerWindows: BrowserWindow[] = []
const CONTENT_PLAYER_BOUNDS = `${pkg.name}.contentPlayer.bounds`
const GLOBAL_CONTENT_PLAYER_IDS = `${pkg.name}.global.contentPlayerIds`

const blockerIdBycontentPlayerWindow: { [key: number]: number | null } = {}

const isDev = process.env.NODE_ENV === "development"

let store: Store | null = null
Expand Down Expand Up @@ -632,43 +631,22 @@ ipcMain.handle(REQUEST_INITIAL_DATA, (event) => {
return data
})

ipcMain.handle(UPDATE_IS_PLAYING_STATE, (event, isPlaying: boolean) => {
const windowId = BrowserWindow.fromWebContents(event.sender)?.id
if (!windowId) {
return
}
if (isPlaying) {
const blockerId = blockerIdBycontentPlayerWindow[windowId]
if (typeof blockerId !== "number") {
blockerIdBycontentPlayerWindow[windowId] = powerSaveBlocker.start(
"prevent-display-sleep"
)
}
} else {
const blockerId = blockerIdBycontentPlayerWindow[windowId]
if (typeof blockerId === "number") {
powerSaveBlocker.stop(blockerId)
blockerIdBycontentPlayerWindow[windowId] = null
}
}
})

const states: ObjectLiteral<unknown> = {}
const statesHash: ObjectLiteral<string> = {}

// 生Recoil総括
const recoilStateUpdate = (payload: SerializableKV) => {
for (const window of BrowserWindow.getAllWindows()) {
window.webContents.send(RECOIL_STATE_UPDATE, payload)
}
states[payload.key] = payload.value
}

const updateContentPlayerIds = () => {
recoilStateUpdate({
key: GLOBAL_CONTENT_PLAYER_IDS,
value: contentPlayerWindows.map((w) => w.id),
})
// 生Recoil
states[GLOBAL_CONTENT_PLAYER_IDS] = contentPlayerWindows.map((w) => w.id)
}

ipcMain.handle(RECOIL_STATE_UPDATE, (event, payload: SerializableKV) => {
Expand Down Expand Up @@ -796,6 +774,8 @@ const openWindow = ({
}
})

const isPlayingKey = `${globalContentPlayerIsPlayingFamilyKey}__${window.id}`

window.webContents.on("context-menu", (e, params) => {
vm.runInContext(
"showContextMenu",
Expand All @@ -804,12 +784,12 @@ const openWindow = ({
generateContentPlayerContextMenu(
{
isPlaying:
name === ROUTES.ContentPlayer
? window.id in blockerIdBycontentPlayerWindow &&
blockerIdBycontentPlayerWindow[window.id] !== null
: null,
name === ROUTES.ContentPlayer ? !!states[isPlayingKey] : null,
toggleIsPlaying: () => {
window.webContents.send(UPDATE_IS_PLAYING_STATE)
recoilStateUpdate({
key: isPlayingKey,
value: !states[isPlayingKey],
})
},
isAlwaysOnTop: window.isAlwaysOnTop(),
toggleIsAlwaysOnTop: () => {
Expand Down Expand Up @@ -846,8 +826,6 @@ const openWindow = ({
if (name !== ROUTES["ContentPlayer"]) {
return
}
// 生Recoil
states[globalActiveContentPlayerIdAtomKey] = window.id
recoilStateUpdate({
key: globalActiveContentPlayerIdAtomKey,
value: window.id,
Expand Down Expand Up @@ -925,17 +903,11 @@ const openWindow = ({
const idx = windowMapping[name].indexOf(window)
windowMapping[name].splice(idx, 1)
if (name === ROUTES["ContentPlayer"]) {
const blockerId = blockerIdBycontentPlayerWindow[_id]
if (typeof blockerId === "number") {
powerSaveBlocker.stop(blockerId)
}
const idx = contentPlayerWindows.indexOf(window)
contentPlayerWindows.splice(idx, 1)
updateContentPlayerIds()
if (states[globalActiveContentPlayerIdAtomKey] === _id) {
const value = contentPlayerWindows.slice(0).shift()?.id ?? null
// 生Recoil
states[globalActiveContentPlayerIdAtomKey] = value
recoilStateUpdate({
key: globalActiveContentPlayerIdAtomKey,
value,
Expand Down
Loading

0 comments on commit 08f472c

Please sign in to comment.