Files
simvision/KSPlayer-main/Sources/KSPlayer/Metal/MotionSensor.swift
Michael Simard 872354b834 Initial commit: SimVision tvOS streaming app
Features:
- VOD library with movie grouping and version detection
- TV show library with season/episode organization
- TMDB integration for trending shows and recently aired episodes
- Recent releases section with TMDB release date sorting
- Watch history tracking with continue watching
- Playlist caching (12-hour TTL) for offline support
- M3U playlist parsing with XStream API support
- Authentication with credential storage

Technical:
- SwiftUI for tvOS
- Actor-based services for thread safety
- Persistent caching for playlists, TMDB data, and watch history
- KSPlayer integration for video playback

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 22:12:08 -06:00

90 lines
2.7 KiB
Swift

//
// MotionSensor.swift
// KSPlayer-iOS
//
// Created by kintan on 2020/1/13.
//
#if canImport(UIKit) && canImport(CoreMotion)
import CoreMotion
import Foundation
import simd
import UIKit
@MainActor
final class MotionSensor {
static let shared = MotionSensor()
private let manager = CMMotionManager()
private let worldToInertialReferenceFrame = simd_float4x4(euler: -90, y: 0, z: 90)
private var deviceToDisplay = simd_float4x4.identity
private let defaultRadiansY: Float
private var orientation = UIInterfaceOrientation.unknown {
didSet {
if oldValue != orientation {
switch orientation {
case .portraitUpsideDown:
deviceToDisplay = simd_float4x4(euler: 0, y: 0, z: 180)
case .landscapeRight:
deviceToDisplay = simd_float4x4(euler: 0, y: 0, z: -90)
case .landscapeLeft:
deviceToDisplay = simd_float4x4(euler: 0, y: 0, z: 90)
default:
deviceToDisplay = simd_float4x4.identity
}
}
}
}
private init() {
switch KSOptions.windowScene?.interfaceOrientation {
case .landscapeRight:
defaultRadiansY = -.pi / 2
case .landscapeLeft:
defaultRadiansY = .pi / 2
default:
defaultRadiansY = 0
}
}
func ready() -> Bool {
manager.isDeviceMotionAvailable ? manager.isDeviceMotionActive : false
}
func start() {
if manager.isDeviceMotionAvailable, !manager.isDeviceMotionActive {
manager.deviceMotionUpdateInterval = 1 / 60
manager.startDeviceMotionUpdates()
}
}
func stop() {
manager.stopDeviceMotionUpdates()
}
func matrix() -> simd_float4x4? {
if var matrix = manager.deviceMotion.flatMap(simd_float4x4.init(motion:)) {
matrix = matrix.transpose
matrix *= worldToInertialReferenceFrame
orientation = KSOptions.windowScene?.interfaceOrientation ?? .portrait
matrix = deviceToDisplay * matrix
matrix = matrix.rotateY(radians: defaultRadiansY)
return matrix
}
return nil
}
}
public extension simd_float4x4 {
init(motion: CMDeviceMotion) {
self.init(rotation: motion.attitude.rotationMatrix)
}
init(rotation: CMRotationMatrix) {
self.init(SIMD4<Float>(Float(rotation.m11), Float(rotation.m12), Float(rotation.m13), 0.0),
SIMD4<Float>(Float(rotation.m21), Float(rotation.m22), Float(rotation.m23), 0.0),
SIMD4<Float>(Float(rotation.m31), Float(rotation.m32), Float(rotation.m33), -1),
SIMD4<Float>(0, 0, 0, 1))
}
}
#endif