VIMediaCache icon indicating copy to clipboard operation
VIMediaCache copied to clipboard

Add basic support to control cache

Open satishVekariya opened this issue 6 years ago • 2 comments

I think cache control is primary requirement. Plz add this feature, thanx

satishVekariya avatar Jun 06 '18 11:06 satishVekariya

I have basic idea to control cache by just extending VICacheManager like below

extension VICacheManager {
    
    static var maxCacheAge: TimeInterval = 60 * 60 * 24 * 7 // 1 week
    
    /// The maximum size of the cache, in bytes.
    static var maxCacheSize: UInt = 1000000 * 1000
    
    static private let fileManager = FileManager.default
    static fileprivate let ioQueue = DispatchQueue(label: "com.vgplayer.ioQueue")
    
    /// Delete old file if cache size is exceede to maxCacheSize
    static func cleanOldFilesIfNeeded(completion handler: (()->())? = nil) {
        var error:NSError? = nil
        let currentCacheSize = calculateCachedSizeWithError(&error)
        
        guard error == nil, currentCacheSize > maxCacheSize else {
            return
        }
        
        ioQueue.sync {
            var (urlsToDelete, diskCacheSize, cachedFiels) = getOldFiles()
            
            //Delete old file
            for fileUrl in urlsToDelete {
                cleanCache(for: fileUrl, error: nil)
            }
            
            //Check remaining cache size
            if maxCacheSize > 0 && diskCacheSize > maxCacheSize {
                let targetSize = maxCacheSize/2
                
                let sortedfiles = cachedFiels.keysSortedByValue({ (v1, v2) -> Bool in
                    if let date1 = v1.contentAccessDate, let date2 = v2.contentAccessDate {
                        return date1.compare(date2) == .orderedAscending
                    }
                    return true
                })
                
                for fileUrl in sortedfiles {
                    diskCacheSize -= UInt(cachedFiels[fileUrl]?.totalFileAllocatedSize ?? 0)
                    cleanCache(for: fileUrl, error: nil)
                    
                    urlsToDelete.append(fileUrl)
                    if diskCacheSize < targetSize {
                        break
                    }
                }
            }
            
            DispatchQueue.main.async {
                handler?()
            }
        }
    }
    
    static func getOldFiles() -> (urlsToDelete: [URL], diskCacheSize: UInt, cachedFiels:[URL: URLResourceValues]) {
        var urlsToDelete = [URL]()
        var diskCacheSize: UInt = 0
        var cachedFiles = [URL: URLResourceValues]()
        
        guard let expiredDate = maxCacheAge < 0 ? nil : Date(timeIntervalSinceNow: -maxCacheAge) else { return (urlsToDelete, diskCacheSize, cachedFiles) }
        
        let fullPath = (cacheDirectory() as NSString).expandingTildeInPath
        let url = URL(fileURLWithPath: fullPath)
        let configurationExtention = "mt_cfg" //More detail -> VICacheConfiguration.m
        let resourceKeys:[URLResourceKey] = [.contentAccessDateKey, .totalFileAllocatedSizeKey]
        
        if let directoryEnumerator = fileManager.enumerator(at: url, includingPropertiesForKeys: resourceKeys, options: .skipsHiddenFiles, errorHandler: nil) {
            for (_, value) in directoryEnumerator.enumerated() {
                if let fileURL = value as? URL, fileURL.pathExtension != configurationExtention, let resourceValues = try? fileURL.resourceValues(forKeys: [.contentAccessDateKey, .totalFileAllocatedSizeKey]) {
                    
                    if let lastAccessDate = resourceValues.contentAccessDate, (lastAccessDate as NSDate).laterDate(expiredDate) == expiredDate {
                        urlsToDelete.append(fileURL)
                        continue
                    } else {
                        cachedFiles[fileURL] = resourceValues
                    }
                    
                    if let size = resourceValues.totalFileAllocatedSize {
                        diskCacheSize += UInt(size)
                    }
                }
            }
        }
        
        return (urlsToDelete, diskCacheSize, cachedFiles)
    }
    
}

fileprivate extension Dictionary {
    func keysSortedByValue(_ isOrderedBefore: (Value, Value) -> Bool) -> [Key] {
        return Array(self).sorted{ isOrderedBefore($0.1, $1.1) }.map{ $0.0 }
    }
}

satishVekariya avatar Jun 06 '18 11:06 satishVekariya

It doesn't seem like this package is actively maintained. Is there a more active fork somewhere?

gilbertl avatar Mar 31 '21 07:03 gilbertl