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>
This commit is contained in:
89
KSPlayer-main/Sources/KSPlayer/Metal/MotionSensor.swift
Normal file
89
KSPlayer-main/Sources/KSPlayer/Metal/MotionSensor.swift
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// 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
|
||||
Reference in New Issue
Block a user