Fix data model issues

This commit is contained in:
ronaldheft 2022-08-10 22:17:12 -04:00
parent e275aa1699
commit 446e54cb91
6 changed files with 65 additions and 69 deletions

View file

@ -45,7 +45,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Local library
Realm.registerRealmables(LocalLibraryItem.self)
Realm.registerRealmables(LocalPodcastEpisode.self)
Realm.registerRealmables(LocalFile.self)
Realm.registerRealmables(LocalMediaProgress.self)

View file

@ -154,10 +154,8 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
let files = downloadItem.downloadItemParts.compactMap { part -> LocalFile? in
if part.filename == "cover.jpg" {
coverFile = part.destinationUri
return nil
} else {
return LocalFile(libraryItem.id, part.filename!, part.mimeType()!, part.destinationUri!, fileSize: Int(part.destinationURL!.fileSize))
}
return LocalFile(libraryItem.id, part.filename!, part.mimeType()!, part.destinationUri!, fileSize: Int(part.destinationURL!.fileSize))
}
let localLibraryItem = LocalLibraryItem(libraryItem, localUrl: localDirectory, server: Store.serverConfig!, files: files, coverPath: coverFile)
@ -165,8 +163,8 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate {
statusNotification["localLibraryItem"] = try? localLibraryItem.asDictionary()
if let progress = libraryItem.userMediaProgress {
// TODO: Handle podcast
let localMediaProgress = LocalMediaProgress(localLibraryItem: localLibraryItem, episode: nil, progress: progress)
let episode = downloadItem.media?.episodes?.first(where: { $0.id == downloadItem.episodeId })
let localMediaProgress = LocalMediaProgress(localLibraryItem: localLibraryItem, episode: episode, progress: progress)
Database.shared.saveLocalMediaProgress(localMediaProgress)
statusNotification["localMediaProgress"] = try? localMediaProgress.asDictionary()
}

View file

@ -199,8 +199,7 @@ struct AudioTrack: Realmable, Codable {
var contentUrl: String?
var mimeType: String
var metadata: FileMetadata?
// var isLocal: Bool
// var localFileId: String?
var localFileId: String?
// var audioProbeResult: AudioProbeResult? Needed for local playback
var serverIndex: Int?
@ -208,6 +207,13 @@ struct AudioTrack: Realmable, Codable {
duration = 0
mimeType = ""
}
mutating func setLocalInfo(filenameIdMap: [String: String], serverIndex: Int) {
if let localFileId = filenameIdMap[self.metadata?.filename ?? ""] {
self.localFileId = localFileId
self.serverIndex = serverIndex
}
}
}
struct FileMetadata: Realmable, Codable {

View file

@ -121,6 +121,14 @@ extension DownloadItemPart {
}
func mimeType() -> String? {
audioTrack?.mimeType ?? episode?.audioTrack?.mimeType
if let track = audioTrack {
return track.mimeType
} else if let podcastTrack = episode?.audioTrack {
return podcastTrack.mimeType
} else if serverPath?.hasSuffix("/cover") ?? false {
return "image/jpg"
} else {
return nil
}
}
}

View file

@ -11,12 +11,12 @@ import Unrealm
struct LocalLibraryItem: Realmable, Codable {
var id: String = "local_\(UUID().uuidString)"
var basePath: String = ""
dynamic var _contentUrl: String?
var _contentUrl: String?
var isInvalid: Bool = false
var mediaType: String = ""
var media: MediaType?
var localFiles: [LocalFile] = []
dynamic var _coverContentUrl: String?
var _coverContentUrl: String?
var isLocal: Bool = true
var serverConnectionConfigId: String?
var serverAddress: String?
@ -24,30 +24,20 @@ struct LocalLibraryItem: Realmable, Codable {
var libraryItemId: String?
var contentUrl: String? {
set(url) {
_contentUrl = url
}
get {
if let path = _contentUrl {
return AbsDownloader.downloadsDirectory.appendingPathComponent(path).absoluteString
} else {
return nil
}
}
}
var coverContentUrl: String? {
set(url) {
_coverContentUrl = url
}
get {
if let path = self._coverContentUrl {
return AbsDownloader.downloadsDirectory.appendingPathComponent(path).absoluteString
} else {
return nil
}
}
}
static func primaryKey() -> String? {
return "id"
@ -63,17 +53,15 @@ struct LocalLibraryItem: Realmable, Codable {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decode(String.self, forKey: .id)
basePath = try values.decode(String.self, forKey: .basePath)
contentUrl = try values.decode(String.self, forKey: .contentUrl)
isInvalid = try values.decode(Bool.self, forKey: .isInvalid)
mediaType = try values.decode(String.self, forKey: .mediaType)
media = try values.decode(MediaType.self, forKey: .media)
localFiles = try values.decode([LocalFile].self, forKey: .localFiles)
coverContentUrl = try values.decode(String.self, forKey: .coverContentUrl)
isLocal = try values.decode(Bool.self, forKey: .isLocal)
serverConnectionConfigId = try values.decode(String.self, forKey: .serverConnectionConfigId)
serverAddress = try values.decode(String.self, forKey: .serverAddress)
serverUserId = try values.decode(String.self, forKey: .serverUserId)
libraryItemId = try values.decode(String.self, forKey: .libraryItemId)
serverConnectionConfigId = try? values.decode(String.self, forKey: .serverConnectionConfigId)
serverAddress = try? values.decode(String.self, forKey: .serverAddress)
serverUserId = try? values.decode(String.self, forKey: .serverUserId)
libraryItemId = try? values.decode(String.self, forKey: .libraryItemId)
}
func encode(to encoder: Encoder) throws {
@ -94,41 +82,23 @@ struct LocalLibraryItem: Realmable, Codable {
}
}
struct LocalPodcastEpisode: Realmable, Codable {
var id: String = UUID().uuidString
var index: Int = 0
var episode: String?
var episodeType: String?
var title: String = "Unknown"
var subtitle: String?
var desc: String?
var audioFile: AudioFile?
var audioTrack: AudioTrack?
var duration: Double = 0
var size: Int = 0
var serverEpisodeId: String?
static func primaryKey() -> String? {
return "id"
}
}
struct LocalFile: Realmable, Codable {
var id: String = UUID().uuidString
var filename: String?
var contentUrl: String = ""
var absolutePath: String {
return AbsDownloader.downloadsDirectory.appendingPathComponent(self.contentUrl).absoluteString
}
var _contentUrl: String = ""
var mimeType: String?
var size: Int = 0
var contentUrl: String {
return AbsDownloader.downloadsDirectory.appendingPathComponent(_contentUrl).absoluteString
}
static func primaryKey() -> String? {
return "id"
}
private enum CodingKeys : String, CodingKey {
case id, filename, contentUrl, absolutePath, mimeType, size
case id, filename, contentUrl, mimeType, size
}
init() {}
@ -137,8 +107,7 @@ struct LocalFile: Realmable, Codable {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decode(String.self, forKey: .id)
filename = try values.decode(String.self, forKey: .filename)
contentUrl = try values.decode(String.self, forKey: .contentUrl)
mimeType = try values.decode(String.self, forKey: .mimeType)
mimeType = try? values.decode(String.self, forKey: .mimeType)
size = try values.decode(Int.self, forKey: .size)
}
@ -147,7 +116,6 @@ struct LocalFile: Realmable, Codable {
try container.encode(id, forKey: .id)
try container.encode(filename, forKey: .filename)
try container.encode(contentUrl, forKey: .contentUrl)
try container.encode(absolutePath, forKey: .absolutePath)
try container.encode(mimeType, forKey: .mimeType)
try container.encode(size, forKey: .size)
}

View file

@ -10,15 +10,32 @@ import Foundation
extension LocalLibraryItem {
init(_ item: LibraryItem, localUrl: String, server: ServerConnectionConfig, files: [LocalFile], coverPath: String?) {
self.init()
self.contentUrl = localUrl
self._contentUrl = localUrl
self.mediaType = item.mediaType
self.media = item.media
self.localFiles = files
self.coverContentUrl = coverPath
self._coverContentUrl = coverPath
self.libraryItemId = item.id
self.serverConnectionConfigId = server.id
self.serverAddress = server.address
self.serverUserId = server.userId
// Link the audio tracks and files
var media = item.media
let fileIdByFilename = Dictionary(uniqueKeysWithValues: files.map { ($0.filename ?? "", $0.id) } )
if ( item.mediaType == "book" ) {
if let tracks = media.tracks {
for i in tracks.indices {
media.tracks?[i].setLocalInfo(filenameIdMap: fileIdByFilename, serverIndex: i)
}
}
} else if ( item.mediaType == "podcast" ) {
if let episodes = media.episodes {
for i in episodes.indices {
media.episodes?[i].audioTrack?.setLocalInfo(filenameIdMap: fileIdByFilename, serverIndex: 0)
}
}
}
self.media = media
}
func getDuration() -> Double {
@ -27,7 +44,7 @@ extension LocalLibraryItem {
return total
}
func getPlaybackSession(episode: LocalPodcastEpisode?) -> PlaybackSession {
func getPlaybackSession(episode: PodcastEpisode?) -> PlaybackSession {
let localEpisodeId = episode?.id
let sessionId = "play_local_\(UUID().uuidString)"
@ -49,7 +66,7 @@ extension LocalLibraryItem {
id: sessionId,
userId: self.serverUserId,
libraryItemId: self.libraryItemId,
episodeId: episode?.serverEpisodeId,
episodeId: episode?.id,
mediaType: self.mediaType,
chapters: [],
displayTitle: mediaMetadata?.title,
@ -75,7 +92,7 @@ extension LocalFile {
self.id = "\(libraryItemId)_\(filename.toBase64())"
self.filename = filename
self.mimeType = mimeType
self.contentUrl = localUrl
self._contentUrl = localUrl
self.size = fileSize
}
@ -91,7 +108,7 @@ extension LocalFile {
}
extension LocalMediaProgress {
init(localLibraryItem: LocalLibraryItem, episode: LocalPodcastEpisode?, progress: MediaProgress) {
init(localLibraryItem: LocalLibraryItem, episode: PodcastEpisode?, progress: MediaProgress) {
self.id = localLibraryItem.id
self.localLibraryItemId = localLibraryItem.id
self.libraryItemId = localLibraryItem.libraryItemId