My Samsung Q60C: native launcher, media and privacy
From a web launcher to native Quiet Home: apps, media rows, remote buttons, privacy and automatic boot root, with source, commands and recovery.
I wanted a fast home screen with the apps and media I actually use. This guide replaces my earlier web-launcher/trampoline write-up. It covers the native solution, the TV changes, the management connection and how to undo each layer.
Source and the complete manual procedure: AnthonMS/samsung-tv-launcher. Use the manual as the command reference and read compatibility first.
What I have now
I replaced Samsung’s home screen with a native launcher built on quiet-tizen. It opens directly from Home and at startup. The old web launcher and trampoline app are no longer needed for everyday use.
A dock contains apps and HDMI inputs. Above it are YouTube recommendations, Jellyfin Continue watching/Next up and live channels. Moonfin handles my media playback. Rows, apps, order, theme and clock are configurable.
The Netflix, TV Plus, Disney+ and Prime Video buttons are custom shortcuts across apps. The channel rocker steps through Moonfin channels with wraparound, and its middle press opens the guide.
Detailed instructions and commands in the repository
Start with the exact TV
My TV is a 2023 Q60C, model TQ65Q60CAUXXC, firmware T-NKLCDEUC-0090-2220.4, Tizen 9 and .NET 6.0.9 on ARMv7. Upstream quiet-tizen described another model, so I checked my own packages, APIs, permissions and schemas first.
This is a recorded installation on one exact TV. Another Samsung running Tizen 9 is not automatically compatible. Read the displayed software version in Settings, Support, About This TV. On mine, /etc/prd_info.ini gave an independent check. A successful root probe alone does not validate everything else.
The repository separates the Q60C guide from retained upstream reference material. Do not run the U8000F profile on a Q60C. Investigate differences in model, firmware, package layout or runtime before continuing.
Detailed instructions and commands in the repository
Prepare the PC and source
I use Samsung SDB from Tizen Studio, Python 3.12, .NET SDK 8, Node.js for tests, Git and OpenSSL. Git for Windows supplies OpenSSL in these examples. Commands below run from the repository root on the PC unless explicitly labelled as a TV script.
Replace YOUR_TV_IP and YOUR_PC_IP with your own LAN addresses. The helper targets only that TV; it does not scan the network. The tv function simply shortens later commands.
Personal configuration, credentials, backups and extracted Samsung files stay in ignored .local folders. Public examples do not contain my tokens, certificates or databases.
git clone https://github.com/AnthonMS/samsung-tv-launcher.git
cd samsung-tv-launcher
$env:SDB = "$env:USERPROFILE\tizen-studio\tools\sdb.exe"
$env:PATH = "C:\Program Files\Git\usr\bin;$env:PATH"
$env:TV_IP = 'YOUR_TV_IP'
$env:PC_IP = 'YOUR_PC_IP'
function tv { py -3.12 tools/device.py --tv $env:TV_IP --pc $env:PC_IP @args }
py -3.12 quiet-tizen/tools/build.py payloadsDetailed instructions and commands in the repository
Developer Mode and the first root check
Open Apps on the TV, enter 1 2 3 4 5, enable Developer Mode and enter the PC’s LAN address as Host PC IP. Then perform a full restart. An ordinary remote off/on can just be standby.
Use the PC address at this stage, not 127.0.0.1. Localhost is a later transition if you choose autonomous boot root.
The probe uses the existing archive-root method and checks UID 0, runtime, cleanup and protected files. It does not assign Home by itself. If it fails, investigate compatibility rather than disabling security services or forcing another model’s profile.
& $env:SDB connect "$($env:TV_IP):26101"
tv probeDetailed instructions and commands in the repository
Record the original state before changing it
I record installed apps, manifests, owners, modes, SMACK labels, services and original Home values. There are three Home selectors: the main-operation app, db/appfw/home_appid and db/appfw/startup_appid.
SQLite snapshots use .backup, not cp on a live database. Original assemblies, resources and any displaced native-image caches are saved on the TV and PC. The targeted inverse is prepared before installation.
The manual contains the complete TV snapshot script and transfer commands. Root/SDB operations run sequentially through tv exec. Wait for cleanup before restarting or entering standby.
# Save the reviewed TV script from docs/MANUAL.md first.
tv exec .local/snapshot.sh
tv pull /home/owner/share/tmp/sdk_tools/native-01-backup.tar.gz .local/backups/native-01.tar.gzDetailed instructions and commands in the repository
Build the native launcher
The launcher is now .NET/NUI rather than a web page. I use the existing Bixby Promotion package slot for my own IL program. This changes a package on writable storage; it does not install a new operating system or firmware.
Build against matching Tizen assemblies obtained from your own permitted SDK/TV installation. Samsung binaries are not distributed in the repository. The transfer helper uses bounded base64 chunks with size/SHA256 verification because sdb pull was unavailable on this model.
Copy catalog/client examples into private local configuration and use app IDs discovered on your own TV. YouTube needs a compatible client configuration you may use. Credentials stay out of Git even when the private installation package needs them.
$refs = 'Tizen.dll','Tizen.NUI.dll','Tizen.System.dll','Tizen.Applications.Common.dll','Tizen.Applications.Service.dll'
foreach ($name in $refs) {
tv pull "/usr/share/dotnet.tizen/framework/$name" "quiet-tizen/.local/tv-framework/$name"
}
py -3.12 quiet-tizen/tools/build.py launcherDetailed instructions and commands in the repository
Trial installation before assigning Home
I install a trial without changing default Home first. Only the affected app is stopped. The assembly keeps the inspected owner, mode and SMACK label, and resources go in quiet-home. The manual supplies the complete script and metadata checks.
On the TV I check rendering, text, arrows, OK, Back, app launches, audio and native settings. Test HDMI with a device actually connected. A status file or successful API return alone is not a visual test.
Only after accepting that trial do I point the main-operation handler, Home and startup at com.samsung.tv.bixby-promotion. Then I test Home from another app, a full restart and standby/wake separately.
# After backup, trial installation and physical verification:
tv exec .local/assign-home.shDetailed instructions and commands in the repository
Dock editing, navigation and appearance
Hold OK on a dock tile, or choose Customize app row in Settings. Tiles jiggle. OK picks one up, Left/Right moves it, Up toggles visibility and Back finishes. Hidden tiles stay dimmed during editing.
HDMI inputs are numbered gradient tiles, not ports permanently tied to Nintendo or PlayStation artwork. A device name can be appended when the TV provides it, and long captions scroll. That is display logic, not a promise every connected device is identifiable.
Top-right circles navigate Home, Apps and Settings. Back follows internal history rather than returning to HDMI. Theme, 12/24-hour time, date and date format live in Settings. Rows form a continuous list; focus scrolls only far enough to reveal the selected row.
Detailed instructions and commands in the repository
YouTube codes and Jellyfin Quick Connect
Pair the YouTube row by selecting YouTube account in Settings, YouTube & media. Open the displayed verification address on your phone, enter the code and approve the account. Choose YouTube or TizenTube separately as the playback app.
For Jellyfin, enter the server address, select Jellyfin account and approve the code in the server’s Profile, Quick Connect. The Moonfin/Jellyfin playback app must also be signed in. Pairing the launcher does not log another app in automatically.
Continue/Next up and live rows can be enabled independently. Switch media playback between Moonfin and Jellyfin. Live channels show their name/current programme without a duration bar. Removing a (Geo-blocked) or resolution suffix from a label does not bypass a restriction.
Test at least two videos with a Home return between them. That exposed a warm-launch bug a single successful first playback missed. A channel that fails in Moonfin’s own guide also needs server/source investigation.
Detailed instructions and commands in the repository
Remote shortcuts across apps
Netflix defaults to Moonfin, TV Plus to Moonfin’s EPG, Disney+ to YouTube and Prime Video to Twitch. The four branded buttons can be assigned to installed apps in Remote & controllers. Channel Up/Down follows Moonfin’s sorted lineup and wraps at either end.
The launcher uses named exclusive Wayland grabs. On this firmware it needed an exact Cynara rule for its own label, user and keygrab privilege. I saved the prior state and inverse before adding it, without giving every app general system permissions.
EPG/channel switching uses a small version-locked Moonfin patch. Cold starts use app-control destinations; warm delivery uses a Tizen message port. Shared request IDs prevent duplicate playback. Unknown Moonfin bundles are rejected, and app updates need fresh inspection.
tv pull /opt/usr/apps/MoonfinApp/res/wgt/main.js .local/moonfin/original-main.js
tv pull /opt/usr/apps/MoonfinApp/res/wgt/index.html .local/moonfin/original-index.html
py -3.12 quiet-tizen/tools/moonfin_guide_bridge.py .local/moonfin/original-main.js .local/moonfin/original-index.html .local/moonfin/patchedDetailed instructions and commands in the repository
What the privacy cleanup disables
I disabled reviewed advertising, analytics, ACR, context and voice components plus optional SmartThings, Health and Gaming Hub helpers. The total is 47 app registrations. Optional features are not automatically malware; I simply do not use them in this setup.
Viewing Information Services, Interest-Based Ads and optional Remote Management were already opted out. I checked the actual consent rows and retained those choices. Voice activation, wakeupless and speech recognition were disabled using their correct types. Account logins and necessary session cookies were preserved.
Nine verified marker files cover ten services. Four other services live on read-only system storage and require runtime masks. I did not change the bootloader, flash firmware, replace global passwd/key files or disable core security.
ACR over HDMI is documented in research, but that does not establish a particular capture rate or actual data sales on my TV. I can check known processes/settings and network boundaries; I cannot certify zero telemetry across closed firmware. Software checks also cannot prove a microphone is electrically disconnected.
# Review one group from YOUR fresh snapshot before applying it.
py -3.12 quiet-tizen/tools/plan_cleanup.py --snapshot .local/privacy/.pkgmgr_parser.db --profile quiet-tizen/profiles/tq65q60cau-2220.4.json --groups ads_analytics --output quiet-tizen/.local/plans/ads
tv exec quiet-tizen/.local/plans/ads/apply.sh
tv exec recipes/mask-runtime.shDetailed instructions and commands in the repository
Make the blocks return after every boot
Runtime masks under /run disappear on a full restart. I installed a separate headless bootstrap in the unused Gaming Hub Service slot. It roots through the TV’s localhost SDB, recreates the four masks and exits. Quiet Home is a different app and does not wait for a root window.
I first tested the chain through a temporary PC relay while normal PC developer access still worked. It produced UID 0 proof and the actual masked/inactive services. Only then did I enable both manifest/registry boot flags and remove the test endpoint.
The package is built privately. Its local signing key and random bridge token stay under .local. The builder does not install anything by itself. Use its archive SHA256 for installation and download originals/the restore script before continuing.
tv pull /opt/usr/apps/com.samsung.tv.ghservice/tizen-manifest.xml .local/boot/original-manifest.xml
py -3.12 tools/prepare_boot.py --manifest .local/boot/original-manifest.xml --test-host $env:PC_IP
tv push .local/boot/boot-package.tar.gz /home/owner/share/tmp/sdk_tools/boot-package.tar.gz
tv exec recipes/install-boot-test.sh boot-01 EXPECTED_ARCHIVE_SHA256
# Follow the headless test, backup transfer and enable steps in docs/PRIVACY.md.Detailed instructions and commands in the repository
The important Developer Mode transition
After a successful trial and completed root cleanup, change Developer Mode Host PC IP to 127.0.0.1 and fully restart. The helper can then root locally at every boot without a running PC. PC management uses a token-protected bridge on port 26103.
The PC and TV LAN addresses have not changed. Developer Mode’s authorized host has changed, so ordinary direct PC SDB access no longer works as before. Use the proxy and keep its token private. Bridge traffic is unencrypted and belongs on the trusted LAN.
I checked a new kernel boot ID, matching root proof, all four masks, 47 flags, eight key grabs and account connections. Then I turned the TV off with the remote, waited 30 seconds and woke it. Quiet Home and protection remained. A short startup interval still precedes the four masks; persistent opt-outs/app disables remain in force throughout.
# Only AFTER the successful trial, enablement, UI address change and restart:
function tv { py -3.12 tools/device.py --tv $env:TV_IP --pc $env:PC_IP --bridge-token-file .local/boot/bridge.token @args }
tv probeDetailed instructions and commands in the repository
The failures are documented too
I kept more than the polished final version. The journal explains why the trampoline was retired, why warm app-control was insufficient, why channel switching moved from server commands to Moonfin callbacks, and why a stale .NET preloader could execute an earlier DLL after replacement.
One important mistake was security-manager-policy-reload --help. It is a script that does not interpret that argument as ordinary help and reloaded base policies. There was no immediate pre-call snapshot, so exact before/after equivalence cannot be claimed. Actual privacy opt-outs were checked afterwards. Do not use that command to query permissions.
The repository indexes every retained operator script and its saved outcome. Raw personalized scripts, error output, databases and signing material are kept locally, not published. The public manual contains the reviewed final procedure with placeholders.
Detailed instructions and commands in the repository
Recovery and future maintenance
If an incompatible firmware update prevents boot root/the bridge, I open Developer Mode on the TV, set Host PC IP back to the actual PC address and restart. Ordinary management is then available for investigation.
Boot persistence, privacy flags, the remote rule, Moonfin patch and Home routing have separate inverses. Restore only the fields/files changed by that phase. Do not replace a live package database with an old full copy or clear account data as the default repair.
I will keep adding one feature at a time, building locally and checking the TV before the next change. That made performance regressions easier to identify. Source, manuals, licenses, tests and journal are in the GitHub repository.
Detailed instructions and commands in the repository
For independent measurements of ACR over HDMI, see Watching TV with the Second-Party.