diff --git a/ios/App/App.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/App/App.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 00000000..18d98100
--- /dev/null
+++ b/ios/App/App.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/App/App/AppDelegate.swift b/ios/App/App/AppDelegate.swift
index 105aefab..5ffa1b7e 100644
--- a/ios/App/App/AppDelegate.swift
+++ b/ios/App/App/AppDelegate.swift
@@ -15,7 +15,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
migrationBlock: { migration, oldSchemaVersion in
if (oldSchemaVersion < 1) {
NSLog("Realm schema version was \(oldSchemaVersion)")
- migration.enumerateObjects(ofType: DeviceSettings.className()) { oldObject, newObject in
+ migration.enumerateObjects(ofType: DeviceSettings.rlmClassName()) { oldObject, newObject in
newObject?["enableAltView"] = false
}
}
@@ -23,6 +23,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
)
Realm.Configuration.defaultConfiguration = configuration
+ Realm.registerRealmables(DeviceSettings.self)
+ Realm.registerRealmables(ServerConnectionConfig.self)
+ Realm.registerRealmables(ServerConnectionConfigActiveIndex.self)
+
+ // Data classes
+ Realm.registerRealmables(LibraryItem.self)
+ Realm.registerRealmables(MediaType.self)
+ Realm.registerRealmables(Metadata.self)
+ Realm.registerRealmables(PodcastEpisode.self)
+ Realm.registerRealmables(AudioFile.self)
+ Realm.registerRealmables(Author.self)
+ Realm.registerRealmables(Chapter.self)
+ Realm.registerRealmables(AudioTrack.self)
+ Realm.registerRealmables(FileMetadata.self)
+ Realm.registerRealmables(Library.self)
+ Realm.registerRealmables(Folder.self)
+ Realm.registerRealmables(LibraryFile.self)
+ Realm.registerRealmables(MediaProgress.self)
+ Realm.registerRealmables(PlaybackMetadata.self)
+
+ // Local library
+ Realm.registerRealmables(LocalLibraryItem.self)
+ Realm.registerRealmables(LocalPodcastEpisode.self)
+ Realm.registerRealmables(LocalFile.self)
+ Realm.registerRealmables(LocalMediaProgress.self)
+
return true
}
diff --git a/ios/App/App/plugins/AbsDatabase.swift b/ios/App/App/plugins/AbsDatabase.swift
index e7ed178c..518f79ff 100644
--- a/ios/App/App/plugins/AbsDatabase.swift
+++ b/ios/App/App/plugins/AbsDatabase.swift
@@ -35,18 +35,12 @@ public class AbsDatabase: CAPPlugin {
let token = call.getString("token", "")
let name = "\(address) (\(username))"
- let config = ServerConnectionConfig()
if id == nil {
id = "\(address)@\(username)".toBase64()
}
- config.id = id!
- config.name = name
- config.address = address
- config.userId = userId
- config.username = username
- config.token = token
+ let config = ServerConnectionConfig(id: id!, index: 0, name: name, address: address, userId: userId, username: username, token: token)
Store.serverConfig = config
call.resolve(convertServerConnectionConfigToJSON(config: config))
@@ -77,7 +71,7 @@ public class AbsDatabase: CAPPlugin {
@objc func getLocalLibraryItems(_ call: CAPPluginCall) {
do {
let items = Database.shared.getLocalLibraryItems()
- call.resolve([ "value": try items.asDictionaryArray() ])
+ call.resolve([ "value": try items.asDictionaryArray()])
} catch(let exception) {
NSLog("error while readling local library items")
debugPrint(exception)
@@ -128,11 +122,7 @@ public class AbsDatabase: CAPPlugin {
let enableAltView = call.getBool("enableAltView") ?? false
let jumpBackwardsTime = call.getInt("jumpBackwardsTime") ?? 10
let jumpForwardTime = call.getInt("jumpForwardTime") ?? 10
- let settings = DeviceSettings()
- settings.disableAutoRewind = disableAutoRewind
- settings.enableAltView = enableAltView
- settings.jumpBackwardsTime = jumpBackwardsTime
- settings.jumpForwardTime = jumpForwardTime
+ let settings = DeviceSettings(disableAutoRewind: disableAutoRewind, enableAltView: enableAltView, jumpBackwardsTime: jumpBackwardsTime, jumpForwardTime: jumpForwardTime)
Database.shared.setDeviceSettings(deviceSettings: settings)
diff --git a/ios/App/Shared/models/DataClasses.swift b/ios/App/Shared/models/DataClasses.swift
index b29b7a6f..4130c5b6 100644
--- a/ios/App/Shared/models/DataClasses.swift
+++ b/ios/App/Shared/models/DataClasses.swift
@@ -7,22 +7,22 @@
import Foundation
import CoreMedia
-import RealmSwift
+import Unrealm
-struct LibraryItem: Codable {
+struct LibraryItem: Realmable, Codable {
var id: String
- var ino:String
+ var ino: String
var libraryId: String
var folderId: String
var path: String
var relPath: String
var isFile: Bool
- var mtimeMs: Int64
- var ctimeMs: Int64
- var birthtimeMs: Int64
- var addedAt: Int64
- var updatedAt: Int64
- var lastScan: Int64?
+ var mtimeMs: Int
+ var ctimeMs: Int
+ var birthtimeMs: Int
+ var addedAt: Int
+ var updatedAt: Int
+ var lastScan: Int?
var scanVersion: String?
var isMissing: Bool
var isInvalid: Bool
@@ -30,9 +30,29 @@ struct LibraryItem: Codable {
var media: MediaType
var libraryFiles: [LibraryFile]
var userMediaProgress: MediaProgress?
+
+ init() {
+ id = ""
+ ino = ""
+ libraryId = ""
+ folderId = ""
+ path = ""
+ relPath = ""
+ isFile = true
+ mtimeMs = 0
+ ctimeMs = 0
+ birthtimeMs = 0
+ addedAt = 0
+ updatedAt = 0
+ isMissing = false
+ isInvalid = false
+ mediaType = ""
+ media = MediaType()
+ libraryFiles = []
+ }
}
-struct MediaType: Codable {
+struct MediaType: Realmable, Codable {
var libraryItemId: String?
var metadata: Metadata
var coverPath: String?
@@ -40,13 +60,17 @@ struct MediaType: Codable {
var audioFiles: [AudioFile]?
var chapters: [Chapter]?
var tracks: [AudioTrack]?
- var size: Int64?
+ var size: Int?
var duration: Double?
var episodes: [PodcastEpisode]?
var autoDownloadEpisodes: Bool?
+
+ init() {
+ metadata = Metadata()
+ }
}
-struct Metadata: Codable {
+struct Metadata: Realmable, Codable {
var title: String
var subtitle: String?
var authors: [Author]?
@@ -65,9 +89,15 @@ struct Metadata: Codable {
var narratorName: String?
var seriesName: String?
var feedUrl: String?
+
+ init() {
+ title = "Unknown"
+ genres = []
+ explicit = false
+ }
}
-struct PodcastEpisode: Codable {
+struct PodcastEpisode: Realmable, Codable {
var id: String
var index: Int
var episode: String?
@@ -78,30 +108,55 @@ struct PodcastEpisode: Codable {
var audioFile: AudioFile?
var audioTrack: AudioTrack?
var duration: Double
- var size: Int64
+ var size: Int
// var serverEpisodeId: String?
+
+ init() {
+ id = ""
+ index = 0
+ title = "Unknown"
+ duration = 0
+ size = 0
+ }
}
-struct AudioFile: Codable {
+struct AudioFile: Realmable, Codable {
var index: Int
var ino: String
var metadata: FileMetadata
+
+ init() {
+ index = 0
+ ino = ""
+ metadata = FileMetadata()
+ }
}
-struct Author: Codable {
+struct Author: Realmable, Codable {
var id: String
var name: String
var coverPath: String?
+
+ init() {
+ id = ""
+ name = "Unknown"
+ }
}
-struct Chapter: Codable {
+struct Chapter: Realmable, Codable {
var id: Int
var start: Double
var end: Double
var title: String?
+
+ init() {
+ id = 0
+ start = 0
+ end = 0
+ }
}
-struct AudioTrack: Codable {
+struct AudioTrack: Realmable, Codable {
var index: Int?
var startOffset: Double?
var duration: Double
@@ -113,50 +168,101 @@ struct AudioTrack: Codable {
// var localFileId: String?
// var audioProbeResult: AudioProbeResult? Needed for local playback
var serverIndex: Int?
+
+ init() {
+ duration = 0
+ mimeType = ""
+ }
}
-struct FileMetadata: Codable {
+struct FileMetadata: Realmable, Codable {
var filename: String
var ext: String
var path: String
var relPath: String
+
+ init() {
+ filename = ""
+ ext = ""
+ path = ""
+ relPath = ""
+ }
}
-struct Library: Codable {
+struct Library: Realmable, Codable {
var id: String
var name: String
var folders: [Folder]
var icon: String
var mediaType: String
+
+ init() {
+ id = ""
+ name = "Unknown"
+ folders = []
+ icon = ""
+ mediaType = ""
+ }
}
-struct Folder: Codable {
+struct Folder: Realmable, Codable {
var id: String
var fullPath: String
+
+ init() {
+ id = ""
+ fullPath = ""
+ }
}
-struct LibraryFile: Codable {
+struct LibraryFile: Realmable, Codable {
var ino: String
var metadata: FileMetadata
+
+ init() {
+ ino = ""
+ metadata = FileMetadata()
+ }
}
-struct MediaProgress:Codable {
- var id:String
- var libraryItemId:String
- var episodeId:String?
- var duration:Double
- var progress:Double
- var currentTime:Double
- var isFinished:Bool
- var lastUpdate:Int64
- var startedAt:Int64
- var finishedAt:Int64?
+struct MediaProgress: Realmable, Codable {
+ var id: String
+ var libraryItemId: String
+ var episodeId: String?
+ var duration: Double
+ var progress: Double
+ var currentTime: Double
+ var isFinished: Bool
+ var lastUpdate: Int
+ var startedAt: Int
+ var finishedAt: Int?
+
+ init() {
+ id = ""
+ libraryItemId = ""
+ duration = 0
+ progress = 0
+ currentTime = 0
+ isFinished = false
+ lastUpdate = 0
+ startedAt = 0
+ }
}
-struct PlaybackMetadata: Codable {
+struct PlaybackMetadata: Realmable, Codable {
var duration: Double
var currentTime: Double
var playerState: PlayerState
+
+ init() {
+ duration = 0
+ currentTime = 0
+ playerState = PlayerState.IDLE
+ }
+
+ static func ignoredProperties() -> [String] {
+ return ["playerState"]
+ }
}
enum PlayerState: Codable {
diff --git a/ios/App/Shared/models/DeviceSettings.swift b/ios/App/Shared/models/DeviceSettings.swift
index cd823916..34d29bd6 100644
--- a/ios/App/Shared/models/DeviceSettings.swift
+++ b/ios/App/Shared/models/DeviceSettings.swift
@@ -7,21 +7,17 @@
import Foundation
import RealmSwift
+import Unrealm
-class DeviceSettings: Object {
- @Persisted var disableAutoRewind: Bool
- @Persisted var enableAltView: Bool
- @Persisted var jumpBackwardsTime: Int
- @Persisted var jumpForwardTime: Int
+struct DeviceSettings: Realmable {
+ var disableAutoRewind: Bool = false
+ var enableAltView: Bool = false
+ var jumpBackwardsTime: Int = 10
+ var jumpForwardTime: Int = 10
}
func getDefaultDeviceSettings() -> DeviceSettings {
- let settings = DeviceSettings()
- settings.disableAutoRewind = false
- settings.enableAltView = false
- settings.jumpForwardTime = 10
- settings.jumpBackwardsTime = 10
- return settings
+ return DeviceSettings()
}
func deviceSettingsToJSON(settings: DeviceSettings) -> Dictionary {
diff --git a/ios/App/Shared/models/LocalLibrary.swift b/ios/App/Shared/models/LocalLibrary.swift
index fb5c4f36..f0e49887 100644
--- a/ios/App/Shared/models/LocalLibrary.swift
+++ b/ios/App/Shared/models/LocalLibrary.swift
@@ -6,139 +6,81 @@
//
import Foundation
-import RealmSwift
+import Unrealm
-class LocalLibraryItem: Object, Encodable {
- @Persisted(primaryKey: true) var id: String = "local_\(UUID().uuidString)"
- @Persisted var basePath: String = ""
- @Persisted var absolutePath: String = ""
- @Persisted var contentUrl: String
- @Persisted var isInvalid: Bool = false
- @Persisted var mediaType: String
- @Persisted var media: LocalMediaType?
- @Persisted var localFiles: List
- @Persisted var coverContentUrl: String? = nil
- @Persisted var coverAbsolutePath: String? = nil
- @Persisted var isLocal: Bool = true
- @Persisted var serverConnectionConfigId: String? = nil
- @Persisted var serverAddress: String? = nil
- @Persisted var serverUserId: String? = nil
- @Persisted var libraryItemId: String? = nil
+struct LocalLibraryItem: Realmable, Codable {
+ var id: String = "local_\(UUID().uuidString)"
+ var basePath: String = ""
+ var absolutePath: String = ""
+ var contentUrl: String = ""
+ var isInvalid: Bool = false
+ var mediaType: String = ""
+ var media: MediaType?
+ var localFiles: [LocalFile] = []
+ var coverContentUrl: String?
+ var coverAbsolutePath: String?
+ var isLocal: Bool = true
+ var serverConnectionConfigId: String?
+ var serverAddress: String?
+ var serverUserId: String?
+ var libraryItemId: String?
+
+ static func primaryKey() -> String? {
+ return "id"
+ }
}
-class LocalMediaType: Object, Encodable {
- @Persisted var libraryItemId: String? = ""
- @Persisted var metadata: LocalMetadata?
- @Persisted var coverPath: String? = ""
- @Persisted var tags: List
- @Persisted var audioFiles: List
- @Persisted var chapters: List
- @Persisted var tracks: List
- @Persisted var size: Int64? = nil
- @Persisted var duration: Double? = nil
- @Persisted var episodes: List
- @Persisted var autoDownloadEpisodes: Bool? = nil
+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"
+ }
}
-class LocalMetadata: Object, Encodable {
- @Persisted var title: String
- @Persisted var subtitle: String? = ""
- @Persisted var authors: List
- @Persisted var narrators: List
- @Persisted var genres: List
- @Persisted var publishedYear: String? = ""
- @Persisted var publishedDate: String? = ""
- @Persisted var publisher: String? = ""
- @Persisted var desc: String? = ""
- @Persisted var isbn: String? = ""
- @Persisted var asin: String? = ""
- @Persisted var language: String? = ""
- @Persisted var explicit: Bool
- @Persisted var authorName: String? = ""
- @Persisted var authorNameLF: String? = ""
- @Persisted var narratorName: String? = ""
- @Persisted var seriesName: String? = ""
- @Persisted var feedUrl: String? = ""
+struct LocalFile: Realmable, Codable {
+ var id: String = UUID().uuidString
+ var filename: String?
+ var contentUrl: String = ""
+ var absolutePath: String = ""
+ var mimeType: String?
+ var size: Int = 0
+
+ static func primaryKey() -> String? {
+ return "id"
+ }
}
-class LocalPodcastEpisode: Object, Encodable {
- @Persisted var id: String = UUID().uuidString
- @Persisted var index: Int
- @Persisted var episode: String? = ""
- @Persisted var episodeType: String? = ""
- @Persisted var title: String
- @Persisted var subtitle: String? = ""
- @Persisted var desc: String? = ""
- @Persisted var audioFile: LocalAudioFile? = nil
- @Persisted var audioTrack: LocalAudioTrack? = nil
- @Persisted var duration: Double
- @Persisted var size: Int64
- @Persisted var serverEpisodeId: String?
-}
-
-class LocalAudioFile: Object, Encodable {
- @Persisted var index: Int
- @Persisted var ino: String
- @Persisted var metadata: LocalFileMetadata?
-}
-
-class LocalAuthor: Object, Encodable {
- @Persisted var id: String = UUID().uuidString
- @Persisted var name: String
- @Persisted var coverPath: String? = ""
-}
-
-class LocalChapter: Object, Encodable {
- @Persisted var id: Int
- @Persisted var start: Double
- @Persisted var end: Double
- @Persisted var title: String? = nil
-}
-
-class LocalAudioTrack: Object, Encodable {
- @Persisted var index: Int? = nil
- @Persisted var startOffset: Double? = nil
- @Persisted var duration: Double
- @Persisted var title: String? = ""
- @Persisted var contentUrl: String? = ""
- @Persisted var mimeType: String
- @Persisted var metadata: LocalFileMetadata? = nil
- @Persisted var isLocal: Bool = true
- @Persisted var localFileId: String? = ""
- @Persisted var serverIndex: Int? = nil
-}
-
-class LocalFileMetadata: Object, Encodable {
- @Persisted var filename: String
- @Persisted var ext: String
- @Persisted var path: String
- @Persisted var relPath: String
-}
-
-class LocalFile: Object, Encodable {
- @Persisted var id: String = UUID().uuidString
- @Persisted var filename: String? = ""
- @Persisted var contentUrl: String
- @Persisted var absolutePath: String
- @Persisted var mimeType: String? = ""
- @Persisted var size: Int64
-}
-
-class LocalMediaProgress: Object, Encodable {
- @Persisted(primaryKey: true) var id: String = UUID().uuidString
- @Persisted var localLibraryItemId: String
- @Persisted var localEpisodeId: String? = ""
- @Persisted var duration: Double
- @Persisted var progress: Double // 0 to 1
- @Persisted var currentTime: Double
- @Persisted var isFinished: Bool
- @Persisted var lastUpdate: Int64
- @Persisted var startedAt: Int64
- @Persisted var finishedAt: Int64? = nil
+struct LocalMediaProgress: Realmable, Codable {
+ var id: String = UUID().uuidString
+ var localLibraryItemId: String = ""
+ var localEpisodeId: String?
+ var duration: Double = 0
+ var progress: Double = 0
+ var currentTime: Double = 0
+ var isFinished: Bool = false
+ var lastUpdate: Int = 0
+ var startedAt: Int = 0
+ var finishedAt: Int?
// For local lib items from server to support server sync
- @Persisted var serverConnectionConfigId: String? = ""
- @Persisted var serverAddress: String? = ""
- @Persisted var serverUserId: String? = ""
- @Persisted var libraryItemId: String? = ""
- @Persisted var episodeId: String? = ""
+ var serverConnectionConfigId: String?
+ var serverAddress: String?
+ var serverUserId: String?
+ var libraryItemId: String?
+ var episodeId: String?
+
+ static func primaryKey() -> String? {
+ return "id"
+ }
}
diff --git a/ios/App/Shared/models/LocalLibraryExtensions.swift b/ios/App/Shared/models/LocalLibraryExtensions.swift
index c08337ce..e05c6be0 100644
--- a/ios/App/Shared/models/LocalLibraryExtensions.swift
+++ b/ios/App/Shared/models/LocalLibraryExtensions.swift
@@ -8,49 +8,12 @@
import Foundation
extension LocalLibraryItem {
- enum CodingKeys: CodingKey {
- case id
- case basePath
- case absolutePath
- case contentUrl
- case isInvalid
- case mediaType
- case media
- case localFiles
- case coverContentUrl
- case coverAbsolutePath
- case isLocal
- case serverConnectionConfigId
- case serverAddress
- case serverUserId
- case libraryItemId
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(id, forKey: .id)
- try container.encode(basePath, forKey: .basePath)
- try container.encode(absolutePath, forKey: .absolutePath)
- try container.encode(contentUrl, forKey: .contentUrl)
- try container.encode(isInvalid, forKey: .isInvalid)
- try container.encode(mediaType, forKey: .mediaType)
- try container.encode(media, forKey: .media)
- try container.encode(localFiles, forKey: .localFiles)
- try container.encode(coverContentUrl, forKey: .coverContentUrl)
- try container.encode(coverAbsolutePath, forKey: .coverAbsolutePath)
- try container.encode(isLocal, forKey: .isLocal)
- try container.encode(serverConnectionConfigId, forKey: .serverConnectionConfigId)
- try container.encode(serverAddress, forKey: .serverAddress)
- try container.encode(serverUserId, forKey: .serverUserId)
- try container.encode(libraryItemId, forKey: .libraryItemId)
- }
-
- convenience init(_ item: LibraryItem, localUrl: URL, server: ServerConnectionConfig, files: [LocalFile]) {
+ init(_ item: LibraryItem, localUrl: URL, server: ServerConnectionConfig, files: [LocalFile]) {
self.init()
self.contentUrl = localUrl.absoluteString
self.mediaType = item.mediaType
- self.media = LocalMediaType(item.media, coverPath: "", files: files)
- self.localFiles.append(objectsIn: files)
+ self.media = item.media
+ self.localFiles = files
// TODO: self.coverContentURL
// TODO: self.converAbsolutePath
self.libraryItemId = item.id
@@ -61,7 +24,7 @@ extension LocalLibraryItem {
func getDuration() -> Double {
var total = 0.0
- self.media?.tracks.forEach { track in total += track.duration }
+ self.media?.tracks?.forEach { track in total += track.duration }
return total
}
@@ -107,315 +70,14 @@ extension LocalLibraryItem {
}
}
-extension LocalMediaType {
- enum CodingKeys: CodingKey {
- case libraryItemId
- case metadata
- case coverPath
- case tags
- case audioFiles
- case chapters
- case tracks
- case size
- case duration
- case episodes
- case autoDownloadEpisodes
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(libraryItemId, forKey: .libraryItemId)
- try container.encode(metadata, forKey: .metadata)
- try container.encode(coverPath, forKey: .coverPath)
- try container.encode(tags, forKey: .tags)
- try container.encode(audioFiles, forKey: .audioFiles)
- try container.encode(chapters, forKey: .chapters)
- try container.encode(tracks, forKey: .tracks)
- try container.encode(size, forKey: .size)
- try container.encode(duration, forKey: .duration)
- try container.encode(episodes, forKey: .episodes)
- try container.encode(autoDownloadEpisodes, forKey: .autoDownloadEpisodes)
- }
-
- convenience init(_ mediaType: MediaType, coverPath: String, files: [LocalFile]) {
- self.init()
- self.libraryItemId = mediaType.libraryItemId
- self.metadata = LocalMetadata(mediaType.metadata)
- self.coverPath = coverPath
- self.tags.append(objectsIn: mediaType.tags ?? [])
- self.audioFiles.append(objectsIn: mediaType.audioFiles!.enumerated().map() {
- i, audioFile -> LocalAudioFile in LocalAudioFile(audioFile)
- })
- self.chapters.append(objectsIn: mediaType.chapters!.enumerated().map() {
- i, chapter -> LocalChapter in LocalChapter(chapter)
- })
- self.tracks.append(objectsIn: mediaType.tracks!.enumerated().map() {
- i, track in LocalAudioTrack(track, libraryItemId: self.libraryItemId ?? "", filename: files[i].filename ?? "")
- })
- self.size = mediaType.size
- self.duration = mediaType.duration
- // TODO: self.episodes
- // TODO: Handle podcast auto downloads
- self.autoDownloadEpisodes = mediaType.autoDownloadEpisodes
- }
-}
-
-extension LocalMetadata {
- enum CodingKeys: CodingKey {
- case title
- case subtitle
- case authors
- case narrators
- case genres
- case publishedYear
- case publishedDate
- case publisher
- case desc
- case isbn
- case asin
- case language
- case explicit
- case authorName
- case authorNameLF
- case narratorName
- case seriesName
- case feedUrl
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(title, forKey: .title)
- try container.encode(subtitle, forKey: .subtitle)
- try container.encode(authors, forKey: .authors)
- try container.encode(narrators, forKey: .narrators)
- try container.encode(genres, forKey: .genres)
- try container.encode(publishedYear, forKey: .publishedYear)
- try container.encode(publishedDate, forKey: .publishedDate)
- try container.encode(publisher, forKey: .publisher)
- try container.encode(desc, forKey: .desc)
- try container.encode(isbn, forKey: .isbn)
- try container.encode(asin, forKey: .asin)
- try container.encode(language, forKey: .language)
- try container.encode(explicit, forKey: .explicit)
- try container.encode(authorName, forKey: .authorName)
- try container.encode(authorNameLF, forKey: .authorNameLF)
- try container.encode(narratorName, forKey: .narratorName)
- try container.encode(seriesName, forKey: .seriesName)
- try container.encode(feedUrl, forKey: .feedUrl)
- }
-
- convenience init(_ metadata: Metadata) {
- self.init()
- self.title = metadata.title
- self.subtitle = metadata.subtitle
- self.narrators.append(objectsIn: metadata.narrators ?? [])
- self.genres.append(objectsIn: metadata.genres)
- self.publishedYear = metadata.publishedYear
- self.publishedDate = metadata.publishedDate
- self.publisher = metadata.publisher
- self.desc = metadata.description
- self.isbn = metadata.isbn
- self.asin = metadata.asin
- self.language = metadata.language
- self.explicit = metadata.explicit
- self.authorName = metadata.authorName
- self.authorNameLF = metadata.authorNameLF
- self.narratorName = metadata.narratorName
- self.seriesName = metadata.seriesName
- self.feedUrl = metadata.feedUrl
- }
-}
-
-extension LocalPodcastEpisode {
- enum CodingKeys: CodingKey {
- case id
- case index
- case episode
- case episodeType
- case title
- case subtitle
- case desc
- case audioFile
- case audioTrack
- case duration
- case size
- case serverEpisodeId
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(id, forKey: .id)
- try container.encode(index, forKey: .index)
- try container.encode(episode, forKey: .episode)
- try container.encode(episodeType, forKey: .episodeType)
- try container.encode(title, forKey: .title)
- try container.encode(subtitle, forKey: .subtitle)
- try container.encode(desc, forKey: .desc)
- try container.encode(audioFile, forKey: .audioFile)
- try container.encode(audioTrack, forKey: .audioTrack)
- try container.encode(duration, forKey: .duration)
- try container.encode(size, forKey: .size)
- try container.encode(serverEpisodeId, forKey: .serverEpisodeId)
- }
-}
-
-extension LocalAudioFile {
- enum CodingKeys: CodingKey {
- case index
- case ino
- case metadata
- }
-
- convenience init(_ audioFile: AudioFile) {
- self.init()
- self.index = audioFile.index
- self.ino = audioFile.ino
- // self.metadata
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(index, forKey: .index)
- try container.encode(ino, forKey: .ino)
- try container.encode(metadata, forKey: .metadata)
- }
-}
-
-extension LocalAuthor {
- enum CodingKeys: CodingKey {
- case id
- case name
- case coverPath
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(id, forKey: .id)
- try container.encode(name, forKey: .name)
- try container.encode(coverPath, forKey: .coverPath)
- }
-
- convenience init(_ author: Author) {
- self.init()
- self.id = author.id
- self.name = author.name
- // self.coverPath
- }
-}
-
-extension LocalChapter {
- enum CodingKeys: CodingKey {
- case id
- case start
- case end
- case title
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(id, forKey: .id)
- try container.encode(start, forKey: .start)
- try container.encode(end, forKey: .end)
- try container.encode(title, forKey: .title)
- }
-
- convenience init(_ chapter: Chapter) {
- self.init()
- self.id = chapter.id
- self.start = chapter.start
- self.end = chapter.end
- self.title = chapter.title
- }
-}
-
-extension LocalAudioTrack {
- enum CodingKeys: CodingKey {
- case index
- case startOffset
- case duration
- case title
- case contentUrl
- case mimeType
- case metadata
- case isLocal
- case localFileId
- case serverIndex
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(index, forKey: .index)
- try container.encode(startOffset, forKey: .startOffset)
- try container.encode(duration, forKey: .duration)
- try container.encode(title, forKey: .title)
- try container.encode(contentUrl, forKey: .contentUrl)
- try container.encode(mimeType, forKey: .mimeType)
- try container.encode(metadata, forKey: .metadata)
- try container.encode(isLocal, forKey: .isLocal)
- try container.encode(localFileId, forKey: .localFileId)
- try container.encode(serverIndex, forKey: .serverIndex)
- }
-
- convenience init(_ track: AudioTrack, libraryItemId: String, filename: String) {
- self.init()
- self.index = track.index
- self.startOffset = track.startOffset
- self.duration = track.duration
- self.title = track.title
- self.contentUrl = "" // TODO: Different URL
- self.mimeType = track.mimeType
- // TODO: self.metadata
- self.localFileId = "\(libraryItemId)_\(filename.toBase64())"
- self.serverIndex = track.serverIndex
- }
-}
-
-extension LocalFileMetadata {
- enum CodingKeys: CodingKey {
- case filename
- case ext
- case path
- case relPath
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(filename, forKey: .filename)
- try container.encode(ext, forKey: .ext)
- try container.encode(path, forKey: .path)
- try container.encode(relPath, forKey: .relPath)
- }
-
- /* TODO: Can we skip this object? */
-}
-
extension LocalFile {
- enum CodingKeys: CodingKey {
- case id
- case filename
- case contentUrl
- case absolutePath
- case mimeType
- case size
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- 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)
- }
-
- convenience init(_ libraryItemId: String, _ filename: String, _ mimeType: String, _ localUrl: URL) {
+ init(_ libraryItemId: String, _ filename: String, _ mimeType: String, _ localUrl: URL) {
self.init()
self.id = "\(libraryItemId)_\(filename.toBase64())"
self.filename = filename
self.contentUrl = localUrl.absoluteString
self.absolutePath = localUrl.path
- self.size = localUrl.fileSize
+ self.size = Int(localUrl.fileSize)
}
func isAudioFile() -> Bool {
@@ -428,42 +90,3 @@ extension LocalFile {
}
}
}
-
-extension LocalMediaProgress {
- enum CodingKeys: CodingKey {
- case id
- case localLibraryItemId
- case localEpisodeId
- case duration
- case progress
- case currentTime
- case isFinished
- case lastUpdate
- case startedAt
- case finishedAt
- case serverConnectionConfigId
- case serverAddress
- case serverUserId
- case libraryItemId
- case episodeId
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(id, forKey: .id)
- try container.encode(localLibraryItemId, forKey: .localLibraryItemId)
- try container.encode(localEpisodeId, forKey: .localEpisodeId)
- try container.encode(duration, forKey: .duration)
- try container.encode(progress, forKey: .progress)
- try container.encode(currentTime, forKey: .currentTime)
- try container.encode(isFinished, forKey: .isFinished)
- try container.encode(lastUpdate, forKey: .lastUpdate)
- try container.encode(startedAt, forKey: .startedAt)
- try container.encode(finishedAt, forKey: .finishedAt)
- try container.encode(serverConnectionConfigId, forKey: .serverConnectionConfigId)
- try container.encode(serverAddress, forKey: .serverAddress)
- try container.encode(serverUserId, forKey: .serverUserId)
- try container.encode(libraryItemId, forKey: .libraryItemId)
- try container.encode(episodeId, forKey: .episodeId)
- }
-}
diff --git a/ios/App/Shared/models/ServerConnectionConfig.swift b/ios/App/Shared/models/ServerConnectionConfig.swift
index c8ace3e1..95ed644f 100644
--- a/ios/App/Shared/models/ServerConnectionConfig.swift
+++ b/ios/App/Shared/models/ServerConnectionConfig.swift
@@ -7,20 +7,29 @@
import Foundation
import RealmSwift
+import Unrealm
-class ServerConnectionConfig: Object {
- @Persisted(primaryKey: true) var id: String
- @Persisted(indexed: true) var index: Int
- @Persisted var name: String
- @Persisted var address: String
- @Persisted var userId: String
- @Persisted var username: String
- @Persisted var token: String
+struct ServerConnectionConfig: Realmable {
+ var id: String = UUID().uuidString
+ var index: Int = 0
+ var name: String = ""
+ var address: String = ""
+ var userId: String = ""
+ var username: String = ""
+ var token: String = ""
+
+ static func primaryKey() -> String? {
+ return "id"
+ }
+
+ static func indexedProperties() -> [String] {
+ return ["index"]
+ }
}
-class ServerConnectionConfigActiveIndex: Object {
- // This could overflow, but you really would have to try
- @Persisted var index: Int?
+struct ServerConnectionConfigActiveIndex: Realmable {
+ // This could overflow, but you really would have to try
+ var index: Int?
}
func convertServerConnectionConfigToJSON(config: ServerConnectionConfig) -> Dictionary {
diff --git a/ios/App/Shared/util/ApiClient.swift b/ios/App/Shared/util/ApiClient.swift
index f25e4bb9..c9ed9e97 100644
--- a/ios/App/Shared/util/ApiClient.swift
+++ b/ios/App/Shared/util/ApiClient.swift
@@ -114,9 +114,11 @@ class ApiClient {
callback(session)
}
}
+
public static func reportPlaybackProgress(report: PlaybackReport, sessionId: String) {
try? postResource(endpoint: "api/session/\(sessionId)/sync", parameters: report.asDictionary().mapValues({ value in "\(value)" }), callback: nil)
}
+
public static func getLibraryItemWithProgress(libraryItemId:String, episodeId:String?, callback: @escaping (_ param: LibraryItem?) -> Void) {
var endpoint = "api/items/\(libraryItemId)?expanded=1&include=progress"
if episodeId != nil {
diff --git a/ios/App/Shared/util/Database.swift b/ios/App/Shared/util/Database.swift
index 0ec073d9..7bc6afc1 100644
--- a/ios/App/Shared/util/Database.swift
+++ b/ios/App/Shared/util/Database.swift
@@ -23,16 +23,12 @@ class Database {
}
public func setServerConnectionConfig(config: ServerConnectionConfig) {
- var refrence: ThreadSafeReference?
- if config.realm != nil {
- refrence = ThreadSafeReference(to: config)
- }
-
+ var config = config
Database.realmQueue.sync {
- let existing: ServerConnectionConfig? = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: config.id)
+ var existing: ServerConnectionConfig? = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: config.id)
if config.index == 0 {
- let lastConfig: ServerConnectionConfig? = instance.objects(ServerConnectionConfig.self).last
+ var lastConfig: ServerConnectionConfig? = instance.objects(ServerConnectionConfig.self).last
if lastConfig != nil {
config.index = lastConfig!.index + 1
@@ -46,15 +42,7 @@ class Database {
if existing != nil {
instance.delete(existing!)
}
- if refrence == nil {
- instance.add(config)
- } else {
- guard let resolved = instance.resolve(refrence!) else {
- throw "unable to resolve refrence"
- }
-
- instance.add(resolved);
- }
+ instance.add(config)
}
} catch(let exception) {
NSLog("failed to save server config")
@@ -83,25 +71,8 @@ class Database {
}
public func getServerConnectionConfigs() -> [ServerConnectionConfig] {
- var refrences: [ThreadSafeReference] = []
-
Database.realmQueue.sync {
- let configs = instance.objects(ServerConnectionConfig.self)
- refrences = configs.map { config in
- return ThreadSafeReference(to: config)
- }
- }
-
- do {
- let realm = try Realm()
-
- return refrences.map { refrence in
- return realm.resolve(refrence)!
- }
- } catch(let exception) {
- NSLog("error while readling configs")
- debugPrint(exception)
- return []
+ return Array(instance.objects(ServerConnectionConfig.self))
}
}
@@ -113,7 +84,7 @@ class Database {
public func setLastActiveConfigIndex(index: Int?) {
let existing = instance.objects(ServerConnectionConfigActiveIndex.self)
- let obj = ServerConnectionConfigActiveIndex()
+ var obj = ServerConnectionConfigActiveIndex()
obj.index = index
do {
@@ -149,25 +120,8 @@ class Database {
}
public func getLocalLibraryItems(mediaType: MediaType? = nil) -> [LocalLibraryItem] {
- var localLibraryItems: [ThreadSafeReference] = []
-
Database.realmQueue.sync {
- let items = instance.objects(LocalLibraryItem.self)
- localLibraryItems = items.map { item in
- return ThreadSafeReference(to: item)
- }
- }
-
- do {
- let realm = try Realm()
-
- return localLibraryItems.map { item in
- return realm.resolve(item)!
- }
- } catch(let exception) {
- NSLog("error while readling local library items")
- debugPrint(exception)
- return []
+ Array(instance.objects(LocalLibraryItem.self))
}
}
@@ -183,26 +137,14 @@ class Database {
}
public func getLocalLibraryItem(localLibraryItem: String) -> LocalLibraryItem? {
- let items = getLocalLibraryItems()
- for item in items {
- if (item.id == localLibraryItem) {
- return item
- }
+ Database.realmQueue.sync {
+ instance.object(ofType: LocalLibraryItem.self, forPrimaryKey: localLibraryItem)
}
- NSLog("Local library item with id \(localLibraryItem) not found")
- return nil
}
public func saveLocalLibraryItem(localLibraryItem: LocalLibraryItem) {
Database.realmQueue.sync {
- do {
- try instance.write {
- instance.add(localLibraryItem);
- }
- } catch(let exception) {
- NSLog("Unable to save local library item")
- debugPrint(exception)
- }
+ try! instance.write { instance.add(localLibraryItem) }
}
}
@@ -213,19 +155,10 @@ class Database {
}
public func removeLocalLibraryItem(localLibraryItemId: String) {
- let item = getLocalLibraryItemByLLId(libraryItem: localLibraryItemId)
Database.realmQueue.sync {
- do {
- try instance.write {
- if item != nil {
- instance.delete(item!)
- } else {
- NSLog("Unable to find local library item to delete")
- }
- }
- } catch (let exception) {
- NSLog("Unable to delete local library item")
- debugPrint(exception)
+ try! instance.write {
+ let item = getLocalLibraryItemByLLId(libraryItem: localLibraryItemId)
+ instance.delete(item!)
}
}
}
diff --git a/ios/App/Shared/util/Store.swift b/ios/App/Shared/util/Store.swift
index 52fbd059..210664e1 100644
--- a/ios/App/Shared/util/Store.swift
+++ b/ios/App/Shared/util/Store.swift
@@ -9,7 +9,7 @@ import Foundation
import RealmSwift
class Store {
- @ThreadSafe private static var _serverConfig: ServerConnectionConfig?
+ private static var _serverConfig: ServerConnectionConfig?
public static var serverConfig: ServerConnectionConfig? {
get {
return _serverConfig
diff --git a/package-lock.json b/package-lock.json
index 13c38711..125a8b38 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32982,4 +32982,4 @@
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
}
}
-}
\ No newline at end of file
+}