From a35d697ebe9cf89675f50f0fc6120a2998012dd2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Mon, 12 Dec 2022 10:21:46 +0100 Subject: [PATCH] Cache fixes --- Model/Cache/BaseCacheModel.swift | 36 +++++++++++++++++++ Model/Cache/CacheModel.swift | 29 ++++++--------- Model/Cache/ChannelPlaylistsCacheModel.swift | 30 ++++++---------- Model/Cache/FeedCacheModel.swift | 22 +++++------- Model/Cache/PlaylistsCacheModel.swift | 30 ++++++---------- .../{ => Cache}/SubscribedChannelsModel.swift | 32 +++++++---------- Model/Cache/VideosCacheModel.swift | 14 +++----- Model/FeedModel.swift | 14 ++++---- Shared/Settings/AdvancedSettings.swift | 4 +-- Yattee.xcodeproj/project.pbxproj | 26 +++++++++----- 10 files changed, 119 insertions(+), 118 deletions(-) create mode 100644 Model/Cache/BaseCacheModel.swift rename Model/{ => Cache}/SubscribedChannelsModel.swift (78%) diff --git a/Model/Cache/BaseCacheModel.swift b/Model/Cache/BaseCacheModel.swift new file mode 100644 index 00000000..ac75875d --- /dev/null +++ b/Model/Cache/BaseCacheModel.swift @@ -0,0 +1,36 @@ +import Cache +import Foundation +import Logging +import SwiftyJSON + +struct BaseCacheModel { + static var shared = BaseCacheModel() + + static let jsonToDataTransformer: (JSON) -> Data = { try! $0.rawData() } + static let jsonFromDataTransformer: (Data) -> JSON = { try! JSON(data: $0) } + static let jsonTransformer = Transformer(toData: jsonToDataTransformer, fromData: jsonFromDataTransformer) + + var models: [CacheModel] { + [ + FeedCacheModel.shared, + VideosCacheModel.shared, + PlaylistsCacheModel.shared, + ChannelPlaylistsCacheModel.shared, + SubscribedChannelsModel.shared + ] + } + + func clear() { + models.forEach { $0.clear() } + } + + var totalSize: Int { + models.compactMap { $0.storage?.totalDiskStorageSize }.reduce(0, +) + } + + var totalSizeFormatted: String { + byteCountFormatter.string(fromByteCount: Int64(totalSize)) + } + + private var byteCountFormatter: ByteCountFormatter { .init() } +} diff --git a/Model/Cache/CacheModel.swift b/Model/Cache/CacheModel.swift index ed2f8c36..be9e63cb 100644 --- a/Model/Cache/CacheModel.swift +++ b/Model/Cache/CacheModel.swift @@ -1,29 +1,24 @@ import Cache import Foundation -import Logging import SwiftyJSON -struct CacheModel { - static var shared = CacheModel() +protocol CacheModel { + var storage: Storage? { get } - static let jsonToDataTransformer: (JSON) -> Data = { try! $0.rawData() } - static let jsonFromDataTransformer: (Data) -> JSON = { try! JSON(data: $0) } - static let jsonTransformer = Transformer(toData: jsonToDataTransformer, fromData: jsonFromDataTransformer) + func clear() +} +extension CacheModel { func clear() { - FeedCacheModel.shared.clear() - VideosCacheModel.shared.clear() - PlaylistsCacheModel.shared.clear() + try? storage?.removeAll() } - var totalSize: Int { - (FeedCacheModel.shared.storage.totalDiskStorageSize ?? 0) + - (VideosCacheModel.shared.storage.totalDiskStorageSize ?? 0) + - (PlaylistsCacheModel.shared.storage.totalDiskStorageSize ?? 0) - } + func getFormattedDate(_ date: Date?) -> String { + guard let date else { return "unknown" } - var totalSizeFormatted: String { - byteCountFormatter.string(fromByteCount: Int64(totalSize)) + let isSameDay = Calendar(identifier: .iso8601).isDate(date, inSameDayAs: Date()) + let formatter = isSameDay ? dateFormatterForTimeOnly : dateFormatter + return formatter.string(from: date) } var dateFormatter: DateFormatter { @@ -43,6 +38,4 @@ struct CacheModel { } var iso8601DateFormatter: ISO8601DateFormatter { .init() } - - private var byteCountFormatter: ByteCountFormatter { .init() } } diff --git a/Model/Cache/ChannelPlaylistsCacheModel.swift b/Model/Cache/ChannelPlaylistsCacheModel.swift index 1b2f0ac6..a62a4686 100644 --- a/Model/Cache/ChannelPlaylistsCacheModel.swift +++ b/Model/Cache/ChannelPlaylistsCacheModel.swift @@ -3,32 +3,32 @@ import Foundation import Logging import SwiftyJSON -struct ChannelPlaylistsCacheModel { +struct ChannelPlaylistsCacheModel: CacheModel { static let shared = ChannelPlaylistsCacheModel() let logger = Logger(label: "stream.yattee.cache.channel-playlists") static let diskConfig = DiskConfig(name: "channel-playlists") static let memoryConfig = MemoryConfig() - let storage = try! Storage( + var storage = try? Storage( diskConfig: Self.diskConfig, memoryConfig: Self.memoryConfig, - transformer: CacheModel.jsonTransformer + transformer: BaseCacheModel.jsonTransformer ) func storePlaylist(playlist: ChannelPlaylist) { - let date = CacheModel.shared.iso8601DateFormatter.string(from: Date()) + let date = iso8601DateFormatter.string(from: Date()) logger.info("STORE \(playlistCacheKey(playlist.id)) -- \(date)") let feedTimeObject: JSON = ["date": date] let playlistObject: JSON = ["playlist": playlist.json.object] - try? storage.setObject(feedTimeObject, forKey: playlistTimeCacheKey(playlist.id)) - try? storage.setObject(playlistObject, forKey: playlistCacheKey(playlist.id)) + try? storage?.setObject(feedTimeObject, forKey: playlistTimeCacheKey(playlist.id)) + try? storage?.setObject(playlistObject, forKey: playlistCacheKey(playlist.id)) } func retrievePlaylist(_ id: ChannelPlaylist.ID) -> ChannelPlaylist? { logger.info("RETRIEVE \(playlistCacheKey(id))") - if let json = try? storage.object(forKey: playlistCacheKey(id)).dictionaryValue["playlist"] { + if let json = try? storage?.object(forKey: playlistCacheKey(id)).dictionaryValue["playlist"] { return ChannelPlaylist.from(json) } @@ -36,9 +36,9 @@ struct ChannelPlaylistsCacheModel { } func getPlaylistsTime(_ id: ChannelPlaylist.ID) -> Date? { - if let json = try? storage.object(forKey: playlistTimeCacheKey(id)), + if let json = try? storage?.object(forKey: playlistTimeCacheKey(id)), let string = json.dictionaryValue["date"]?.string, - let date = CacheModel.shared.iso8601DateFormatter.date(from: string) + let date = iso8601DateFormatter.date(from: string) { return date } @@ -47,17 +47,7 @@ struct ChannelPlaylistsCacheModel { } func getFormattedPlaylistTime(_ id: ChannelPlaylist.ID) -> String { - if let time = getPlaylistsTime(id) { - let isSameDay = Calendar(identifier: .iso8601).isDate(time, inSameDayAs: Date()) - let formatter = isSameDay ? CacheModel.shared.dateFormatterForTimeOnly : CacheModel.shared.dateFormatter - return formatter.string(from: time) - } - - return "" - } - - func clear() { - try? storage.removeAll() + getFormattedDate(getPlaylistsTime(id)) } private func playlistCacheKey(_ playlist: ChannelPlaylist.ID) -> String { diff --git a/Model/Cache/FeedCacheModel.swift b/Model/Cache/FeedCacheModel.swift index cdda7ead..fe392b6d 100644 --- a/Model/Cache/FeedCacheModel.swift +++ b/Model/Cache/FeedCacheModel.swift @@ -3,7 +3,7 @@ import Foundation import Logging import SwiftyJSON -struct FeedCacheModel { +struct FeedCacheModel: CacheModel { static let shared = FeedCacheModel() static let limit = 30 let logger = Logger(label: "stream.yattee.cache.feed") @@ -11,25 +11,25 @@ struct FeedCacheModel { static let diskConfig = DiskConfig(name: "feed") static let memoryConfig = MemoryConfig() - let storage = try! Storage( + let storage = try? Storage( diskConfig: Self.diskConfig, memoryConfig: Self.memoryConfig, - transformer: CacheModel.jsonTransformer + transformer: BaseCacheModel.jsonTransformer ) func storeFeed(account: Account, videos: [Video]) { - let date = CacheModel.shared.iso8601DateFormatter.string(from: Date()) + let date = iso8601DateFormatter.string(from: Date()) logger.info("caching feed \(account.feedCacheKey) -- \(date)") let feedTimeObject: JSON = ["date": date] let videosObject: JSON = ["videos": videos.prefix(Self.limit).map { $0.json.object }] - try? storage.setObject(feedTimeObject, forKey: feedTimeCacheKey(account.feedCacheKey)) - try? storage.setObject(videosObject, forKey: account.feedCacheKey) + try? storage?.setObject(feedTimeObject, forKey: feedTimeCacheKey(account.feedCacheKey)) + try? storage?.setObject(videosObject, forKey: account.feedCacheKey) } func retrieveFeed(account: Account) -> [Video] { logger.info("retrieving cache for \(account.feedCacheKey)") - if let json = try? storage.object(forKey: account.feedCacheKey), + if let json = try? storage?.object(forKey: account.feedCacheKey), let videos = json.dictionaryValue["videos"] { return videos.arrayValue.map { Video.from($0) } @@ -39,9 +39,9 @@ struct FeedCacheModel { } func getFeedTime(account: Account) -> Date? { - if let json = try? storage.object(forKey: feedTimeCacheKey(account.feedCacheKey)), + if let json = try? storage?.object(forKey: feedTimeCacheKey(account.feedCacheKey)), let string = json.dictionaryValue["date"]?.string, - let date = CacheModel.shared.iso8601DateFormatter.date(from: string) + let date = iso8601DateFormatter.date(from: string) { return date } @@ -49,10 +49,6 @@ struct FeedCacheModel { return nil } - func clear() { - try? storage.removeAll() - } - private func feedTimeCacheKey(_ feedCacheKey: String) -> String { "\(feedCacheKey)-feedTime" } diff --git a/Model/Cache/PlaylistsCacheModel.swift b/Model/Cache/PlaylistsCacheModel.swift index 880e89cc..bd4b9ef4 100644 --- a/Model/Cache/PlaylistsCacheModel.swift +++ b/Model/Cache/PlaylistsCacheModel.swift @@ -3,7 +3,7 @@ import Foundation import Logging import SwiftyJSON -struct PlaylistsCacheModel { +struct PlaylistsCacheModel: CacheModel { static let shared = PlaylistsCacheModel() static let limit = 30 let logger = Logger(label: "stream.yattee.cache.playlists") @@ -11,25 +11,25 @@ struct PlaylistsCacheModel { static let diskConfig = DiskConfig(name: "playlists") static let memoryConfig = MemoryConfig() - let storage = try! Storage( + let storage = try? Storage( diskConfig: Self.diskConfig, memoryConfig: Self.memoryConfig, - transformer: CacheModel.jsonTransformer + transformer: BaseCacheModel.jsonTransformer ) func storePlaylist(account: Account, playlists: [Playlist]) { - let date = CacheModel.shared.iso8601DateFormatter.string(from: Date()) + let date = iso8601DateFormatter.string(from: Date()) logger.info("caching \(playlistCacheKey(account)) -- \(date)") let feedTimeObject: JSON = ["date": date] let playlistsObject: JSON = ["playlists": playlists.map { $0.json.object }] - try? storage.setObject(feedTimeObject, forKey: playlistTimeCacheKey(account)) - try? storage.setObject(playlistsObject, forKey: playlistCacheKey(account)) + try? storage?.setObject(feedTimeObject, forKey: playlistTimeCacheKey(account)) + try? storage?.setObject(playlistsObject, forKey: playlistCacheKey(account)) } func retrievePlaylists(account: Account) -> [Playlist] { logger.info("retrieving cache for \(playlistCacheKey(account))") - if let json = try? storage.object(forKey: playlistCacheKey(account)), + if let json = try? storage?.object(forKey: playlistCacheKey(account)), let playlists = json.dictionaryValue["playlists"] { return playlists.arrayValue.map { Playlist.from($0) } @@ -39,9 +39,9 @@ struct PlaylistsCacheModel { } func getPlaylistsTime(account: Account) -> Date? { - if let json = try? storage.object(forKey: playlistTimeCacheKey(account)), + if let json = try? storage?.object(forKey: playlistTimeCacheKey(account)), let string = json.dictionaryValue["date"]?.string, - let date = CacheModel.shared.iso8601DateFormatter.date(from: string) + let date = iso8601DateFormatter.date(from: string) { return date } @@ -50,17 +50,7 @@ struct PlaylistsCacheModel { } func getFormattedPlaylistTime(account: Account) -> String { - if let time = getPlaylistsTime(account: account) { - let isSameDay = Calendar(identifier: .iso8601).isDate(time, inSameDayAs: Date()) - let formatter = isSameDay ? CacheModel.shared.dateFormatterForTimeOnly : CacheModel.shared.dateFormatter - return formatter.string(from: time) - } - - return "" - } - - func clear() { - try? storage.removeAll() + getFormattedDate(getPlaylistsTime(account: account)) } private func playlistCacheKey(_ account: Account) -> String { diff --git a/Model/SubscribedChannelsModel.swift b/Model/Cache/SubscribedChannelsModel.swift similarity index 78% rename from Model/SubscribedChannelsModel.swift rename to Model/Cache/SubscribedChannelsModel.swift index a065f71d..1153c5e2 100644 --- a/Model/SubscribedChannelsModel.swift +++ b/Model/Cache/SubscribedChannelsModel.swift @@ -5,17 +5,17 @@ import Siesta import SwiftUI import SwiftyJSON -final class SubscribedChannelsModel: ObservableObject { +final class SubscribedChannelsModel: ObservableObject, CacheModel { static var shared = SubscribedChannelsModel() let logger = Logger(label: "stream.yattee.cache.channels") static let diskConfig = DiskConfig(name: "channels") static let memoryConfig = MemoryConfig() - let storage = try! Storage( + let storage = try? Storage( diskConfig: SubscribedChannelsModel.diskConfig, memoryConfig: SubscribedChannelsModel.memoryConfig, - transformer: CacheModel.jsonTransformer + transformer: BaseCacheModel.jsonTransformer ) @Published var isLoading = false @@ -89,20 +89,20 @@ final class SubscribedChannelsModel: ObservableObject { } func storeChannels(account: Account, channels: [Channel]) { - let date = CacheModel.shared.iso8601DateFormatter.string(from: Date()) + let date = iso8601DateFormatter.string(from: Date()) logger.info("caching channels \(channelsDateCacheKey(account)) -- \(date)") let dateObject: JSON = ["date": date] let channelsObject: JSON = ["channels": channels.map(\.json).map(\.object)] - try? storage.setObject(dateObject, forKey: channelsDateCacheKey(account)) - try? storage.setObject(channelsObject, forKey: channelsCacheKey(account)) + try? storage?.setObject(dateObject, forKey: channelsDateCacheKey(account)) + try? storage?.setObject(channelsObject, forKey: channelsCacheKey(account)) } func getChannels(account: Account) -> [Channel] { logger.info("getting channels \(channelsDateCacheKey(account))") - if let json = try? storage.object(forKey: channelsCacheKey(account)), + if let json = try? storage?.object(forKey: channelsCacheKey(account)), let channels = json.dictionaryValue["channels"] { return channels.arrayValue.map { Channel.from($0) } @@ -125,10 +125,10 @@ final class SubscribedChannelsModel: ObservableObject { "channels-\(account.id)-date" } - func getFeedTime(account: Account) -> Date? { - if let json = try? storage.object(forKey: channelsDateCacheKey(account)), + func getChannelsTime(account: Account) -> Date? { + if let json = try? storage?.object(forKey: channelsDateCacheKey(account)), let string = json.dictionaryValue["date"]?.string, - let date = CacheModel.shared.iso8601DateFormatter.date(from: string) + let date = iso8601DateFormatter.date(from: string) { return date } @@ -136,21 +136,15 @@ final class SubscribedChannelsModel: ObservableObject { return nil } - var feedTime: Date? { + var channelsTime: Date? { if let account = accounts.current { - return getFeedTime(account: account) + return getChannelsTime(account: account) } return nil } var formattedCacheTime: String { - if let feedTime { - let isSameDay = Calendar(identifier: .iso8601).isDate(feedTime, inSameDayAs: Date()) - let formatter = isSameDay ? CacheModel.shared.dateFormatterForTimeOnly : CacheModel.shared.dateFormatter - return formatter.string(from: feedTime) - } - - return "" + getFormattedDate(channelsTime) } } diff --git a/Model/Cache/VideosCacheModel.swift b/Model/Cache/VideosCacheModel.swift index b950d324..6ec80eea 100644 --- a/Model/Cache/VideosCacheModel.swift +++ b/Model/Cache/VideosCacheModel.swift @@ -3,35 +3,31 @@ import Foundation import Logging import SwiftyJSON -struct VideosCacheModel { +struct VideosCacheModel: CacheModel { static let shared = VideosCacheModel() let logger = Logger(label: "stream.yattee.cache.videos") static let diskConfig = DiskConfig(name: "videos") static let memoryConfig = MemoryConfig() - let storage = try! Storage( + let storage = try? Storage( diskConfig: Self.diskConfig, memoryConfig: Self.memoryConfig, - transformer: CacheModel.jsonTransformer + transformer: BaseCacheModel.jsonTransformer ) func storeVideo(_ video: Video) { logger.info("caching \(video.cacheKey)") - try? storage.setObject(video.json, forKey: video.cacheKey) + try? storage?.setObject(video.json, forKey: video.cacheKey) } func retrieveVideo(_ cacheKey: String) -> Video? { logger.info("retrieving cache for \(cacheKey)") - if let json = try? storage.object(forKey: cacheKey) { + if let json = try? storage?.object(forKey: cacheKey) { return Video.from(json) } return nil } - - func clear() { - try? storage.removeAll() - } } diff --git a/Model/FeedModel.swift b/Model/FeedModel.swift index de2e948d..ad28fd1e 100644 --- a/Model/FeedModel.swift +++ b/Model/FeedModel.swift @@ -1,7 +1,9 @@ +import Cache import Foundation import Siesta +import SwiftyJSON -final class FeedModel: ObservableObject { +final class FeedModel: ObservableObject, CacheModel { static let shared = FeedModel() @Published var isLoading = false @@ -10,6 +12,8 @@ final class FeedModel: ObservableObject { private var accounts = AccountsModel.shared + var storage: Storage? + var feed: Resource? { accounts.api.feed(page) } @@ -104,13 +108,7 @@ final class FeedModel: ObservableObject { } var formattedFeedTime: String { - if let feedTime { - let isSameDay = Calendar(identifier: .iso8601).isDate(feedTime, inSameDayAs: Date()) - let formatter = isSameDay ? CacheModel.shared.dateFormatterForTimeOnly : CacheModel.shared.dateFormatter - return formatter.string(from: feedTime) - } - - return "" + getFormattedDate(feedTime) } private func loadCachedFeed() { diff --git a/Shared/Settings/AdvancedSettings.swift b/Shared/Settings/AdvancedSettings.swift index 30931c15..7d27c9d4 100644 --- a/Shared/Settings/AdvancedSettings.swift +++ b/Shared/Settings/AdvancedSettings.swift @@ -137,7 +137,7 @@ struct AdvancedSettings: View { title: Text( "Are you sure you want to clear cache?" ), - primaryButton: .destructive(Text("Clear"), action: CacheModel.shared.clear), + primaryButton: .destructive(Text("Clear"), action: BaseCacheModel.shared.clear), secondaryButton: .cancel() ) ) @@ -148,7 +148,7 @@ struct AdvancedSettings: View { } var cacheSize: some View { - Text(String(format: "Total size: %@", CacheModel.shared.totalSizeFormatted)) + Text(String(format: "Total size: %@", BaseCacheModel.shared.totalSizeFormatted)) .foregroundColor(.secondary) } } diff --git a/Yattee.xcodeproj/project.pbxproj b/Yattee.xcodeproj/project.pbxproj index ad6bd26c..c9c934dd 100644 --- a/Yattee.xcodeproj/project.pbxproj +++ b/Yattee.xcodeproj/project.pbxproj @@ -662,6 +662,9 @@ 379F141F289ECE7F00DE48B5 /* QualitySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379F141E289ECE7F00DE48B5 /* QualitySettings.swift */; }; 379F1420289ECE7F00DE48B5 /* QualitySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379F141E289ECE7F00DE48B5 /* QualitySettings.swift */; }; 379F1421289ECE7F00DE48B5 /* QualitySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379F141E289ECE7F00DE48B5 /* QualitySettings.swift */; }; + 37A2B346294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; }; + 37A2B347294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; }; + 37A2B348294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; }; 37A5DBC4285DFF5400CA4DD1 /* SwiftUIPager in Frameworks */ = {isa = PBXBuildFile; productRef = 37A5DBC3285DFF5400CA4DD1 /* SwiftUIPager */; }; 37A5DBC6285E06B100CA4DD1 /* SwiftUIPager in Frameworks */ = {isa = PBXBuildFile; productRef = 37A5DBC5285E06B100CA4DD1 /* SwiftUIPager */; }; 37A5DBC8285E371400CA4DD1 /* ControlBackgroundModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */; }; @@ -933,9 +936,9 @@ 37F5E8B6291BE9D0006C15F5 /* URLBookmarkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B5291BE9D0006C15F5 /* URLBookmarkModel.swift */; }; 37F5E8B7291BE9D0006C15F5 /* URLBookmarkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B5291BE9D0006C15F5 /* URLBookmarkModel.swift */; }; 37F5E8B8291BE9D0006C15F5 /* URLBookmarkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B5291BE9D0006C15F5 /* URLBookmarkModel.swift */; }; - 37F5E8BA291BEF69006C15F5 /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B9291BEF69006C15F5 /* CacheModel.swift */; }; - 37F5E8BB291BEF69006C15F5 /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B9291BEF69006C15F5 /* CacheModel.swift */; }; - 37F5E8BC291BEF69006C15F5 /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B9291BEF69006C15F5 /* CacheModel.swift */; }; + 37F5E8BA291BEF69006C15F5 /* BaseCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B9291BEF69006C15F5 /* BaseCacheModel.swift */; }; + 37F5E8BB291BEF69006C15F5 /* BaseCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B9291BEF69006C15F5 /* BaseCacheModel.swift */; }; + 37F5E8BC291BEF69006C15F5 /* BaseCacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F5E8B9291BEF69006C15F5 /* BaseCacheModel.swift */; }; 37F64FE426FE70A60081B69E /* RedrawOnModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F64FE326FE70A60081B69E /* RedrawOnModifier.swift */; }; 37F64FE526FE70A60081B69E /* RedrawOnModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F64FE326FE70A60081B69E /* RedrawOnModifier.swift */; }; 37F64FE626FE70A60081B69E /* RedrawOnModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F64FE326FE70A60081B69E /* RedrawOnModifier.swift */; }; @@ -1309,6 +1312,7 @@ 379B0252287A1CDF001015B5 /* OrientationTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrientationTracker.swift; sourceTree = ""; }; 379DC3D028BA4EB400B09677 /* Seek.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Seek.swift; sourceTree = ""; }; 379F141E289ECE7F00DE48B5 /* QualitySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QualitySettings.swift; sourceTree = ""; }; + 37A2B345294723850050933E /* CacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheModel.swift; sourceTree = ""; }; 37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlBackgroundModifier.swift; sourceTree = ""; }; 37A9965926D6F8CA006E3224 /* HorizontalCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalCells.swift; sourceTree = ""; }; 37A9965D26D6F9B9006E3224 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; @@ -1430,7 +1434,7 @@ 37F4AD2528613B81004D0F66 /* Color+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Debug.swift"; sourceTree = ""; }; 37F4AE7126828F0900BD60EA /* VerticalCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalCells.swift; sourceTree = ""; }; 37F5E8B5291BE9D0006C15F5 /* URLBookmarkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLBookmarkModel.swift; sourceTree = ""; }; - 37F5E8B9291BEF69006C15F5 /* CacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheModel.swift; sourceTree = ""; }; + 37F5E8B9291BEF69006C15F5 /* BaseCacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCacheModel.swift; sourceTree = ""; }; 37F64FE326FE70A60081B69E /* RedrawOnModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedrawOnModifier.swift; sourceTree = ""; }; 37F7AB4C28A9361F00FB46B5 /* UIDevice+Cellular.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIDevice+Cellular.swift"; sourceTree = ""; }; 37F7AB4E28A94E0600FB46B5 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; @@ -2042,11 +2046,13 @@ 377F9F79294403DC0043F856 /* Cache */ = { isa = PBXGroup; children = ( + 37F5E8B9291BEF69006C15F5 /* BaseCacheModel.swift */, 3738535329451DC800D2D0CB /* BookmarksCacheModel.swift */, - 37F5E8B9291BEF69006C15F5 /* CacheModel.swift */, + 37A2B345294723850050933E /* CacheModel.swift */, 377692552946476F0055EC18 /* ChannelPlaylistsCacheModel.swift */, 377F9F7E2944175F0043F856 /* FeedCacheModel.swift */, 3776925129463C310055EC18 /* PlaylistsCacheModel.swift */, + 37E64DD026D597EB00C71877 /* SubscribedChannelsModel.swift */, 377F9F7A294403F20043F856 /* VideosCacheModel.swift */, ); path = Cache; @@ -2315,7 +2321,6 @@ 37CEE4BC2677B670005A1EFE /* SingleAssetStream.swift */, 3797758A2689345500DD52A8 /* Store.swift */, 37CEE4C02677B697005A1EFE /* Stream.swift */, - 37E64DD026D597EB00C71877 /* SubscribedChannelsModel.swift */, 373CFADA269663F1003CB2C6 /* Thumbnail.swift */, 37C0698127260B2100F7F6CB /* ThumbnailsModel.swift */, 3705B181267B4E4900704544 /* TrendingCategory.swift */, @@ -3151,7 +3156,7 @@ 375DFB5826F9DA010013F468 /* InstancesModel.swift in Sources */, 3751BA8327E6914F007B1A60 /* ReturnYouTubeDislikeAPI.swift in Sources */, 373031F528383A89000CFD59 /* PiPDelegate.swift in Sources */, - 37F5E8BA291BEF69006C15F5 /* CacheModel.swift in Sources */, + 37F5E8BA291BEF69006C15F5 /* BaseCacheModel.swift in Sources */, 37DD9DC62785D63A00539416 /* UIResponder+Extensions.swift in Sources */, 370015A928BBAE7F000149FD /* ProgressBar.swift in Sources */, 37C3A24927235FAA0087A57A /* ChannelPlaylistCell.swift in Sources */, @@ -3196,6 +3201,7 @@ 375EC972289F2ABF00751258 /* MultiselectRow.swift in Sources */, 37001563271B1F250049C794 /* AccountsModel.swift in Sources */, 3795593627B08538007FF8F4 /* StreamControl.swift in Sources */, + 37A2B346294723850050933E /* CacheModel.swift in Sources */, 37CC3F50270D010D00608308 /* VideoBanner.swift in Sources */, 378E50FB26FE8B9F00F49626 /* Instance.swift in Sources */, 37E70923271CD43000D34DDE /* WelcomeScreen.swift in Sources */, @@ -3316,6 +3322,7 @@ 379DC3D228BA4EB400B09677 /* Seek.swift in Sources */, 376BE50727347B57009AD608 /* SettingsHeader.swift in Sources */, 378AE93C274EDFB2006A4EE1 /* Backport.swift in Sources */, + 37A2B347294723850050933E /* CacheModel.swift in Sources */, 37152EEB26EFEB95004FB96D /* LazyView.swift in Sources */, 37F4AD2028612DFD004D0F66 /* Buffering.swift in Sources */, 375EC973289F2ABF00751258 /* MultiselectRow.swift in Sources */, @@ -3332,7 +3339,7 @@ 37B044B826F7AB9000E1419D /* SettingsView.swift in Sources */, 377692572946476F0055EC18 /* ChannelPlaylistsCacheModel.swift in Sources */, 374924E1292126A00017D862 /* VideoDetailsToolbar.swift in Sources */, - 37F5E8BB291BEF69006C15F5 /* CacheModel.swift in Sources */, + 37F5E8BB291BEF69006C15F5 /* BaseCacheModel.swift in Sources */, 3765788A2685471400D4EA09 /* Playlist.swift in Sources */, 37030FFC27B0398000ECDDAA /* MPVClient.swift in Sources */, 3751B4B327836902000B7DF4 /* SearchPage.swift in Sources */, @@ -3541,7 +3548,7 @@ 37648B69286CF5F1003D330B /* TVControls.swift in Sources */, 374C053D2724614F009BDDBE /* PlayerTVMenu.swift in Sources */, 37BE0BD426A1D47D0092E2DB /* AppleAVPlayerView.swift in Sources */, - 37F5E8BC291BEF69006C15F5 /* CacheModel.swift in Sources */, + 37F5E8BC291BEF69006C15F5 /* BaseCacheModel.swift in Sources */, 37977585268922F600DD52A8 /* InvidiousAPI.swift in Sources */, 3769537928A877C4005D87C3 /* StreamControl.swift in Sources */, 3700155D271B0D4D0049C794 /* PipedAPI.swift in Sources */, @@ -3571,6 +3578,7 @@ 378FFBC628660172009E3FBE /* URLParser.swift in Sources */, 37141671267A8ACC006CA35D /* TrendingView.swift in Sources */, 3732C9FD28C012E600E7DCAF /* SafeArea.swift in Sources */, + 37A2B348294723850050933E /* CacheModel.swift in Sources */, 37C3A24727235DA70087A57A /* ChannelPlaylist.swift in Sources */, 3788AC2926F6840700F6BAA9 /* FavoriteItemView.swift in Sources */, 37319F0727103F94004ECCD0 /* PlayerQueue.swift in Sources */,