1
0
Fork 0
This commit is contained in:
Arthur K. 2026-05-03 08:18:13 +03:00
commit 57f996f352
Signed by: wzray
GPG key ID: B97F30FDC4636357
3 changed files with 145 additions and 0 deletions

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# PVR Stretch 4:3
Set stretch 4:3 view mode for PVR channels

16
addon.xml Normal file
View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon id="service.pvrstretch"
name="PVR Stretch 4:3"
version="0.1.0"
provider-name="wzray">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
</requires>
<extension point="xbmc.service" library="service.py" start="startup"/>
<extension point="xbmc.addon.metadata">
<summary lang="en_US">Set stretch 4:3 view mode for PVR channels</summary>
<description lang="en_US">Set stretch 4:3 view mode for PVR channels</description>
<platform>all</platform>
<license>MIT</license>
</extension>
</addon>

126
service.py Normal file
View file

@ -0,0 +1,126 @@
import json
import threading
import xbmc
import xbmcaddon
ADDON = xbmcaddon.Addon()
ADDON_ID = ADDON.getAddonInfo("id")
VIEW_MODE = "stretch4x3"
def log(message, level=xbmc.LOGINFO):
xbmc.log(f"[{ADDON_ID}] {message}", level)
def jsonrpc(method, params=None):
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": method,
}
if params is not None:
payload["params"] = params
request = json.dumps(payload)
response = xbmc.executeJSONRPC(request)
try:
data = json.loads(response)
except ValueError:
log(f"Invalid JSON-RPC response from {method}: {response}", xbmc.LOGERROR)
return None
if "error" in data:
log(f"JSON-RPC {method} failed: {data['error']}", xbmc.LOGWARNING)
return None
return data.get("result")
def get_active_video_player_id():
result = jsonrpc("Player.GetActivePlayers")
if not isinstance(result, list):
return None
for player in result:
if player.get("type") == "video":
return player.get("playerid")
return None
def get_current_item(player_id):
result = jsonrpc(
"Player.GetItem",
{
"playerid": player_id,
"properties": ["file"],
},
)
if not isinstance(result, dict):
return None
item = result.get("item")
if not isinstance(item, dict):
return None
return item
class PvrStretchPlayer(xbmc.Player):
def __init__(self, monitor):
super().__init__()
self.monitor = monitor
def onPlayBackStarted(self):
threading.Thread(target=self._apply, daemon=True).start()
def _apply(self):
item = None
for _ in range(100):
if self.monitor.abortRequested():
return
player_id = get_active_video_player_id()
if player_id is not None:
item = get_current_item(player_id)
if item:
break
if self.monitor.waitForAbort(0.1):
return
if not item:
log("No player item found after playback start", xbmc.LOGWARNING)
return
item_type = (item or {}).get("type")
if item_type != "channel":
return
log(f"Applying {VIEW_MODE}: type={item_type}")
result = jsonrpc("Player.SetViewMode", {"viewmode": VIEW_MODE})
if result is None:
log(f"Failed to apply {VIEW_MODE}", xbmc.LOGWARNING)
return
log(f"Applied {VIEW_MODE}: result={result}")
def run():
monitor = xbmc.Monitor()
player = PvrStretchPlayer(monitor)
log("Service started")
while not monitor.abortRequested():
monitor.waitForAbort(1)
del player
log("Service stopped")
if __name__ == "__main__":
run()