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