diff --git a/Makefile b/Makefile index 4a78219..ac7eda5 100644 --- a/Makefile +++ b/Makefile @@ -47,11 +47,11 @@ release: install: release mkdir -p "$(APPDIR)" "$(PREFIX)/bin" rm -f "$(PREFIX)/lib/terebi/terebi" - rm -rf "$(PREFIX)/lib/terebi/terebi.app" "$(APPDIR)/terebi.app" - cp -R ".build/release/terebi.app" "$(APPDIR)/terebi.app" - ln -sfn "$$(cd "$(APPDIR)" && pwd)/terebi.app/Contents/MacOS/terebi-cli" "$(PREFIX)/bin/terebi" - /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f "$(APPDIR)/terebi.app" - mdimport "$(APPDIR)/terebi.app" + rm -rf "$(PREFIX)/lib/terebi/terebi.app" "$(APPDIR)/terebi.app" "$(APPDIR)/Terebi.app" + cp -R ".build/release/terebi.app" "$(APPDIR)/Terebi.app" + ln -sfn "$$(cd "$(APPDIR)" && pwd)/Terebi.app/Contents/MacOS/terebi-cli" "$(PREFIX)/bin/terebi" + /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f "$(APPDIR)/Terebi.app" + mdimport "$(APPDIR)/Terebi.app" $(BUILD_DIR): mkdir -p "$@" diff --git a/README.md b/README.md index 67072bf..efc9775 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ export PATH="$HOME/.local/bin:$PATH" terebi --help ``` -Installation builds a release, places `terebi.app` in `~/Applications`, registers it with Launch Services, and requests Spotlight indexing. The CLI symlink is `~/.local/bin/terebi`; any old app under `~/.local/lib/terebi` is removed. Quit running players before updating. +Installation builds a release, places `Terebi.app` in `~/Applications`, registers it with Launch Services, and requests Spotlight indexing. The application display name is **Terebi**; the CLI remains `~/.local/bin/terebi`. Any old app under `~/.local/lib/terebi` or lowercase installed bundle is removed. Quit running players before updating. Use `make install APPDIR="/Applications"` to change the app directory (it must be writable), `PREFIX="/custom/path"` to change the CLI prefix (`bin/terebi`), or both. Use `make release` for just `.build/release/terebi.app`. diff --git a/Resources/Info.plist b/Resources/Info.plist index 4962356..d7406a6 100644 --- a/Resources/Info.plist +++ b/Resources/Info.plist @@ -4,7 +4,8 @@ CFBundleExecutableterebi CFBundleIdentifierlocal.personal.terebi - CFBundleNameterebi + CFBundleNameTerebi + CFBundleDisplayNameTerebi CFBundlePackageTypeAPPL CFBundleShortVersionString0.1 LSMinimumSystemVersion15.0 diff --git a/Sources/App/Bootstrap.swift b/Sources/App/Bootstrap.swift index 1f1a358..a2d7b7b 100644 --- a/Sources/App/Bootstrap.swift +++ b/Sources/App/Bootstrap.swift @@ -12,10 +12,10 @@ enum TerebiBootstrap { let payload = app.appendingPathComponent("Contents/Frameworks/libterebi-player.dylib") guard let library = dlopen(payload.path, RTLD_NOW | RTLD_LOCAL) else { let detail = dlerror().map { String(cString: $0) } ?? "The dynamic loader could not load the player." - fail("Could not load the player: \(detail)\n\nPlayer library: \(payload.path)\nRebuild and reinstall terebi.") + fail("Could not load the player: \(detail)\n\nPlayer library: \(payload.path)\nRebuild and reinstall Terebi.") } guard let entry = dlsym(library, "terebi_app_main") else { - fail("The player library is missing its application entry point. Rebuild and reinstall terebi.") + fail("The player library is missing its application entry point. Rebuild and reinstall Terebi.") } // Keep the declared app executable alive so LaunchServices retains its identity. typealias PlayerMain = @convention(c) () -> Void @@ -29,7 +29,7 @@ enum TerebiBootstrap { application.activate(ignoringOtherApps: true) let alert = NSAlert() alert.alertStyle = .critical - alert.messageText = "terebi could not start" + alert.messageText = "Terebi could not start" alert.informativeText = message alert.addButton(withTitle: "Quit") alert.runModal() diff --git a/Sources/App/TerebiApp.swift b/Sources/App/TerebiApp.swift index 2820c9e..1628e49 100644 --- a/Sources/App/TerebiApp.swift +++ b/Sources/App/TerebiApp.swift @@ -220,7 +220,7 @@ final class PlayerModel: ObservableObject { guard canCast, let source = currentMedia, let handle else { return } cancelYouTubeResolution() commandError = nil - casting.start(to: device, source: source, title: fileName ?? "terebi", subtitle: selectedSubtitle, + casting.start(to: device, source: source, title: fileName ?? "Terebi", subtitle: selectedSubtitle, handle: handle, snapshot: state, playing: playing ?? effectivePlaying, volume: volume, audibleVolume: lastAudibleVolume) revealControls() @@ -555,7 +555,7 @@ final class PlayerModel: ObservableObject { isSeeking = false seekPosition = 0 window?.representedURL = source.url - window?.title = fileName ?? "terebi" + window?.title = fileName ?? "Terebi" revealControls() systemPlayback?.update() } @@ -711,7 +711,7 @@ final class PlayerModel: ObservableObject { commandError = nil isSeeking = false window?.representedURL = nil - window?.title = "terebi" + window?.title = "Terebi" revealControls() systemPlayback?.update() } @@ -762,7 +762,7 @@ final class PlayerModel: ObservableObject { func attachWindow(_ window: NSWindow) { guard self.window !== window else { return } self.window = window - window.title = fileName ?? "terebi" + window.title = fileName ?? "Terebi" window.contentMinSize = NSSize(width: 400, height: 240) compactWindow.normalVideoLayout = { [weak self] in guard let self, self.showsQueue, self.state.has_video else { return nil } @@ -1978,7 +1978,7 @@ private struct PlayerContent: View { private func compactTitleLabel(progress: String?, constrained: Bool) -> some View { HStack(spacing: 0) { - Text(model.fileName ?? "terebi") + Text(model.fileName ?? "Terebi") .lineLimit(1) .truncationMode(.tail) .frame(minWidth: 0, maxWidth: constrained ? .infinity : nil, alignment: .leading) @@ -2069,11 +2069,11 @@ private struct PlayerContent: View { } else { Image(systemName: "play.rectangle.fill").font(.system(size: 14)) } - Text(model.fileName ?? "terebi") + Text(model.fileName ?? "Terebi") .font(.system(size: 13, weight: .semibold)) .lineLimit(1) .truncationMode(.tail) - .help(model.fileName ?? "terebi") + .help(model.fileName ?? "Terebi") } .padding(.horizontal, 8) .frame(height: 24) @@ -2491,7 +2491,7 @@ private struct PlayerContent: View { .foregroundStyle(Color(SunsetPalette.accent)) .accessibilityHidden(true) VStack(alignment: .leading, spacing: 4) { - Text("terebi").font(.system(size: 20, weight: .semibold)) + Text("Terebi").font(.system(size: 20, weight: .semibold)) .foregroundStyle(Color(SunsetPalette.text)) Text("Open media to get started") .font(.callout) @@ -2603,7 +2603,7 @@ private struct PlayerContent: View { } .font(.system(size: 11, weight: .medium)) .accessibilityElement(children: .combine) - .help((model.fileName ?? "terebi") + (progress.map { " · \($0)" } ?? "")) + .help((model.fileName ?? "Terebi") + (progress.map { " · \($0)" } ?? "")) .padding(.horizontal, 8) .frame(height: 28) .background(PlayerGlass(cornerRadius: 10).clipShape(RoundedRectangle(cornerRadius: 10)).allowsHitTesting(false)) @@ -2848,7 +2848,7 @@ struct TerebiApp: App { @StateObject private var model = PlayerModel.shared var body: some Scene { - Window("\(model.fileName ?? "terebi")", id: "terebi") { + Window("\(model.fileName ?? "Terebi")", id: "terebi") { PlayerContent(model: model) .focusedSceneObject(model) } @@ -2874,7 +2874,7 @@ public func terebiAppMain() { NSApp.activate(ignoringOtherApps: true) let alert = NSAlert() alert.alertStyle = .critical - alert.messageText = "Could not load terebi configuration" + alert.messageText = "Could not load Terebi configuration" alert.informativeText = error.localizedDescription alert.runModal() exit(78)