An iOS app: the page in a web view, with the phone's own player (#418)

web/src/native.ts (#45) has handed playback to a host since September, and
there was no host in this repo: the earlier app, rays/ipodderx-app, grew native
lists beside the page and is left behind. This one is the page and a player:
a WKWebView of ipx-web, AVPlayer behind the bridge with the audio session to
play on locked, now playing and the remote commands (15 back, 30 forward,
scrubbing), and positions and read written from the player's own clock, with
DeadAir's copy named so the server reads the position on its clock.

Built with XcodeGen on a Mac; nothing here compiles the Swift. Its icon is
web/logo.svg at 1024.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RqkrVDqdiQEMWAkNGQ2tYA
This commit is contained in:
2026-11-07 21:50:43 +00:00
parent 6d64cba374
commit a581e3fc88
15 changed files with 784 additions and 1 deletions

View File

@@ -0,0 +1,24 @@
import XCTest
@testable import iPX
final class ServerTests: XCTestCase {
func testABareHostGetsHTTPS() {
XCTAssertEqual(Server.normalise(" ipodderx.sdf1.net ")?.absoluteString, "https://ipodderx.sdf1.net")
}
func testPlainHTTPOnlyOnYourOwnNetwork() {
XCTAssertNotNil(Server.normalise("http://192.168.1.130:8099"))
XCTAssertNotNil(Server.normalise("http://tower.local:8099"))
XCTAssertNotNil(Server.normalise("http://172.20.0.5"))
XCTAssertNil(Server.normalise("http://ipodderx.sdf1.net"), "ATS would refuse it later")
XCTAssertNil(Server.normalise("http://172.32.0.5"))
XCTAssertNil(Server.normalise("ftp://192.168.1.130"))
XCTAssertNil(Server.normalise(""))
}
func testThePagesPathsResolveAgainstTheServer() {
UserDefaults.standard.set("https://ipodderx.sdf1.net", forKey: "ipx.server")
XCTAssertEqual(Server.resolve("/media/42/deadair.m3u8?traceparent=x")?.absoluteString,
"https://ipodderx.sdf1.net/media/42/deadair.m3u8?traceparent=x")
}
}