clone

a desktop tv and program guide for over-the-air broadcasts: what's on air, what your tuner gets, live tv, recordings

main
airwaves / main.go
main.go 3.9K
1// Command airwaves is the desktop TV for an Airwaves server: live2// over-the-air TV, the program guide, recordings and reception.3package main45import (6 "log"7 "os"8 "strconv"9 "strings"1011 "github.com/wailsapp/wails/v2"12 "github.com/wailsapp/wails/v2/pkg/options"13 "github.com/wailsapp/wails/v2/pkg/options/assetserver"14 "github.com/wailsapp/wails/v2/pkg/options/linux"15 "github.com/wailsapp/wails/v2/pkg/options/mac"1617 "airwaves/frontend"18)1920const version = "0.1.0"2122func main() {23 app := NewApp()24 setPageZoom(float64(app.scale()) / 100)25 width, height, state := window()26 err := wails.Run(&options.App{27 Title: "Airwaves",28 Width: width,29 Height: height,30 MinWidth: min(1024, width),31 MinHeight: min(640, height),32 // Filling the screen, or 16:9 under gamescope (see window).33 WindowStartState: state,34 BackgroundColour: &options.RGBA{R: 7, G: 8, B: 10, A: 255},35 AssetServer: &assetserver.Options{Assets: frontend.Dist()},36 OnStartup: app.startup,37 OnShutdown: app.shutdown,38 Bind: []any{app},39 Mac: &mac.Options{40 TitleBar: mac.TitleBarHiddenInset(),41 Appearance: mac.NSAppearanceNameDarkAqua,42 About: &mac.AboutInfo{43 Title: "Airwaves " + version,44 Message: "Over-the-air TV, guide and reception explorer.",45 },46 },47 // Without Linux options Wails turns WebKitGTK's GPU use off, and48 // video drawn in software on a TV runs at a few frames a second.49 Linux: &linux.Options{50 WebviewGpuPolicy: linux.WebviewGpuPolicyAlways,51 ProgramName: programName(),52 },53 })54 if err != nil {55 log.Fatal(err)56 }57}5859// window is the size and state the window opens in. On a desktop it fills60// the screen, zoomed (not a fullscreen space). Under gamescope (SteamOS61// Game Mode), which has no window manager and scales the game's window to62// the TV on the GPU, it is a plain 16:9 1920x1080 window: going fullscreen63// there would render the page at the TV's own size, which can be 4K. Shift64// F still goes fullscreen. AIRWAVES_WINDOW=1280x720 opens a window of that65// size instead, for weaker boxes.66func window() (width, height int, state options.WindowStartState) {67 if w, h, ok := parseSize(os.Getenv("AIRWAVES_WINDOW")); ok {68 return w, h, options.Normal69 }70 if gamescope() {71 return 1920, 1080, options.Normal72 }73 return 1360, 840, options.Maximised74}7576// autoScale is the interface size for the screen, in percent: larger under77// gamescope, where the 1080p window fills a TV across the room.78func autoScale() int {79 if gamescope() {80 return 12581 }82 return 10083}8485// platform is the frontend's experience: a console's under gamescope, else86// a desktop's, unless AIRWAVES_PLATFORM names one.87func platform() string {88 switch p := os.Getenv("AIRWAVES_PLATFORM"); p {89 case "desktop", "console", "tv":90 return p91 }92 if gamescope() {93 return "console"94 }95 return "desktop"96}9798// gamescope tells whether the app runs under gamescope: SteamOS Game Mode,99// on a TV.100func gamescope() bool {101 return os.Getenv("GAMESCOPE_WAYLAND_DISPLAY") != "" || os.Getenv("SteamGamepadUI") != "" ||102 os.Getenv("XDG_CURRENT_DESKTOP") == "gamescope"103}104105// programName is the Flatpak's app ID when there is one. WebKit names its106// MPRIS service (the desktop's now playing and media keys) after the107// program name when that is a valid application ID, and Flatpak lets an108// app own MPRIS names under its own ID only.109func programName() string {110 if id := os.Getenv("FLATPAK_ID"); id != "" {111 return id112 }113 return "airwaves"114}115116// parseSize reads "1280x720"; an empty or malformed size is not ok.117func parseSize(s string) (width, height int, ok bool) {118 if s == "" {119 return 0, 0, false120 }121 ws, hs, _ := strings.Cut(strings.ToLower(strings.TrimSpace(s)), "x")122 w, err1 := strconv.Atoi(ws)123 h, err2 := strconv.Atoi(hs)124 if err1 != nil || err2 != nil || w < 320 || h < 240 {125 log.Printf("AIRWAVES_WINDOW=%q: want WIDTHxHEIGHT, like 1280x720", s)126 return 0, 0, false127 }128 return w, h, true129}