This commit is contained in:
Aiden Vigue 2021-06-21 02:41:45 -04:00
parent a7ed08e2b5
commit b27e8c6a74
No known key found for this signature in database
GPG Key ID: B9A09843AB079D5B
7 changed files with 77 additions and 70 deletions

View File

@ -47,48 +47,48 @@ class DeviceProfileBuilder {
// Build direct play profiles
var directPlayProfiles: [DirectPlayProfile] = []
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "aac,mp3,wav", videoCodec: "h264", type: .video)]
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "aac,mp3,wav", videoCodec: "h264,mpeg4", type: .video)]
// Device supports Dolby Digital (AC3, EAC3)
if supportsFeature(minimumSupported: .A8X) {
if supportsFeature(minimumSupported: .A9) {
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "aac,mp3,wav,ac3,eac3,flac,opus", videoCodec: "hevc,h264,hev1", type: .video)] // HEVC/H.264 with Dolby Digital
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "aac,mp3,wav,ac3,eac3,flac,opus", videoCodec: "hevc,h264,hev1,mpeg4", type: .video)] // HEVC/H.264 with Dolby Digital
} else {
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "ac3,eac3,aac,mp3,wav,opus", videoCodec: "h264", type: .video)] // H.264 with Dolby Digital
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "ac3,eac3,aac,mp3,wav,opus", videoCodec: "h264,mpeg4", type: .video)] // H.264 with Dolby Digital
}
}
// Device supports Dolby Vision?
if supportsFeature(minimumSupported: .A10X) {
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "aac,mp3,wav,ac3,eac3,flac,opus", videoCodec: "dvhe,dvh1,h264,hevc,hev1", type: .video)] // H.264/HEVC with Dolby Digital - No Atmos - Vision
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "aac,mp3,wav,ac3,eac3,flac,opus", videoCodec: "dvhe,dvh1,h264,hevc,hev1,mpeg4", type: .video)] // H.264/HEVC with Dolby Digital - No Atmos - Vision
}
// Device supports Dolby Atmos?
if supportsFeature(minimumSupported: .A12) {
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "aac,mp3,wav,ac3,eac3,flac,truehd,dts,dca,opus", videoCodec: "h264,hevc,dvhe,dvh1,h264,hevc,hev1", type: .video)] // H.264/HEVC with Dolby Digital & Atmos - Vision
directPlayProfiles = [DirectPlayProfile(container: "mov,mp4,mkv", audioCodec: "aac,mp3,wav,ac3,eac3,flac,truehd,dts,dca,opus", videoCodec: "h264,hevc,dvhe,dvh1,h264,hevc,hev1,mpeg4", type: .video)] // H.264/HEVC with Dolby Digital & Atmos - Vision
}
// Build transcoding profiles
var transcodingProfiles: [TranscodingProfile] = []
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "h264", audioCodec: "aac,mp3,wav")]
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "h264,mpeg4", audioCodec: "aac,mp3,wav")]
// Device supports Dolby Digital (AC3, EAC3)
if supportsFeature(minimumSupported: .A8X) {
if supportsFeature(minimumSupported: .A9) {
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "h264,hevc,hev1", audioCodec: "aac,mp3,wav,eac3,ac3,flac,opus", _protocol: "hls", context: .streaming, maxAudioChannels: "6", minSegments: 2, breakOnNonKeyFrames: true)]
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "h264,hevc,hev1,mpeg4", audioCodec: "aac,mp3,wav,eac3,ac3,flac,opus", _protocol: "hls", context: .streaming, maxAudioChannels: "6", minSegments: 2, breakOnNonKeyFrames: true)]
} else {
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "h264", audioCodec: "aac,mp3,wav,eac3,ac3,opus", _protocol: "hls", context: .streaming, maxAudioChannels: "6", minSegments: 2, breakOnNonKeyFrames: true)]
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "h264,mpeg4", audioCodec: "aac,mp3,wav,eac3,ac3,opus", _protocol: "hls", context: .streaming, maxAudioChannels: "6", minSegments: 2, breakOnNonKeyFrames: true)]
}
}
// Device supports Dolby Vision?
if supportsFeature(minimumSupported: .A10X) {
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "dvhe,dvh1,hevc,h264,hev1", audioCodec: "aac,mp3,wav,ac3,eac3,flac,opus", _protocol: "hls", context: .streaming, maxAudioChannels: "6", minSegments: 2, breakOnNonKeyFrames: true)]
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "dvhe,dvh1,hevc,h264,hev1,mpeg4", audioCodec: "aac,mp3,wav,ac3,eac3,flac,opus", _protocol: "hls", context: .streaming, maxAudioChannels: "6", minSegments: 2, breakOnNonKeyFrames: true)]
}
// Device supports Dolby Atmos?
if supportsFeature(minimumSupported: .A12) {
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "dvhe,dvh1,hevc,h264,hev1", audioCodec: "aac,mp3,wav,ac3,eac3,flac,dts,truehd,dca,opus", _protocol: "hls", context: .streaming, maxAudioChannels: "6", minSegments: 2, breakOnNonKeyFrames: true)]
transcodingProfiles = [TranscodingProfile(container: "ts", type: .video, videoCodec: "dvhe,dvh1,hevc,h264,hev1,mpeg4", audioCodec: "aac,mp3,wav,ac3,eac3,flac,dts,truehd,dca,opus", _protocol: "hls", context: .streaming, maxAudioChannels: "6", minSegments: 2, breakOnNonKeyFrames: true)]
}
var codecProfiles: [CodecProfile] = []
@ -96,12 +96,12 @@ class DeviceProfileBuilder {
let h264CodecConditions: [ProfileCondition] = [
ProfileCondition(condition: .notEquals, property: .isAnamorphic, value: "true", isRequired: false),
ProfileCondition(condition: .equalsAny, property: .videoProfile, value: "high|main|baseline|constrained baseline", isRequired: false),
ProfileCondition(condition: .lessThanEqual, property: .videoLevel, value: "60", isRequired: false),
ProfileCondition(condition: .lessThanEqual, property: .videoLevel, value: "80", isRequired: false),
ProfileCondition(condition: .notEquals, property: .isInterlaced, value: "true", isRequired: false)]
let hevcCodecConditions: [ProfileCondition] = [
ProfileCondition(condition: .notEquals, property: .isAnamorphic, value: "true", isRequired: false),
ProfileCondition(condition: .equalsAny, property: .videoProfile, value: "main|main 10", isRequired: false),
ProfileCondition(condition: .lessThanEqual, property: .videoLevel, value: "160", isRequired: false),
ProfileCondition(condition: .equalsAny, property: .videoProfile, value: "high|main|main 10", isRequired: false),
ProfileCondition(condition: .lessThanEqual, property: .videoLevel, value: "175", isRequired: false),
ProfileCondition(condition: .notEquals, property: .isInterlaced, value: "true", isRequired: false)]
codecProfiles.append(CodecProfile(type: .video, applyConditions: h264CodecConditions, codec: "h264"))
@ -116,12 +116,8 @@ class DeviceProfileBuilder {
subtitleProfiles.append(SubtitleProfile(format: "ssa", method: .embed))
subtitleProfiles.append(SubtitleProfile(format: "subrip", method: .embed))
subtitleProfiles.append(SubtitleProfile(format: "sub", method: .embed))
subtitleProfiles.append(SubtitleProfile(format: "pgssub", method: .embed))
subtitleProfiles.append(SubtitleProfile(format: "pgs", method: .embed))
subtitleProfiles.append(SubtitleProfile(format: "subrip", method: .external))
subtitleProfiles.append(SubtitleProfile(format: "sub", method: .external))
subtitleProfiles.append(SubtitleProfile(format: "pgssub", method: .external))
subtitleProfiles.append(SubtitleProfile(format: "pgs", method: .external))
subtitleProfiles.append(SubtitleProfile(format: "ass", method: .external))
subtitleProfiles.append(SubtitleProfile(format: "ssa", method: .external))
subtitleProfiles.append(SubtitleProfile(format: "vtt", method: .external))

View File

@ -34,7 +34,7 @@ struct ItemView: View {
.statusBar(hidden: true)
.edgesIgnoringSafeArea(.all)
.prefersHomeIndicatorAutoHidden(true)
}.supportedOrientations(.landscape), isActive: $videoPlayerItem.shouldShowPlayer) {
}, isActive: $videoPlayerItem.shouldShowPlayer) {
EmptyView()
}
VStack {

View File

@ -12,7 +12,6 @@ import SwiftUI
struct LibrarySearchView: View {
@StateObject var viewModel: LibrarySearchViewModel
@State var searchQuery = ""
// MARK: tracks for grid
@State private var tracks: [GridItem] = Array(repeating: .init(.flexible()), count: Int(UIScreen.main.bounds.size.width) / 125)
@ -25,42 +24,43 @@ struct LibrarySearchView: View {
Spacer().frame(height: 6)
SearchBar(text: $searchQuery)
ZStack {
ScrollView(.vertical) {
if !viewModel.items.isEmpty {
Spacer().frame(height: 16)
LazyVGrid(columns: tracks) {
ForEach(viewModel.items, id: \.id) { item in
NavigationLink(destination: ItemView(item: item)) {
VStack(alignment: .leading) {
ImageView(src: item.getPrimaryImage(maxWidth: 100), bh: item.getPrimaryImageBlurHash())
.frame(width: 100, height: 150)
.cornerRadius(10)
Text(item.name ?? "")
.font(.caption)
.fontWeight(.semibold)
.foregroundColor(.primary)
.lineLimit(1)
if item.productionYear != nil {
Text(String(item.productionYear!))
.foregroundColor(.secondary)
.font(.caption)
.fontWeight(.medium)
} else {
Text(item.type ?? "")
}
}.frame(width: 100)
}
}
if(!viewModel.isLoading) {
ScrollView(.vertical) {
if !viewModel.items.isEmpty {
Spacer().frame(height: 16)
LazyVGrid(columns: tracks) {
ForEach(viewModel.items, id: \.id) { item in
NavigationLink(destination: ItemView(item: item)) {
VStack(alignment: .leading) {
ImageView(src: item.getPrimaryImage(maxWidth: 100), bh: item.getPrimaryImageBlurHash())
.frame(width: 100, height: 150)
.cornerRadius(10)
Text(item.name ?? "")
.font(.caption)
.fontWeight(.semibold)
.foregroundColor(.primary)
.lineLimit(1)
if item.productionYear != nil {
Text(String(item.productionYear!))
.foregroundColor(.secondary)
.font(.caption)
.fontWeight(.medium)
} else {
Text(item.type ?? "")
}
}.frame(width: 100)
}
}
Spacer().frame(height: 16)
}
.onRotate { _ in
recalcTracks()
}
} else {
Text("Query returned 0 results.")
}
.onRotate { _ in
recalcTracks()
}
} else if !viewModel.isLoading {
Text("No results :(")
}
}
if viewModel.isLoading {
} else {
ProgressView()
}
}

View File

@ -53,6 +53,9 @@ struct LibraryView: View {
.fontWeight(.medium)
} else {
Text(item.type ?? "")
.foregroundColor(.secondary)
.font(.caption)
.fontWeight(.medium)
}
}.frame(width: 100)
}
@ -69,7 +72,7 @@ struct LibraryView: View {
} label: {
Image(systemName: "chevron.left")
.font(.system(size: 25))
}.disabled(viewModel.hasPreviousPage)
}.disabled(!viewModel.hasPreviousPage)
Text("Page \(String(viewModel.currentPage + 1)) of \(String(viewModel.totalPages))")
.font(.headline)
.fontWeight(.semibold)
@ -78,7 +81,7 @@ struct LibraryView: View {
} label: {
Image(systemName: "chevron.right")
.font(.system(size: 25))
}.disabled(viewModel.hasNextPage)
}.disabled(!viewModel.hasNextPage)
}
Spacer()
}

View File

@ -22,7 +22,7 @@ struct SettingsView: View {
func onAppear() {
let defaults = UserDefaults.standard
username = SessionManager.current.user.username!
username = SessionManager.current.user.username ?? ""
inNetworkStreamBitrate = defaults.integer(forKey: "InNetworkBandwidth")
outOfNetworkStreamBitrate = defaults.integer(forKey: "OutOfNetworkBandwidth")
autoSelectSubtitles = defaults.bool(forKey: "AutoSelectSubtitles")

View File

@ -523,7 +523,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
} else {
deliveryUrl = nil
}
let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt")
let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec!)
if subtitle.delivery != .encode {
subtitleTrackArray.append(subtitle)
@ -548,6 +548,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
self.sendPlayReport()
playbackItem = item
}
dump(playbackItem)
startLocalPlaybackEngine(true)
})
.store(in: &cancellables)
@ -583,29 +584,22 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
}
if(fetchCaptions) {
print("Fetching captions.")
// Pause and load captions into memory.
mediaPlayer.pause()
var shouldHaveSubtitleTracks = 1
subtitleTrackArray.forEach { sub in
if sub.id != -1 && sub.delivery == .external && sub.codec != "subrip" {
shouldHaveSubtitleTracks = shouldHaveSubtitleTracks + 1
if sub.id != -1 && sub.delivery == .external {
mediaPlayer.addPlaybackSlave(sub.url!, type: .subtitle, enforce: false)
}
}
// Wait for captions to load
delegate?.showLoadingView(self)
while mediaPlayer.numberOfSubtitlesTracks != shouldHaveSubtitleTracks {}
// Select default track & resume playback
mediaPlayer.currentVideoSubTitleIndex = selectedCaptionTrack
mediaPlayer.pause()
mediaPlayer.play()
}
self.mediaHasStartedPlaying()
delegate?.hideLoadingView(self)
mediaPlayer.pause()
mediaPlayer.play()
print("Local engine started.")
}
@ -837,6 +831,7 @@ extension PlayerViewController: VLCMediaPlayerDelegate {
}
if CACurrentMediaTime() - lastProgressReportTime > 5 {
mediaPlayer.currentVideoSubTitleIndex = selectedCaptionTrack
sendProgressReport(eventName: "timeupdate")
lastProgressReportTime = CACurrentMediaTime()
}

View File

@ -72,7 +72,20 @@ final class ConnectToServerViewModel: ViewModel {
func login() {
SessionManager.current.login(username: usernameSubject.value, password: passwordSubject.value)
.sink(receiveCompletion: { completion in
self.handleAPIRequestCompletion(completion: completion)
switch completion {
case .finished:
break
case .failure(let error):
if let err = error as? ErrorResponse {
switch err {
case .error(401, _, _, _):
self.errorMessage = "Invalid credentials"
case .error:
self.errorMessage = err.localizedDescription
}
}
break
}
}, receiveValue: { _ in
})