Implement basic current game detection
This commit is contained in:
parent
2cbf3ec2c6
commit
9ec9a0cf40
3 changed files with 198 additions and 10 deletions
41
main.py
41
main.py
|
@ -2,11 +2,13 @@ import time
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import pathlib
|
||||||
|
|
||||||
VERSION = "0.5.0"
|
VERSION = "0.6.0"
|
||||||
SETTINGS_LOCATION = "~/.config/powertools.json"
|
HOME_DIR = str(pathlib.Path(os.getcwd()).parent.parent.resolve())
|
||||||
|
DEFAULT_SETTINGS_LOCATION = HOME_DIR + "/.config/powertools/default_settings.json"
|
||||||
LOG_LOCATION = "/tmp/powertools.log"
|
LOG_LOCATION = "/tmp/powertools.log"
|
||||||
FANTASTIC_INSTALL_DIR = "~/homebrew/plugins/Fantastic"
|
FANTASTIC_INSTALL_DIR = HOME_DIR + "/homebrew/plugins/Fantastic"
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -17,8 +19,15 @@ logging.basicConfig(
|
||||||
force = True)
|
force = True)
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.DEBUG)
|
||||||
logging.info(f"PowerTools v{VERSION} https://github.com/NGnius/PowerTools")
|
logging.info(f"PowerTools v{VERSION} https://github.com/NGnius/PowerTools")
|
||||||
|
logging.info(f"CWD: {os.getcwd()} HOME:{HOME_DIR}")
|
||||||
|
|
||||||
|
import sys
|
||||||
|
#import pathlib
|
||||||
|
sys.path.append(str(pathlib.Path(__file__).parent.resolve()))
|
||||||
|
import server as pt_server
|
||||||
|
|
||||||
startup_time = time.time()
|
startup_time = time.time()
|
||||||
|
|
||||||
class CPU:
|
class CPU:
|
||||||
|
@ -120,6 +129,8 @@ class Plugin:
|
||||||
auto_fan = True
|
auto_fan = True
|
||||||
persistent = True
|
persistent = True
|
||||||
modified_settings = False
|
modified_settings = False
|
||||||
|
current_game = None # None means main menu
|
||||||
|
last_recognised_game = None
|
||||||
|
|
||||||
async def get_version(self) -> str:
|
async def get_version(self) -> str:
|
||||||
return VERSION
|
return VERSION
|
||||||
|
@ -245,12 +256,12 @@ class Plugin:
|
||||||
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
||||||
async def _main(self):
|
async def _main(self):
|
||||||
# startup: load & apply settings
|
# startup: load & apply settings
|
||||||
if os.path.exists(SETTINGS_LOCATION):
|
if os.path.exists(DEFAULT_SETTINGS_LOCATION):
|
||||||
settings = read_json(SETTINGS_LOCATION)
|
settings = read_json(DEFAULT_SETTINGS_LOCATION)
|
||||||
logging.debug(f"Loaded settings from {SETTINGS_LOCATION}: {settings}")
|
logging.debug(f"Loaded settings from {DEFAULT_SETTINGS_LOCATION}: {settings}")
|
||||||
else:
|
else:
|
||||||
settings = None
|
settings = None
|
||||||
logging.debug(f"Settings {SETTINGS_LOCATION} does not exist, skipped")
|
logging.debug(f"Settings {DEFAULT_SETTINGS_LOCATION} does not exist, skipped")
|
||||||
if settings is None or settings["persistent"] == False:
|
if settings is None or settings["persistent"] == False:
|
||||||
logging.debug("Ignoring settings from file")
|
logging.debug("Ignoring settings from file")
|
||||||
self.persistent = False
|
self.persistent = False
|
||||||
|
@ -288,12 +299,15 @@ class Plugin:
|
||||||
write_to_sys("/sys/class/hwmon/hwmon5/fan1_target", settings["fan"]["target"])
|
write_to_sys("/sys/class/hwmon/hwmon5/fan1_target", settings["fan"]["target"])
|
||||||
self.dirty = False
|
self.dirty = False
|
||||||
logging.info("Handled saved settings, back-end startup complete")
|
logging.info("Handled saved settings, back-end startup complete")
|
||||||
|
# server setup
|
||||||
|
await pt_server.start(VERSION)
|
||||||
# work loop
|
# work loop
|
||||||
while True:
|
while True:
|
||||||
if self.modified_settings and self.persistent:
|
if self.modified_settings and self.persistent:
|
||||||
self.save_settings(self)
|
self.save_settings(self)
|
||||||
self.modified_settings = False
|
self.modified_settings = False
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
await pt_server.shutdown()
|
||||||
|
|
||||||
# called from main_view::onViewReady
|
# called from main_view::onViewReady
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
|
@ -343,7 +357,16 @@ class Plugin:
|
||||||
def save_settings(self):
|
def save_settings(self):
|
||||||
settings = self.current_settings(self)
|
settings = self.current_settings(self)
|
||||||
logging.info(f"Saving settings to file: {settings}")
|
logging.info(f"Saving settings to file: {settings}")
|
||||||
write_json(SETTINGS_LOCATION, settings)
|
write_json(DEFAULT_SETTINGS_LOCATION, settings)
|
||||||
|
|
||||||
|
# per-game profiles
|
||||||
|
|
||||||
|
async def get_current_game(self) -> str:
|
||||||
|
current_game = pt_server.http_server.game()
|
||||||
|
if current_game is None:
|
||||||
|
return "Menu (default)"
|
||||||
|
else:
|
||||||
|
return f"{current_game.name()} ({current_game.appid()})"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,12 +81,35 @@
|
||||||
function getPersistent() {
|
function getPersistent() {
|
||||||
return call_plugin_method("get_persistent", {});
|
return call_plugin_method("get_persistent", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentGame() {
|
||||||
|
return call_plugin_method("get_current_game", {});
|
||||||
|
}
|
||||||
|
|
||||||
// other logic
|
// other logic
|
||||||
|
|
||||||
async function onReady() {
|
async function onReady() {
|
||||||
await onViewReady();
|
await onViewReady();
|
||||||
|
|
||||||
|
// detect game starts and exits
|
||||||
|
console.log("Injecting game detection code into main window (SP)");
|
||||||
|
await execute_in_tab("SP", false,
|
||||||
|
`SteamClient.Apps.RegisterForGameActionStart((actionType, data) => {
|
||||||
|
console.log("start game", appStore.GetAppOverviewByGameID(data));
|
||||||
|
fetch("http://127.0.0.1:5030/on_game_start/" + data.toString(), {method: "POST", body: JSON.stringify(appStore.GetAppOverviewByGameID(data))}).then((_) => {});
|
||||||
|
});
|
||||||
|
// this seems to not run when I thought (runs right after ^^^, not when game exits)
|
||||||
|
/*SteamClient.Apps.RegisterForGameActionEnd((actionType, data) => {
|
||||||
|
if (data != null && data != undefined) {
|
||||||
|
console.log("stop game", appStore.GetAppOverviewByGameID(data));
|
||||||
|
fetch("http://127.0.0.1:5030/on_game_exit/" + data.toString(), {method: "POST", body: JSON.stringify(appStore.GetAppOverviewByGameID(data))}).then((_) => {});
|
||||||
|
} else {
|
||||||
|
console.log("stop game null");
|
||||||
|
fetch("http://127.0.0.1:5030/on_game_exit_null", {method: "POST", body:data}).then((_) => {});
|
||||||
|
}
|
||||||
|
});*/`
|
||||||
|
);
|
||||||
|
|
||||||
let boostToggle = document.getElementById("boostToggle");
|
let boostToggle = document.getElementById("boostToggle");
|
||||||
setToggleState(boostToggle, await getCPUBoost());
|
setToggleState(boostToggle, await getCPUBoost());
|
||||||
setToggleState(document.getElementById("smtToggle"), await getSMT());
|
setToggleState(document.getElementById("smtToggle"), await getSMT());
|
||||||
|
@ -106,7 +129,10 @@
|
||||||
setToggleState(document.getElementById("persistToggle"), await getPersistent());
|
setToggleState(document.getElementById("persistToggle"), await getPersistent());
|
||||||
// this is unimportant; always do it last
|
// this is unimportant; always do it last
|
||||||
await updateVersion();
|
await updateVersion();
|
||||||
window.setInterval(function() {updateBatteryStats().then(_ => {})}, 5000);
|
window.setInterval(function() {
|
||||||
|
updateBatteryStats().then(_ => {});
|
||||||
|
updateCurrentGame().then(_ => {});
|
||||||
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setCPUNotch(index) {
|
async function setCPUNotch(index) {
|
||||||
|
@ -249,6 +275,12 @@
|
||||||
setToggleState(toggle, !isActive);
|
setToggleState(toggle, !isActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateCurrentGame() {
|
||||||
|
let gameNow = document.getElementById("gameNow");
|
||||||
|
let gameNameNow = await getCurrentGame();
|
||||||
|
gameNow.innerText = gameNameNow;
|
||||||
|
}
|
||||||
|
|
||||||
let versionCount = -1;
|
let versionCount = -1;
|
||||||
async function updateVersion() {
|
async function updateVersion() {
|
||||||
let version = await getVersion();
|
let version = await getVersion();
|
||||||
|
@ -566,6 +598,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gamepaddialog_FieldDescription_2OJfk">Restores settings after a reboot</div>
|
<div class="gamepaddialog_FieldDescription_2OJfk">Restores settings after a reboot</div>
|
||||||
|
<div class="gamepaddialog_Field_S-_La gamepaddialog_WithFirstRow_qFXi6 gamepaddialog_VerticalAlignCenter_3XNvA gamepaddialog_InlineWrapShiftsChildrenBelow_pHUb6 gamepaddialog_WithBottomSeparator_1lUZx gamepaddialog_StandardPadding_XRBFu gamepaddialog_HighlightOnFocus_wE4V6 Panel Focusable" style="--indent-level:0;">
|
||||||
|
<div class="gamepaddialog_FieldLabelRow_H9WOq">
|
||||||
|
<div class="gamepaddialog_FieldLabel_3b0U-">Now Playing</div>
|
||||||
|
<div class="gamepaddialog_FieldChildren_14_HB">
|
||||||
|
<div class="gamepaddialog_LabelFieldValue_5Mylh" id="gameNow"> Littlewood (894940) </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="quickaccesscontrols_PanelSection_2C0g0" style="padding:0px 4px;">
|
<div class="quickaccesscontrols_PanelSection_2C0g0" style="padding:0px 4px;">
|
||||||
|
|
124
server.py
Normal file
124
server.py
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from aiohttp import web
|
||||||
|
|
||||||
|
HOME_DIR = str(pathlib.Path(os.getcwd()).parent.parent.resolve())
|
||||||
|
SETTINGS_DIR = HOME_DIR + "/.config/powertools"
|
||||||
|
|
||||||
|
if not os.path.exists(SETTINGS_DIR):
|
||||||
|
os.mkdir(SETTINGS_DIR)
|
||||||
|
|
||||||
|
http_runner = None
|
||||||
|
http_server = None
|
||||||
|
|
||||||
|
class GameInfo:
|
||||||
|
def __init__(self, gameid: int, game_info: dict):
|
||||||
|
self.gameid = gameid
|
||||||
|
self.game_info = game_info
|
||||||
|
|
||||||
|
def appid(self):
|
||||||
|
return self.game_info["appid"]
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
return self.game_info["display_name"]
|
||||||
|
|
||||||
|
def settings_path(self) -> str:
|
||||||
|
return SETTINGS_DIR + os.pathsep + str(self.appid()) + ".json"
|
||||||
|
|
||||||
|
def load_settings(self) -> dict:
|
||||||
|
settings_path = self.settings_path()
|
||||||
|
if os.exists(settings_path):
|
||||||
|
with open(settings_path, mode="r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def has_settings(self) -> bool:
|
||||||
|
return os.exists(self.settings_path())
|
||||||
|
|
||||||
|
|
||||||
|
class Server(web.Application):
|
||||||
|
|
||||||
|
def __init__(self, version):
|
||||||
|
super().__init__()
|
||||||
|
self.version = version
|
||||||
|
self.current_game = None
|
||||||
|
self.last_recognised_game = None
|
||||||
|
self.add_routes([
|
||||||
|
web.get("/", lambda req: self.index(req)),
|
||||||
|
web.post("/on_game_start/{game_id}", lambda req: self.on_game_start(req)),
|
||||||
|
web.post("/on_game_exit/{game_id}", lambda req: self.on_game_exit(req)),
|
||||||
|
web.post("/on_game_exit_null", lambda req: self.on_game_exit_null(req))
|
||||||
|
])
|
||||||
|
logging.debug("Server init complete")
|
||||||
|
|
||||||
|
def game(self) -> GameInfo:
|
||||||
|
return self.current_game
|
||||||
|
|
||||||
|
def recognised_game(self) -> GameInfo:
|
||||||
|
return self.last_recognised_game
|
||||||
|
|
||||||
|
async def index(self, request):
|
||||||
|
logging.debug("Debug index page accessed")
|
||||||
|
return web.json_response({
|
||||||
|
"name": "PowerTools",
|
||||||
|
"version": self.version,
|
||||||
|
"latest_game_id": self.current_game,
|
||||||
|
"latest_recognised_game_id": self.last_recognised_game,
|
||||||
|
}, headers={"Access-Control-Allow-Origin": "*"})
|
||||||
|
|
||||||
|
async def on_game_start(self, request):
|
||||||
|
game_id = request.match_info["game_id"]
|
||||||
|
data = await request.text()
|
||||||
|
logging.debug(f"on_game_start {game_id} body:\n{data}")
|
||||||
|
try:
|
||||||
|
game_id = int(game_id)
|
||||||
|
data = json.loads(data)
|
||||||
|
except:
|
||||||
|
return web.Response(text="WTF", status=400)
|
||||||
|
self.current_game = GameInfo(game_id, data)
|
||||||
|
if True: # TODO check for game_id in existing profiles
|
||||||
|
self.last_recognised_game = self.current_game # only set this when profile exists
|
||||||
|
# TODO apply profile
|
||||||
|
return web.Response(status=204, headers={"Access-Control-Allow-Origin": "*"})
|
||||||
|
|
||||||
|
async def on_game_exit(self, request):
|
||||||
|
# ignored for now
|
||||||
|
game_id = request.match_info["game_id"]
|
||||||
|
data = await request.text()
|
||||||
|
logging.debug(f"on_game_exit {game_id}")
|
||||||
|
try:
|
||||||
|
game_id = int(game_id)
|
||||||
|
except ValueError:
|
||||||
|
return web.Response(text="WTF", status=400)
|
||||||
|
if self.current_game.gameid == game_id:
|
||||||
|
pass
|
||||||
|
#self.current_game = None
|
||||||
|
# TODO change settings to default
|
||||||
|
return web.Response(status=204, headers={"Access-Control-Allow-Origin": "*"})
|
||||||
|
|
||||||
|
async def on_game_exit_null(self, request):
|
||||||
|
# ignored for now
|
||||||
|
logging.info(f"on_game_exit_null")
|
||||||
|
#self.current_game = None
|
||||||
|
# TODO change settings to default
|
||||||
|
return web.Response(status=204, headers={"Access-Control-Allow-Origin": "*"})
|
||||||
|
|
||||||
|
async def start(version):
|
||||||
|
global http_runner, http_server
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
http_server = Server(version)
|
||||||
|
http_runner = web.AppRunner(http_server)
|
||||||
|
await http_runner.setup()
|
||||||
|
site = web.TCPSite(http_runner, '0.0.0.0', 5030)
|
||||||
|
await site.start()
|
||||||
|
|
||||||
|
async def shutdown(): # never really called
|
||||||
|
global http_runner, http_server
|
||||||
|
if http_runner is not None:
|
||||||
|
await http_runner.cleanup()
|
||||||
|
http_runner = None
|
||||||
|
http_server = None
|
Loading…
Reference in a new issue