Private
Public Access
Prepare webOSbrew publishing audit and safe symlink autostart
This commit is contained in:
1 parent
aaa8aa82e6
commit
b81cb9a8a0
16 files changed
+185
-31
No files matched your search
@@ -10,3 +10,4 @@
|
||||
*.ipk binary
|
||||
*.mp4 binary
|
||||
service/histogram-service binary
|
||||
*.sh text eol=lf
|
||||
@@ -21,3 +21,5 @@ test-interpolation
|
||||
test-layout
|
||||
service/led-mapping.txt
|
||||
service/led-interpolation.txt
|
||||
|
||||
test-autostart
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "org.webosbrew.histogramhyperion",
|
||||
"version": "0.6.1",
|
||||
"type": "web",
|
||||
"title": "HyperDRM",
|
||||
"appDescription": "Ambient Light für webOS und Hyperion",
|
||||
"iconUri": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/app/icon.png",
|
||||
"sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM",
|
||||
"rootRequired": true,
|
||||
"ipkUrl": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/HyperDRM_0.6.1_arm.ipk",
|
||||
"ipkHash": {
|
||||
"sha256": "164f8e18139fbd931de5999d744f0633cca8c979570727db81777ba430d41f29"
|
||||
},
|
||||
"ipkSize": 1163172
|
||||
}
|
||||
Binary file not shown.
@@ -25,7 +25,7 @@ Only the own service is modified. No Hue, LG library, driver or firmware binarie
|
||||
|
||||
## Installation
|
||||
|
||||
The current package is [HyperDRM_0.6.0_arm.ipk](HyperDRM_0.6.0_arm.ipk). Install it using the TV's webOS/Homebrew package installation workflow.
|
||||
The current package is [HyperDRM_0.6.1_arm.ipk](HyperDRM_0.6.1_arm.ipk). Install it using the TV's webOS/Homebrew package installation workflow.
|
||||
|
||||
Elevate the installed own service through Homebrew Channel:
|
||||
|
||||
@@ -41,7 +41,7 @@ The internal app/service IDs remain `org.webosbrew.histogramhyperion` and `org.w
|
||||
|
||||
The app's **Autostart: Ein/Aus** switch controls the own hook `/var/lib/webosbrew/init.d/60-histogramhyperion`. Homebrew Channel runs it during boot after service elevation. It retries start while the TV and Hyperion initialize, with up to 120 attempts separated by five seconds. The Homebrew failsafe can suppress boot hooks.
|
||||
|
||||
**Stoppen** ends the current capture session and leaves the saved autostart preference unchanged. Turning autostart off removes the own hook and cancels waiting boot attempts. A foreign file or symlink at that path will not be overwritten.
|
||||
**Stoppen** ends the current capture session and leaves the saved autostart preference unchanged. The hook is a symlink to `boot.sh` inside the service container. Removal leaves a harmless dangling link; the script also exits when its service target is absent. Turning autostart off removes the own hook and cancels waiting boot attempts. A foreign file or symlink at that path will not be overwritten.
|
||||
|
||||
Boot log: `/var/lib/webosbrew/histogramhyperion-boot.log`.
|
||||
|
||||
@@ -52,6 +52,7 @@ Use an ARM EABI cross-compiler and Python 3:
|
||||
```sh
|
||||
arm-linux-gnueabi-gcc -Wall -Wextra -Werror -O2 -rdynamic native/service.c -ldl -o service/histogram-service
|
||||
python3 build_package.py
|
||||
python3 build_manifest.py
|
||||
```
|
||||
|
||||
The package builder bundles only the own app, native executable, metadata and logo assets. A built executable and current IPK are included for the tested platform.
|
||||
@@ -67,7 +68,7 @@ arm-linux-gnueabi-gcc -Wall -Wextra -Werror -O2 native/test_layout.c -ldl -o tes
|
||||
arm-linux-gnueabi-gcc -Wall -Wextra -Werror -O2 native/test_interpolation.c -o test-interpolation
|
||||
```
|
||||
|
||||
The tests passed on the G4. Boot-hook invocation started a stopped service; an actual cold boot has not yet been tested. Autostart activation was tested; deactivation is implemented but has not yet been practically tested on the TV.
|
||||
The tests passed on the G4. Boot-hook invocation started a stopped service; an actual cold boot has not yet been tested. Isolated ARM tests also cover autostart deactivation, legacy-hook migration, foreign-hook protection and removal of the target container.
|
||||
|
||||
`calibration-gradient.mp4` is the own red/green coordinate ramp used for calibration. `spatial-calibration.json` and `spatial-interpolation.json` record the calibration and example layout. The offline mapping scripts require locally obtained `calibration-samples.jsonl` and `serverinfo.json`; these diagnostic snapshots are not distributed. Runtime mapping is implemented in `native/layout.h` and reads the actual Hyperion layout.
|
||||
|
||||
@@ -76,3 +77,7 @@ To regenerate the test video, install `imageio-ffmpeg` in your Python environmen
|
||||
## Logo
|
||||
|
||||
The logo master is `app/logo.png`, with 80 px and 130 px installation icons.
|
||||
|
||||
## Publishing status
|
||||
|
||||
See [the publishing review](docs/publishing-review.md) for the requirements audit and unresolved submission conditions. This repository is not a claim that webOSbrew has approved the app.
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"id": "org.webosbrew.histogramhyperion", "version": "0.6.0", "vendor": "Local development", "type": "web", "main": "index.html", "title": "HyperDRM", "icon": "icon.png", "resolution": "1920x1080", "disableBackHistoryAPI": true, "largeIcon": "large-icon.png", "appDescription": "Ambient Light für webOS und Hyperion"}
|
||||
{"id": "org.webosbrew.histogramhyperion", "version": "0.6.1", "vendor": "Local development", "type": "web", "main": "index.html", "title": "HyperDRM", "icon": "icon.png", "resolution": "1920x1080", "disableBackHistoryAPI": true, "largeIcon": "large-icon.png", "appDescription": "Ambient Light für webOS und Hyperion", "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM"}
|
||||
@@ -0,0 +1,14 @@
|
||||
"""Describe the exact built IPK for Homebrew Channel."""
|
||||
import hashlib, json
|
||||
from pathlib import Path
|
||||
ROOT=Path(__file__).resolve().parent
|
||||
BASE='https://gitea.adnau.de/matze19999/HyperDRM'
|
||||
RAW=BASE+'/raw/branch/main/'
|
||||
app=json.loads((ROOT/'app/appinfo.json').read_text(encoding='utf-8'))
|
||||
ipk=ROOT/('HyperDRM_'+app['version']+'_arm.ipk')
|
||||
data=ipk.read_bytes()
|
||||
manifest={key:app[key] for key in ('id','version','type','title','appDescription')}
|
||||
manifest.update(iconUri=RAW+'app/icon.png',sourceUrl=BASE,rootRequired=True,
|
||||
ipkUrl=RAW+ipk.name,ipkHash={'sha256':hashlib.sha256(data).hexdigest()},ipkSize=len(data))
|
||||
(ROOT/'HyperDRM.manifest.json').write_text(json.dumps(manifest,indent=2,ensure_ascii=False)+'\n',encoding='utf-8')
|
||||
print('Manifest:',ipk.name,len(data),'bytes',manifest['ipkHash']['sha256'])
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
"""Package own app and executable; no Signify or LG binaries are included."""
|
||||
import io, json, struct, tarfile, zlib
|
||||
import io, json, tarfile
|
||||
from pathlib import Path
|
||||
ROOT=Path(__file__).resolve().parent
|
||||
ID='org.webosbrew.histogramhyperion'
|
||||
VERSION=json.loads((ROOT/'app/appinfo.json').read_text())['version']
|
||||
VERSION=json.loads((ROOT/'app/appinfo.json').read_text(encoding='utf-8'))['version']
|
||||
def tar_bytes(entries):
|
||||
stream=io.BytesIO()
|
||||
with tarfile.open(fileobj=stream,mode='w:gz') as tar:
|
||||
@@ -14,7 +14,7 @@ def tar_bytes(entries):
|
||||
entries=[]
|
||||
for directory,target in [('app','applications/'+ID),('service','services/'+ID+'.service'),('package','packages/'+ID)]:
|
||||
for path in sorted((ROOT/directory).iterdir()):
|
||||
if path.is_file() and path.name not in {"led-mapping.txt", "led-interpolation.txt"}:entries.append(('usr/palm/'+target+'/'+path.name,path.read_bytes(),0o755 if path.name=='histogram-service' else 0o644))
|
||||
if path.is_file() and path.name not in {"led-mapping.txt", "led-interpolation.txt"}:entries.append(('usr/palm/'+target+'/'+path.name,path.read_bytes(),0o755 if path.name in {'histogram-service','boot.sh'} else 0o644))
|
||||
control=f'Package: {ID}\nVersion: {VERSION}\nArchitecture: arm\nMaintainer: Local development\nDescription: HyperDRM ambient light for webOS and Hyperion\nSection: misc\nPriority: optional\n\n'.encode()
|
||||
members=[('debian-binary',b'2.0\n'),('control.tar.gz',tar_bytes([('control',control,0o644)])),('data.tar.gz',tar_bytes(entries))]
|
||||
out=bytearray(b'!<arch>\n')
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# webOSbrew publishing review
|
||||
|
||||
Requirements: https://www.webosbrew.org/develop/guides/publishing/rules/
|
||||
Reviewed: 2026-10-06. No submission has been opened.
|
||||
|
||||
## Human review and disclosure
|
||||
|
||||
The implementation and original icon were produced with substantial AI assistance. The owner directed development and tested visual behavior on a real LG G4 with webOS 24. These user tests do not establish that a human has reviewed the entire source. Before submission, a maintainer must meaningfully review the implementation and be able to explain its design; the submission's AI disclosure must reflect the actual history. Removing creation notes does not change that history. The generated icon should be reviewed or replaced by the owner, according to the recommendation that icons and descriptions be the author's own work.
|
||||
|
||||
Design review points: histogram bin width and RGB averages; LG developer-marker lifetime; bounded Hyperion layout parsing; interpolation/calibration limits; black-bar preset transitions; root-only methods; boot-hook migration; source-transition retries and cancellation.
|
||||
|
||||
## DRM and content
|
||||
|
||||
No media, DRM keys, ROMs, account bypasses or third-party capture binaries are distributed. The calibration video is a locally generated coordinate ramp. The app sends RGB color values rather than video frames.
|
||||
|
||||
The capture initializer temporarily creates `/var/luna/preferences/vt_devmode` to pass LG's developer gate. Although no decryption or DRM patch is implemented, it has not been established whether the resulting access to color data during protected playback is acceptable under webOSbrew's prohibition of DRM circumvention. This must be reviewed explicitly before submission. Do not certify DRM compliance solely because only colors are output.
|
||||
|
||||
## Hardware and removal
|
||||
|
||||
No writes to signed system partitions. Writes outside the service container are limited to the own Homebrew autostart symlink, bounded boot log and transient developer marker. A guardian removes the own marker after initialization or process termination; a previously existing marker is preserved. Concurrent writes/power loss remain review considerations.
|
||||
|
||||
The boot hook is a symlink to `service/boot.sh` in the installed container. The script checks for its executable and service metadata before acting, checks them again on every retry, and exits when the hook is disabled or the target is removed. Only an exact known legacy own hook is migrated; foreign files/symlinks are rejected. Logs are truncated at each invocation and per-attempt output is bounded.
|
||||
|
||||
## Source, licence and release
|
||||
|
||||
Public repository page and raw README access were verified without credentials (HTTP 200); the API restricts anonymous requests. An identifiable project licence must be chosen by the owner. No vendored proprietary libraries are shipped. A release manifest must record the exact IPK hash/size and root requirement. The apps-repo package must use pool `main`, a public sourceUrl and public HTTPS manifest/IPK/icon URLs. No listing is ready until those URLs resolve without credentials.
|
||||
|
||||
## Evidence and remaining checks
|
||||
|
||||
G4/webOS 24: original capture, spatial output, color boost, dynamic layout tests (50/500), black-bar classification and boot-hook invocation tested. Other models are unsupported until tested. Autostart symlink enable/disable, exact legacy migration, rejection of foreign files/symlinks, temporary-file collision and missing-target removal passed in an isolated ARM test on the TV. Version 0.6.1 was installed and started on the G4; the existing copied production hook migrated to the correct container symlink. Boot script syntax passed on the TV. Actual cold boot and clean-state installation/removal have not yet been demonstrated. Public listing eligibility remains pending human and DRM review, release URL validation and licence choice. The runtime reports Rockhopper 10.2.2-57 and device SoC o24; these measured values are used for the package requirements rather than an unverified minimum release.
|
||||
+30
-22
@@ -1,28 +1,36 @@
|
||||
#ifndef HISTOGRAM_AUTOSTART_H
|
||||
#define HISTOGRAM_AUTOSTART_H
|
||||
#define BOOT_HOOK "/var/lib/webosbrew/init.d/60-histogramhyperion"
|
||||
static const char boot_script[] = "#!/bin/sh\n# Histogram Hyperion own boot hook v1\n(\n attempt=0\n while [ -x /var/lib/webosbrew/init.d/60-histogramhyperion ] && [ \"$attempt\" -lt 120 ]; do\n result=$(timeout 12 luna-send -n 1 luna://org.webosbrew.histogramhyperion.service/start '{}' 2>&1)\n case \"$result\" in\n *'\"running\":true'*) exit 0 ;;\n esac\n attempt=$((attempt + 1))\n sleep 5\n done\n echo 'Histogram Hyperion boot start cancelled or timed out'\n) >/var/lib/webosbrew/histogramhyperion-boot.log 2>&1 </dev/null &\nexit 0\n";
|
||||
static bool boot_enabled(void){return access(BOOT_HOOK,X_OK)==0;}
|
||||
static bool set_boot(bool enabled){
|
||||
struct stat st;
|
||||
if(lstat(BOOT_HOOK,&st)==0){
|
||||
if(!S_ISREG(st.st_mode))return false;
|
||||
char existing[sizeof(boot_script)];int fd=open(BOOT_HOOK,O_RDONLY|O_NOFOLLOW|O_CLOEXEC);if(fd<0)return false;
|
||||
ssize_t size=read(fd,existing,sizeof(existing));close(fd);
|
||||
if(size!=(ssize_t)(sizeof(boot_script)-1) || memcmp(existing,boot_script,(size_t)size)!=0)return false;
|
||||
if(!enabled)return unlink(BOOT_HOOK)==0;
|
||||
return chmod(BOOT_HOOK,0755)==0;
|
||||
#ifndef BOOT_DIRECTORY
|
||||
#define BOOT_DIRECTORY "/var/lib/webosbrew/init.d"
|
||||
#endif
|
||||
#ifndef BOOT_SCRIPT
|
||||
#define BOOT_SCRIPT "/media/developer/apps/usr/palm/services/org.webosbrew.histogramhyperion.service/boot.sh"
|
||||
#endif
|
||||
#define BOOT_HOOK BOOT_DIRECTORY "/60-histogramhyperion"
|
||||
/* Exact pre-0.6.1 hook; only this known own file may be migrated. */
|
||||
static const char legacy_boot_script[] = "#!/bin/sh\n# Histogram Hyperion own boot hook v1\n(\n attempt=0\n while [ -x /var/lib/webosbrew/init.d/60-histogramhyperion ] && [ \"$attempt\" -lt 120 ]; do\n result=$(timeout 12 luna-send -n 1 luna://org.webosbrew.histogramhyperion.service/start '{}' 2>&1)\n case \"$result\" in\n *'\"running\":true'*) exit 0 ;;\n esac\n attempt=$((attempt + 1))\n sleep 5\n done\n echo 'Histogram Hyperion boot start cancelled or timed out'\n) >/var/lib/webosbrew/histogramhyperion-boot.log 2>&1 </dev/null &\nexit 0\n";
|
||||
/* 0: absent, 1: own legacy copy, 2: own symlink, -1: foreign/error. */
|
||||
static int boot_hook_kind(void){
|
||||
struct stat st;if(lstat(BOOT_HOOK,&st)!=0)return errno==ENOENT?0:-1;
|
||||
if(S_ISLNK(st.st_mode)){
|
||||
char target[sizeof(BOOT_SCRIPT)+1];ssize_t n=readlink(BOOT_HOOK,target,sizeof(target));
|
||||
return n==(ssize_t)(sizeof(BOOT_SCRIPT)-1) && memcmp(target,BOOT_SCRIPT,(size_t)n)==0?2:-1;
|
||||
}
|
||||
if(errno!=ENOENT)return false;
|
||||
if(!enabled)return true;
|
||||
if(mkdir("/var/lib/webosbrew",0755)!=0 && errno!=EEXIST)return false;
|
||||
if(mkdir("/var/lib/webosbrew/init.d",0755)!=0 && errno!=EEXIST)return false;
|
||||
int fd=open(BOOT_HOOK ".tmp",O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW,0700);if(fd<0)return false;
|
||||
size_t used=0;bool ok=true;
|
||||
while(used<sizeof(boot_script)-1){ssize_t n=write(fd,boot_script+used,sizeof(boot_script)-1-used);if(n<=0){ok=false;break;}used+=(size_t)n;}
|
||||
if(ok)ok=fchmod(fd,0755)==0 && fsync(fd)==0;
|
||||
if(close(fd)!=0)ok=false;
|
||||
if(ok)ok=rename(BOOT_HOOK ".tmp",BOOT_HOOK)==0;
|
||||
if(!S_ISREG(st.st_mode))return -1;
|
||||
char data[sizeof(legacy_boot_script)];int fd=open(BOOT_HOOK,O_RDONLY|O_NOFOLLOW|O_CLOEXEC);if(fd<0)return -1;
|
||||
ssize_t n=read(fd,data,sizeof(data));close(fd);
|
||||
return n==(ssize_t)(sizeof(legacy_boot_script)-1) && memcmp(data,legacy_boot_script,(size_t)n)==0?1:-1;
|
||||
}
|
||||
static bool boot_enabled(void){return boot_hook_kind()>0 && access(BOOT_HOOK,X_OK)==0;}
|
||||
static bool set_boot(bool enabled){
|
||||
int kind=boot_hook_kind();if(kind<0)return false;
|
||||
if(!enabled)return kind==0 || unlink(BOOT_HOOK)==0;
|
||||
if(access(BOOT_SCRIPT,X_OK)!=0)return false;
|
||||
if(kind==2)return true;
|
||||
if(mkdir(BOOT_DIRECTORY,0755)!=0 && errno!=EEXIST)return false;
|
||||
/* Never overwrite another process's temporary file or a foreign hook. */
|
||||
if(symlink(BOOT_SCRIPT,BOOT_HOOK ".tmp")!=0)return false;
|
||||
bool ok=rename(BOOT_HOOK ".tmp",BOOT_HOOK)==0;
|
||||
if(!ok)unlink(BOOT_HOOK ".tmp");
|
||||
return ok;
|
||||
}
|
||||
|
||||
+2
-1
@@ -150,7 +150,7 @@ static bool autostart(void *h,void *m,void *ctx){
|
||||
static bool status(void *h,void *m,void *ctx){
|
||||
(void)ctx;char json[4096],safe[512];size_t n=0;
|
||||
for(size_t i=0;last_error[i] && n+2<sizeof(safe);i++){char c=last_error[i];if(c=='"'||c=='\\')safe[n++]='\\';if((unsigned char)c>=32)safe[n++]=c;}safe[n]=0;
|
||||
int used=snprintf(json,sizeof(json),"{\"returnValue\":true,\"version\":\"0.6.0\",\"running\":%s,\"colorValid\":%s,\"frames\":%lu,\"endpoint\":\"127.0.0.1:19444\",\"priority\":%d,\"uid\":%u,\"drmVerified\":false,\"mappingVerified\":false,\"outputColor\":[%u,%u,%u],\"error\":\"%s\",\"regions\":[",capture?"true":"false",color_valid?"true":"false",frames,PRIORITY,(unsigned)geteuid(),sent_rgb[0],sent_rgb[1],sent_rgb[2],safe);
|
||||
int used=snprintf(json,sizeof(json),"{\"returnValue\":true,\"version\":\"0.6.1\",\"running\":%s,\"colorValid\":%s,\"frames\":%lu,\"endpoint\":\"127.0.0.1:19444\",\"priority\":%d,\"uid\":%u,\"drmVerified\":false,\"mappingVerified\":false,\"outputColor\":[%u,%u,%u],\"error\":\"%s\",\"regions\":[",capture?"true":"false",color_valid?"true":"false",frames,PRIORITY,(unsigned)geteuid(),sent_rgb[0],sent_rgb[1],sent_rgb[2],safe);
|
||||
for(int i=0;i<16;i++)used+=snprintf(json+used,sizeof(json)-used,"%s[%u,%u,%u]",i?",":"",rgb[i][0],rgb[i][1],rgb[i][2]);
|
||||
used+=snprintf(json+used,sizeof(json)-used,"],\"ledCount\":%u,\"spatialOutput\":%s,\"blackPercent\":[",led_count,led_count?"true":"false");
|
||||
for(int i=0;i<16;i++)used+=snprintf(json+used,sizeof(json)-used,"%s%u",i?",":"",black_percent[i]);
|
||||
@@ -218,6 +218,7 @@ static int tick(void *unused){
|
||||
static void *symbol(void *lib,const char *name){void *s=dlsym(lib,name);if(!s){fprintf(stderr,"Missing symbol %s\n",name);exit(2);}return s;}
|
||||
int main(void){
|
||||
signal(SIGTERM,quit_signal);signal(SIGINT,quit_signal);
|
||||
if(boot_enabled() && !set_boot(true))fprintf(stderr,"Own legacy boot hook migration failed\n");
|
||||
void *vt=dlopen("libvtcapture.so.1",RTLD_NOW),*ls=dlopen("libluna-service2.so.3",RTLD_NOW),*glib=dlopen("libglib-2.0.so.0",RTLD_NOW);
|
||||
if(!vt||!ls||!glib){fprintf(stderr,"Missing LG library: %s\n",dlerror());return 2;}
|
||||
vt_init=symbol(vt,"vtCapture_initHistogram");vt_preset=symbol(vt,"vtCapture_setPresetHistogram");vt_get=symbol(vt,"vtCapture_getHistogram");vt_finish=symbol(vt,"vtCapture_finalizeHistogram");
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#define _DEFAULT_SOURCE
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#define TEST_ROOT "/tmp/hyperdrm-autostart-test"
|
||||
#define BOOT_DIRECTORY TEST_ROOT "/init.d"
|
||||
#define BOOT_SCRIPT TEST_ROOT "/boot.sh"
|
||||
#include "autostart.h"
|
||||
static void put_file(const char *path,const char *data){
|
||||
int fd=open(path,O_WRONLY|O_CREAT|O_EXCL,0700);assert(fd>=0);
|
||||
size_t size=strlen(data);assert(write(fd,data,size)==(ssize_t)size);assert(close(fd)==0);
|
||||
}
|
||||
int main(void){
|
||||
/* Fail rather than touching another run's files. */
|
||||
assert(mkdir(TEST_ROOT,0700)==0);put_file(BOOT_SCRIPT,"#!/bin/sh\nexit 0\n");
|
||||
assert(!boot_enabled() && set_boot(false));
|
||||
assert(set_boot(true));assert(boot_hook_kind()==2 && boot_enabled());
|
||||
assert(set_boot(true));assert(set_boot(false) && boot_hook_kind()==0);
|
||||
put_file(BOOT_HOOK,legacy_boot_script);assert(boot_hook_kind()==1);
|
||||
assert(set_boot(true) && boot_hook_kind()==2);assert(set_boot(false));
|
||||
put_file(BOOT_HOOK,"foreign startup\n");assert(!set_boot(true) && !set_boot(false));
|
||||
assert(unlink(BOOT_HOOK)==0);
|
||||
assert(symlink("/foreign/script",BOOT_HOOK)==0);assert(!set_boot(true) && !set_boot(false));
|
||||
assert(unlink(BOOT_HOOK)==0);
|
||||
put_file(BOOT_HOOK ".tmp","foreign temporary\n");assert(!set_boot(true));assert(boot_hook_kind()==0);
|
||||
assert(unlink(BOOT_HOOK ".tmp")==0);
|
||||
assert(set_boot(true));assert(unlink(BOOT_SCRIPT)==0);assert(!boot_enabled());
|
||||
assert(!set_boot(true));assert(set_boot(false));
|
||||
assert(rmdir(BOOT_DIRECTORY)==0 && rmdir(TEST_ROOT)==0);
|
||||
puts("PASS: symlink enable/disable, legacy migration, foreign files preserved, missing target harmless");
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{"id": "org.webosbrew.histogramhyperion", "version": "0.6.0", "vendor": "Local development", "app": "org.webosbrew.histogramhyperion", "services": ["org.webosbrew.histogramhyperion.service"]}
|
||||
{"id": "org.webosbrew.histogramhyperion", "version": "0.6.1", "vendor": "Local development", "app": "org.webosbrew.histogramhyperion", "services": ["org.webosbrew.histogramhyperion.service"], "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM"}
|
||||
@@ -0,0 +1,19 @@
|
||||
title: HyperDRM
|
||||
iconUri: https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/app/icon.png
|
||||
manifestUrl: https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/HyperDRM.manifest.json
|
||||
category: amblight
|
||||
pool: main
|
||||
shortDescription: TV color histograms for local Hyperion ambient lighting
|
||||
requirements:
|
||||
webosRelease: "10.2.2"
|
||||
deviceSoC:
|
||||
- o24
|
||||
description: |
|
||||
HyperDRM sends spatial LED colors from LG color histograms to Hyperion
|
||||
running on the TV. It supports dynamic LED layouts, interpolated colors,
|
||||
top/bottom black-bar detection and optional boot autostart.
|
||||
|
||||
Tested on a rooted LG G4, Rockhopper release 10.2.2-57, device SoC o24.
|
||||
Homebrew Channel service elevation and local Hyperion are required.
|
||||
Other models and releases are not validated. This is color output;
|
||||
no video preview stream is provided.
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
# HyperDRM: container-owned startup script, linked by the app.
|
||||
SERVICE_DIR=/media/developer/apps/usr/palm/services/org.webosbrew.histogramhyperion.service
|
||||
TARGET="$SERVICE_DIR/histogram-service"
|
||||
HOOK=/var/lib/webosbrew/init.d/60-histogramhyperion
|
||||
[ -x "$TARGET" ] && [ -f "$SERVICE_DIR/services.json" ] || exit 0
|
||||
command -v luna-send >/dev/null 2>&1 || exit 0
|
||||
command -v timeout >/dev/null 2>&1 || exit 0
|
||||
(
|
||||
echo 'HyperDRM boot start requested'
|
||||
attempt=0
|
||||
while [ -x "$TARGET" ] && [ -f "$SERVICE_DIR/services.json" ] && [ -L "$HOOK" ] && [ "$(readlink "$HOOK")" = "$SERVICE_DIR/boot.sh" ] && [ "$attempt" -lt 120 ]; do
|
||||
result=$(timeout 12 luna-send -n 1 luna://org.webosbrew.histogramhyperion.service/start '{}' 2>&1)
|
||||
case "$result" in
|
||||
*'"running":true'*) echo 'HyperDRM service started'; exit 0 ;;
|
||||
esac
|
||||
attempt=$((attempt + 1))
|
||||
printf 'Attempt %s failed: %.512s\n' "$attempt" "$result"
|
||||
sleep 5
|
||||
done
|
||||
echo 'HyperDRM boot start cancelled, target removed or retry limit reached'
|
||||
) >/var/lib/webosbrew/histogramhyperion-boot.log 2>&1 </dev/null &
|
||||
exit 0
|
||||
Binary file not shown.
Reference in new issue
Block a user