v3.0.0 - #3
Merged
Merged
Conversation
- check_version: the changelog branch was nested inside the version branch and never ran; versions were compared as strings so 2.9.x would never see a 2.10.x update; an empty response returned a bare None instead of a 3-tuple. Add version_tuple() and compare numerically. - checkGZIP: gzip-encoded responses crashed on Python 3 because StringIO was fed bytes; use BytesIO. - b64decoder: the padding fixup appended bytes to a str (TypeError on Python 3). - fetch_url: PY3 was undefined when running on Python 2.
The Lcn, LcnXX and Checkskin prompts used 'if answer is None / else', so answering No fell into the else branch and ran the scan or check anyway. Guard with 'elif answer:'. LcnXX also reopened its prompt with self.Lcn as callback, so the answer ran the wrong handler. Checkskin additionally connected its eTimer to the return value of check_module_skin() - the function was already executed and returns None, so the timer fired into a TypeError; run the check directly and drop the timer.
- A missing comma in the generic pattern list concatenated two regexes into one broken pattern that could never match. - A dead server made make_request return None and '"x" in None' raise a confusing TypeError; fail cleanly with a clear message instead. - The pattern loop kept scanning after a successful match, so a page matching several patterns appended duplicate server entries to the config; stop after the first hit.
- removenow: package filenames without an underscore lost their last character (ipk[:-1]), so opkg remove targeted a nonexistent package; strip the extension instead. - The grid page count used npics // 20 + 1, creating a phantom empty page whenever an item count is an exact multiple of 20 (all six grid screens share the formula). - requests.get in runScriptWithConsole and retfile had no timeout and could freeze the GUI thread forever on a stalled connection.
check_vers compared version strings lexicographically, so an installed 2.10.x would be offered a downgrade to 2.9.x and 2.9.x would never see a 2.10.x update. Use the shared version_tuple helper.
'Label: %s' % x if x else 'Unknown' binds as ('Label: %s' % x) if x
else 'Unknown', so any missing value printed a bare 'Unknown' line
without its field label. Format through a small helper instead, and
show the real boolean for the VTi/DMM image flags (False previously
displayed as 'Unknown').
- TransferBouquetTerrestrialFinal defined its inner RestoreTerrestrial function but never called it, so the terrestrial bouquet restore after a settings install was a no-op. - addInTVBouquets compared the bouquet's full path against bouquets.tv lines that only contain the file name, so the already-present check never matched and a duplicate reference (to a possibly different hardcoded name) was appended on every run; compare and write the actual bouquet file name. - RestoreTerrestrial checked for '#NAME' inside line.lower(), which can never match, so the bouquet was never renamed to Digitale Terrestre. - Terrestrial.py's ServiceScan hook imported itself through .LCNScanner.Terrestrial, a path that does not exist from inside the LCNScanner package; the class is defined in the same module.
translate_utils.py is imported by nothing and cannot be imported at all: it expects DEBUG, HEADERS and SYSTEM_DIR from the package, which do not exist (leftover from the ForecaOne plugin). The translation workflow uses its own copies in update_translations.py. bissfeedautokey.sh and ipaudiopro_1.4.sh are byte-identical duplicates of Bissfeedautokey.sh and Ipaudiopro_1.4.sh; the capitalized names are the ones referenced by plugin.py. Multistalker_pro.sh and multisalker_pro1_eliesat.sh differ in content and stay untouched.
Opening the Information screen imported stbinfo on the GUI thread; its module-level StbInfo() runs pings, TCP probes and up to four public-IP lookups, blocking the whole interface for 20+ seconds on first open (worse when offline, since every lookup runs into its timeout). - LSinfo now shows 'Collecting system information...' immediately, gathers the data in a daemon thread (including the heavy first import) and applies the text from an eTimer on the main thread. The poll stops on screen close so a late result cannot touch a dead widget. - stbinfo tracks connectivity as a boolean and skips the public-IP lookups entirely when the box is offline - previously the offline case was the slowest. Lookup timeouts trimmed to 3s.
okRun1 wiped lamedb and every .tv/.radio file from /etc/enigma2 before checking that the download or unzip had succeeded: urlretrieve had no error handling, the unzip exit code was ignored, and a zip with an unexpected layout made the cp copy nothing - any of these left the box with no channel list at all. The install now runs download -> verify -> backup -> wipe -> install: - download via requests with a timeout and clear failure message, aborting before /etc/enigma2 is touched; - unzip exit code checked; the payload must actually contain a lamedb or .tv file (channel lists at the zip root are now handled too, and the top-level folder is detected instead of walking into the deepest subdirectory); - the current /etc/enigma2 is saved to /tmp/settings_backup.tar.gz before the wipe and restored automatically if the copy fails.
Six screens (LinuxsatPanel, LSskin, LSChannel, LulullaScript, CiefpInstaller, ScriptInstaller) each carried a byte-identical copy of the 20-tile grid machinery: title/skin/resolution setup, widget and ActionMap wiring, paging (openTest/paintFrame), navigation (key_left/right/up/down), sorting and the view-log prompt. Every fix in this area had to be applied six times. The engine now lives once in an LPGridScreen base class: subclasses fill their menu lists and call initGrid(). Behavior is unchanged, verified by driving every screen through full navigation wrap-around, paging and sort/restore in a stubbed enigma2 environment. Also folded in while moving the code: - _view_log kept its eTimer in a local variable, so the timer could be garbage collected before firing and the log viewer silently never opened; the timer is now held on the screen instance. - Dropped keyNumberGlobal, dead code referencing a "menu" widget that none of these screens define, with no key binding pointing at it. plugin.py shrinks by ~1150 lines net.
Every remaining network operation ran on the enigma main thread and froze the whole GUI: the addon catalog was fetched at panel open AND again on every category click, provider pages were scraped synchronously when a channel-list screen opened, package downloads blocked until complete, and the settings install (download + unzip + copy) locked the interface for its entire duration. - New AsyncCall helper runs a blocking function in a daemon thread and delivers the result to a callback on the main thread via eTimer. The AsyncMixin (used by LPGridScreen and addInstall) cancels pending callbacks when the screen closes, so a late result never touches a dead widget. - The catalog is fetched once per session (5-minute TTL) and warmed in the background when the panel opens, so a category click is served from cache instantly; the shared _openCategory lives in LPGridScreen. - Provider page scraping, package downloads and the settings install now show a status text and run in the background; the console or result message appears when the work is done. Verified in the stubbed enigma2 environment end-to-end: cache hit counting, panel prefetch, category click -> addInstall slice, provider page failure path, async package install -> opkg console command, and a full settings install with a real zip archive through the real shell (unzip, payload check, backup, wipe, install), plus grid navigation regression on the refactored screens.
- Search (GREEN button, shown in the skins next to Exit): on the main panel it searches the entire addon catalog across every category and opens the matches as a normal installable list; on the category grids it jumps straight to the first matching tile, changing page if needed. Runs through the async helper, so a cold catalog never blocks the GUI. - Installed addons are shown in green in the addon lists. The installed-package scan that message() already did on click is now a shared helper (get_installed_packages) and feeds one flag per list entry. - The startup update check, present but disconnected since its onLayoutFinish line was commented out, is enabled again: it runs in the background at panel open and shows a single clear message (version, changelog, how to update) instead of the old modal-detection logic. Uses the fixed numeric version comparison. - AsyncCall hardened against double delivery of a result. Verified in the stubbed environment: update prompt on a newer remote version, global search returning only matching catalog entries plus the no-match path, grid search jumping to the correct tile and page, installed-flag computation against the package database, and list entry rendering with the installed color. All three LinuxsatPanel.xml skins extended with the key_green label and re-validated as XML.
Lint (ruff, pylint, autopep8) and the translation updater only triggered on main, so develop work got no checks until release. The two auto-commit workflows also hardcoded 'origin main' in their pull/push steps; they now use the triggering branch, and the autopep8 commit step is limited to push events so pull requests are lint-only. Autotag stays main-only since tags mark releases.
Version bump across __init__.py, CONTROL/control, installer.sh and the README badge. The installer.sh changelog (what the in-plugin update check displays) summarizes the 3.0.0 line: - Search all addons with the GREEN button - Installed addons shown in green in the lists - No more GUI freezes: all network work is asynchronous and the addon catalog is cached per session - Settings install verifies the download and keeps an automatic backup - Update check runs at panel start - Grid engine unified in one base class, dead code removed and a long list of bug fixes (see the individual commits)
key_up's conditions almost never matched a real cursor state: pressing UP anywhere but a page's first tile fell into a branch that jumped to the last page, and because openTest() resets the index to the page start, on page 2 the cursor just snapped to the first tile instead of moving up a row. key_left's wrap had the same openTest problem, landing on the first tile of the previous page instead of the last one. All four direction keys are rewritten with plain row/column logic: LEFT/RIGHT step one tile and wrap page-to-page at the edges; UP/DOWN move one row and cross pages keeping the current column (clamped on a partial last row). Verified exhaustively in the stubbed environment: every key from every position on grids of 6, 16, 20, 25, 37, 40 and 45 items keeps the cursor inside the visible page, full LEFT/RIGHT cycles visit every tile exactly once and wrap home, UP/DOWN are inverse operations within a page, and the reported case (UP on page 2) moves one row up.
The last page pre-filled all 20 slots with the LSS.png placeholder and then overwrote only the occupied ones, so a page with e.g. 14 entries showed 6 leftover placeholder icons. openTest now draws the occupied tiles and hides the unused pixmaps (re-showing them when a full page is displayed again); the min/max entry computation for full and last pages is unified in the process. Verified for 6/16/20/25/34/37/45-item grids: the last page shows exactly its own tiles, returning to a full page restores all 20, and the navigation invariants still hold from every position.
The import inside check_and_install_requests exists only to test whether the module is installed before falling back to opkg/apt-get, so the unused-import warning is intentional. importlib.util.find_spec is not an option while the Python 2 code paths remain.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LinuxsatPanel v3.0.0
✨ New Features
catalog across every category and shows the matches as a normal installable list.
On category/script grids, GREEN jumps straight to the first matching tile,
switching page automatically. New "Search" label + green button bar in all
three skins (HD / FHD / WQHD).
in green, computed from the opkg/dpkg database when the list opens.
version, changelog and update instructions. (The check existed but had been
disconnected; it is now enabled, asynchronous, and uses a correct numeric
version comparison.)
⚡ Performance — no more GUI freezes
AsyncCall/AsyncMixinhelper (background thread + eTimer delivery, auto-cancelled on screen close):
at panel open — category clicks are instant.
Information screen; public-IP lookups are skipped entirely when offline.
🛡️ Data safety
download → verify (unzip exit code + archive must actually contain a
lamedb/.tvpayload; both zip layouts supported) → automatic backup of/etc/enigma2→ wipe → install → automatic restore if the copy fails.Every failure path shows a clear message and leaves the box untouched.
🐛 Bug fixes
positions, and on page 2 it snapped to the first tile); LEFT wrapped to the
wrong tile. All four arrows rewritten: UP/DOWN move one row and keep the
column across pages, LEFT/RIGHT wrap cleanly page-to-page.
placeholder icons; unused tiles are now hidden.
LcnXXalso reopened with the wrong callback.None) ofthe already-executed check → guaranteed TypeError.
2.10.x; 2.10.x was offered a "downgrade"); the changelog was never parsed;
an empty response crashed callers. All fixed (
version_tuple).broken pattern; a dead server raised instead of showing a message; duplicate
server entries could be appended (missing
break)._lost their last character, soopkg removetargeted a nonexistent package.phantom empty page.
a no-op (function defined but never called);
bouquets.tvdedup compared afull path against name-only lines, appending a duplicate reference on every
run;
#NAMErename could never match; self-import in the ServiceScan hook.StringIOfed bytes),b64decoderpadding (bytes + str), undefinedPY3infetch_urlon py2.field label (operator-precedence bug).
and could be garbage-collected before firing — log viewer silently never
opened. Timer now held on the screen instance.
the GUI forever.
🧹 Code quality & cleanup
20-tile grid machinery (~1,500 duplicated lines). It now lives once in
LPGridScreen;plugin.pyshrinks from ~5,100 to ~3,900 lines. Every futurefix in this area lands once instead of six times.
translate_utils.py(imported by nothing and unimportable) andtwo byte-identical duplicate
sh/scripts.keyNumberGlobal(referenced a widget that doesn't exist).__pycache__/*.pycadded to.gitignore.🔧 CI / Housekeeping
developtoo; the auto-commit workflows push back to the triggering branchinstead of hardcoded
main. Autotag remains main-only (tags = releases).__init__.py,CONTROL/control,installer.sh(update-check changelog included) and the README badge.Merging this PR will trigger the automatic tag + release.