From 0bc832b00254b03e6fcbcca511fad46155524760 Mon Sep 17 00:00:00 2001 From: Vein Date: Tue, 19 Sep 2017 16:37:35 +0800 Subject: [PATCH] clean code --- .../MediaCache/VGPlayerCacheManager.swift | 14 +- .../MediaCache/VGPlayerCacheMedia.swift | 16 +- .../VGPlayerCacheMediaConfiguration.swift | 42 +-- .../MediaCache/VGPlayerCacheMediaWorker.swift | 58 ++-- .../MediaCache/VGPlayerCacheSession.swift | 2 +- .../VGPlayerDownloadActionWorker.swift | 68 ++-- .../VGPlayerDownloadURLSessionManager.swift | 26 +- .../MediaCache/VGPlayerDownloader.swift | 84 ++--- .../MediaCache/VGPlayerResourceLoader.swift | 20 +- .../VGPlayerResourceLoaderManager.swift | 12 +- .../VGPlayerResourceLoadingRequest.swift | 36 +-- VGPlayer/Classes/VGPlayer.swift | 139 ++++---- VGPlayer/Classes/VGPlayerSlider.swift | 20 +- VGPlayer/Classes/VGPlayerView.swift | 296 +++++++++--------- VGPlayer/Classes/VGSubtitles.swift | 8 +- .../UserInterfaceState.xcuserstate | Bin 17108 -> 39242 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 50 +++ 17 files changed, 472 insertions(+), 419 deletions(-) diff --git a/VGPlayer/Classes/MediaCache/VGPlayerCacheManager.swift b/VGPlayer/Classes/MediaCache/VGPlayerCacheManager.swift index d154265..d0a6df1 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerCacheManager.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerCacheManager.swift @@ -31,7 +31,7 @@ open class VGPlayerCacheManager: NSObject { public override init() { super.init() - self.ioQueue.sync { self.fileManager = FileManager() } + ioQueue.sync { fileManager = FileManager() } } static public func cacheDirectory() -> String { @@ -65,22 +65,22 @@ open class VGPlayerCacheManager: NSObject { } open func cleanAllCache() { - self.ioQueue.sync { + ioQueue.sync { do { let cacheDirectory = VGPlayerCacheManager.cacheDirectory() - try self.fileManager.removeItem(atPath: cacheDirectory) + try fileManager.removeItem(atPath: cacheDirectory) } catch { } } } open func cleanOldFiles(completion handler: (()->())? = nil) { - self.ioQueue.sync { + ioQueue.sync { let cacheDirectory = VGPlayerCacheManager.cacheDirectory() var (URLsToDelete, diskCacheSize, cachedFiles) = self.cachedFiles(atPath: cacheDirectory, onlyForCacheSize: false) for fileURL in URLsToDelete { do { - try self.fileManager.removeItem(at: fileURL) + try fileManager.removeItem(at: fileURL) } catch _ { } } @@ -104,7 +104,7 @@ open class VGPlayerCacheManager: NSObject { diskCacheSize -= cacheSize do { - try self.fileManager.removeItem(at: fileURL) + try fileManager.removeItem(at: fileURL) } catch { } URLsToDelete.append(fileURL) @@ -139,7 +139,7 @@ open class VGPlayerCacheManager: NSObject { do { let url = URL(fileURLWithPath: fullPath) - if let directoryEnumerator = self.fileManager.enumerator(at:url, includingPropertiesForKeys: Array(resourceKeys), options: [.skipsHiddenFiles], errorHandler: nil) { + if let directoryEnumerator = fileManager.enumerator(at:url, includingPropertiesForKeys: Array(resourceKeys), options: [.skipsHiddenFiles], errorHandler: nil) { for (_ , value) in directoryEnumerator.enumerated() { do { if let fileURL = value as? URL{ diff --git a/VGPlayer/Classes/MediaCache/VGPlayerCacheMedia.swift b/VGPlayer/Classes/MediaCache/VGPlayerCacheMedia.swift index 3e8ea5e..1b88c7e 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerCacheMedia.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerCacheMedia.swift @@ -23,21 +23,21 @@ open class VGPlayerCacheMedia: NSObject, NSCoding { } public func encode(with aCoder: NSCoder) { - aCoder.encode(self.contentType, forKey: "contentType") - aCoder.encode(self.isByteRangeAccessSupported, forKey: "isByteRangeAccessSupported") - aCoder.encode(self.contentLength, forKey: "contentLength") - aCoder.encode(self.downloadedLength, forKey: "downloadedLength") + aCoder.encode(contentType, forKey: "contentType") + aCoder.encode(isByteRangeAccessSupported, forKey: "isByteRangeAccessSupported") + aCoder.encode(contentLength, forKey: "contentLength") + aCoder.encode(downloadedLength, forKey: "downloadedLength") } public required init(coder aDecoder: NSCoder) { super.init() - self.contentType = aDecoder.decodeObject(forKey: "contentType") as? String - self.isByteRangeAccessSupported = aDecoder.decodeBool(forKey: "isByteRangeAccessSupported") - self.contentLength = aDecoder.decodeInt64(forKey: "contentLength") + contentType = aDecoder.decodeObject(forKey: "contentType") as? String + isByteRangeAccessSupported = aDecoder.decodeBool(forKey: "isByteRangeAccessSupported") + contentLength = aDecoder.decodeInt64(forKey: "contentLength") if let downloadedLength = aDecoder.decodeObject(forKey: "downloadedLength") as? UInt64 { self.downloadedLength = downloadedLength } else { - self.downloadedLength = 0 + downloadedLength = 0 } } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerCacheMediaConfiguration.swift b/VGPlayer/Classes/MediaCache/VGPlayerCacheMediaConfiguration.swift index d4508d7..8f8c9c2 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerCacheMediaConfiguration.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerCacheMediaConfiguration.swift @@ -22,8 +22,8 @@ open class VGPlayerCacheMediaConfiguration:NSObject, NSCoding, NSCopying { public fileprivate(set) var progress: Double = 0.0 { didSet { - if let contentLength = self.cacheMedia?.contentLength, - let downloadedBytes = self.downloadedBytes { + if let contentLength = cacheMedia?.contentLength, + let downloadedBytes = downloadedBytes { progress = Double(downloadedBytes / contentLength) } } @@ -33,12 +33,12 @@ open class VGPlayerCacheMediaConfiguration:NSObject, NSCoding, NSCopying { didSet { var bytes = 0 - self.cacheSegmentQueue.sync { - for range in self.cacheSegments { + cacheSegmentQueue.sync { + for range in cacheSegments { bytes += range.rangeValue.length } } - self.downloadedBytes = Int64(bytes) + downloadedBytes = Int64(bytes) } } @@ -46,8 +46,8 @@ open class VGPlayerCacheMediaConfiguration:NSObject, NSCoding, NSCopying { didSet { var bytes: UInt64 = 0 var time = 0.0 - if self.downloadInfo.count > 0 { - self.cacheDownloadInfoQueue.sync { + if downloadInfo.count > 0 { + cacheDownloadInfoQueue.sync { for a in downloadInfo { if let arr = a as? Array{ bytes += arr.first as! UInt64 @@ -58,7 +58,7 @@ open class VGPlayerCacheMediaConfiguration:NSObject, NSCoding, NSCopying { } } } - self.downloadSpeed = Double(bytes) / 1024.0 / time + downloadSpeed = Double(bytes) / 1024.0 / time } } @@ -79,21 +79,21 @@ open class VGPlayerCacheMediaConfiguration:NSObject, NSCoding, NSCopying { } public func encode(with aCoder: NSCoder) { - aCoder.encode(self.fileName, forKey: "fileName") - aCoder.encode(self.cacheSegments, forKey: "cacheSegments") - aCoder.encode(self.downloadInfo, forKey: "downloadInfo") - aCoder.encode(self.cacheMedia, forKey: "cacheMedia") - aCoder.encode(self.url, forKey: "url") + aCoder.encode(fileName, forKey: "fileName") + aCoder.encode(cacheSegments, forKey: "cacheSegments") + aCoder.encode(downloadInfo, forKey: "downloadInfo") + aCoder.encode(cacheMedia, forKey: "cacheMedia") + aCoder.encode(url, forKey: "url") } public func copy(with zone: NSZone? = nil) -> Any { let confi = VGPlayerCacheMediaConfiguration() - confi.filePath = self.filePath - confi.fileName = self.fileName - confi.cacheSegments = self.cacheSegments - confi.cacheMedia = self.cacheMedia - confi.url = self.url - confi.fileName = self.fileName - confi.downloadInfo = self.downloadInfo + confi.filePath = filePath + confi.fileName = fileName + confi.cacheSegments = cacheSegments + confi.cacheMedia = cacheMedia + confi.url = url + confi.fileName = fileName + confi.downloadInfo = downloadInfo return confi } @@ -125,7 +125,7 @@ open class VGPlayerCacheMediaConfiguration:NSObject, NSCoding, NSCopying { extension VGPlayerCacheMediaConfiguration { open func save() { self.cacheSegmentQueue.sync { - let _ = NSKeyedArchiver.archiveRootObject(self, toFile: self.filePath!) + let _ = NSKeyedArchiver.archiveRootObject(self, toFile: filePath!) } } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerCacheMediaWorker.swift b/VGPlayer/Classes/MediaCache/VGPlayerCacheMediaWorker.swift index 4346a04..7c51b94 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerCacheMediaWorker.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerCacheMediaWorker.swift @@ -32,7 +32,7 @@ open class VGPlayerCacheMediaWorker: NSObject { public init(url: URL) { let path = VGPlayerCacheManager.cacheFilePath(for: url) - self.filePath = path + filePath = path let fileManager = FileManager.default let cacheFolder = (path as NSString).deletingLastPathComponent var err: Error? @@ -52,7 +52,7 @@ open class VGPlayerCacheMediaWorker: NSObject { let fileURL = URL(fileURLWithPath: path) do { - try self.readFileHandle = FileHandle(forReadingFrom: fileURL) + try readFileHandle = FileHandle(forReadingFrom: fileURL) } catch { err = error } @@ -63,26 +63,26 @@ open class VGPlayerCacheMediaWorker: NSObject { } do { - try self.writeFileHandle = FileHandle(forWritingTo: fileURL) - self.cacheConfiguration = VGPlayerCacheMediaConfiguration.configuration(filePath: path) - self.cacheConfiguration?.url = url + try writeFileHandle = FileHandle(forWritingTo: fileURL) + cacheConfiguration = VGPlayerCacheMediaConfiguration.configuration(filePath: path) + cacheConfiguration?.url = url } catch { err = error } } } - self.setupError = err; + setupError = err; super.init() } open func cache(_ data: Data, forRange range: NSRange, closure: (Bool) -> Void) { - self.writeFileQueue.sync { + writeFileQueue.sync { - if let _ = self.writeFileHandle?.seek(toFileOffset: UInt64(range.location)), - let _ = self.writeFileHandle?.write(data) { - self.writeBytes += Double(data.count) - self.cacheConfiguration?.addCache(range) + if let _ = writeFileHandle?.seek(toFileOffset: UInt64(range.location)), + let _ = writeFileHandle?.write(data) { + writeBytes += Double(data.count) + cacheConfiguration?.addCache(range) closure(true) } else { closure(false) @@ -91,8 +91,8 @@ open class VGPlayerCacheMediaWorker: NSObject { } open func cache(forRange range: NSRange) -> Data? { - self.readFileHandle?.seek(toFileOffset: UInt64(range.location)) - let data = self.readFileHandle?.readData(ofLength: range.length) + readFileHandle?.seek(toFileOffset: UInt64(range.location)) + let data = readFileHandle?.readData(ofLength: range.length) return data } @@ -104,7 +104,7 @@ open class VGPlayerCacheMediaWorker: NSObject { let endOffset = range.location + range.length - if let cachedSegments = self.cacheConfiguration?.cacheSegments { + if let cachedSegments = cacheConfiguration?.cacheSegments { for (_, value) in cachedSegments.enumerated() { let segmentRange = value.rangeValue @@ -167,9 +167,9 @@ open class VGPlayerCacheMediaWorker: NSObject { } open func set(cacheMedia: VGPlayerCacheMedia) -> Bool { - self.cacheConfiguration?.cacheMedia = cacheMedia - if let _ = self.writeFileHandle?.truncateFile(atOffset: UInt64(cacheMedia.contentLength)), - let _ = self.writeFileHandle?.synchronizeFile(){ + cacheConfiguration?.cacheMedia = cacheMedia + if let _ = writeFileHandle?.truncateFile(atOffset: UInt64(cacheMedia.contentLength)), + let _ = writeFileHandle?.synchronizeFile(){ return true } else { return false @@ -177,33 +177,33 @@ open class VGPlayerCacheMediaWorker: NSObject { } open func save() { - self.writeFileQueue.sync { - self.writeFileHandle?.synchronizeFile() - self.cacheConfiguration?.save() + writeFileQueue.sync { + writeFileHandle?.synchronizeFile() + cacheConfiguration?.save() } } open func startWritting() { - if !self.isWritting { + if !isWritting { NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(_:)), name: .UIApplicationDidEnterBackground, object: nil) } - self.isWritting = true - self.starWriteDate = NSDate() - self.writeBytes = 0.0 + isWritting = true + starWriteDate = NSDate() + writeBytes = 0.0 } open func finishWritting() { - if self.isWritting { - self.isWritting = false + if isWritting { + isWritting = false NotificationCenter.default.removeObserver(self) - if let starWriteDate = self.starWriteDate { + if let starWriteDate = starWriteDate { let time = Date().timeIntervalSince(starWriteDate as Date) - self.cacheConfiguration?.add(UInt64(self.writeBytes), time: time) + cacheConfiguration?.add(UInt64(writeBytes), time: time) } } } @objc internal func applicationDidEnterBackground(_ notification: Notification) { - self.save() + save() } } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerCacheSession.swift b/VGPlayer/Classes/MediaCache/VGPlayerCacheSession.swift index ce3ada5..ec80813 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerCacheSession.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerCacheSession.swift @@ -15,6 +15,6 @@ open class VGPlayerCacheSession: NSObject { public override init() { let queue = OperationQueue() queue.name = "com.vgplayer.downloadSession" - self.downloadQueue = queue + downloadQueue = queue } } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerDownloadActionWorker.swift b/VGPlayer/Classes/MediaCache/VGPlayerDownloadActionWorker.swift index 03deb63..c61c868 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerDownloadActionWorker.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerDownloadActionWorker.swift @@ -36,59 +36,59 @@ open class VGPlayerDownloadActionWorker: NSObject { self.cacheMediaWorker = cacheMediaWorker self.url = url super.init() - self.downloadURLSessionManager = VGPlayerDownloadURLSessionManager(delegate: self) + downloadURLSessionManager = VGPlayerDownloadURLSessionManager(delegate: self) let sessionConfiguration = URLSessionConfiguration.default let session = URLSession(configuration: sessionConfiguration, delegate: downloadURLSessionManager, delegateQueue: VGPlayerCacheSession.shared.downloadQueue) self.session = session } deinit { - self.cancel() + cancel() } open func start() { - self.processActions() + processActions() } open func cancel() { - if self.session != nil { - self.session?.invalidateAndCancel() + if session != nil { + session?.invalidateAndCancel() } - self.isCancelled = true + isCancelled = true } internal func processActions() { - if self.isCancelled { + if isCancelled { return } - let firstAction = self.actions.first + let firstAction = actions.first if firstAction == nil { - self.delegate?.downloadActionWorker(self, didFinishWithError: nil) + delegate?.downloadActionWorker(self, didFinishWithError: nil) return } self.actions.remove(at: 0) if let action = firstAction { if action.type == .local { // local - if let data = self.cacheMediaWorker.cache(forRange: action.range) { - self.delegate?.downloadActionWorker(self, didReceive: data, isLocal: true) - self.processActions() + if let data = cacheMediaWorker.cache(forRange: action.range) { + delegate?.downloadActionWorker(self, didReceive: data, isLocal: true) + processActions() } else { let nsError = NSError(domain: "com.vgplayer.downloadActionWorker", code: -1, userInfo: [NSLocalizedDescriptionKey: "Read cache data failed."]) - self.delegate?.downloadActionWorker(self, didFinishWithError: nsError as Error) + delegate?.downloadActionWorker(self, didFinishWithError: nsError as Error) } } else { // remote let fromOffset = action.range.location let endOffset = action.range.location + action.range.length - 1 - var request = URLRequest(url: self.url) + var request = URLRequest(url: url) request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData // local and remote cache policy 缓存策略 let range = String(format: "bytes=%lld-%lld", fromOffset, endOffset) request.setValue(range, forHTTPHeaderField: "Range") // set HTTP Header - self.startOffset = action.range.location - self.task = self.session?.dataTask(with: request) - self.task?.resume() // star download + startOffset = action.range.location + task = self.session?.dataTask(with: request) + task?.resume() // star download } } } @@ -96,14 +96,14 @@ open class VGPlayerDownloadActionWorker: NSObject { internal func notify(downloadProgressWithFlush isFlush: Bool, isFinished: Bool) { let currentTime = CFAbsoluteTimeGetCurrent() // Returns the current system absolute time. let interval = VGPlayerCacheManager.mediaCacheNotifyInterval - if self.notifyTime < currentTime - interval || isFlush { - if let configuration = self.cacheMediaWorker.cacheConfiguration?.copy() { + if notifyTime < currentTime - interval || isFlush { + if let configuration = cacheMediaWorker.cacheConfiguration?.copy() { let configurationKey = VGPlayerCacheManager.VGPlayerCacheConfigurationKey let userInfo = [configurationKey: configuration] NotificationCenter.default.post(name: .VGPlayerCacheManagerDidUpdateCache, object: self, userInfo: userInfo) if isFinished && (configuration as! VGPlayerCacheMediaConfiguration).progress >= 1.0 { - self.notify(downloadFinishedWithError: nil) + notify(downloadFinishedWithError: nil) } } @@ -111,7 +111,7 @@ open class VGPlayerDownloadActionWorker: NSObject { } internal func notify(downloadFinishedWithError error: Error?) { - if let configuration = self.cacheMediaWorker.cacheConfiguration?.copy() { + if let configuration = cacheMediaWorker.cacheConfiguration?.copy() { let configurationKey = VGPlayerCacheManager.VGPlayerCacheConfigurationKey let finishedErrorKey = VGPlayerCacheManager.VGPlayerCacheErrorKey var userInfo: [String : Any] = [configurationKey: configuration] @@ -128,23 +128,23 @@ open class VGPlayerDownloadActionWorker: NSObject { extension VGPlayerDownloadActionWorker: VGPlayerDownloadeURLSessionManagerDelegate { public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { - self.cacheMediaWorker.finishWritting() - self.cacheMediaWorker.save() + cacheMediaWorker.finishWritting() + cacheMediaWorker.save() if error != nil { - self.delegate?.downloadActionWorker(self, didFinishWithError: error) - self.notify(downloadFinishedWithError: error) + delegate?.downloadActionWorker(self, didFinishWithError: error) + notify(downloadFinishedWithError: error) } else { - self.notify(downloadProgressWithFlush: true, isFinished: true) - self.processActions() + notify(downloadProgressWithFlush: true, isFinished: true) + processActions() } } public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { - if self.isCancelled { + if isCancelled { return } - let range = NSRange(location: self.startOffset, length: data.count) + let range = NSRange(location: startOffset, length: data.count) cacheMediaWorker.cache(data, forRange: range) { [weak self] (isCache) in guard let strongSelf = self else { return } if (!isCache) { @@ -153,9 +153,9 @@ extension VGPlayerDownloadActionWorker: VGPlayerDownloadeURLSessionManagerDelega } } - self.cacheMediaWorker.save() - self.startOffset += data.count - self.delegate?.downloadActionWorker(self, didReceive: data, isLocal: false) + cacheMediaWorker.save() + startOffset += data.count + delegate?.downloadActionWorker(self, didReceive: data, isLocal: false) notify(downloadProgressWithFlush: false, isFinished: false) } @@ -166,8 +166,8 @@ extension VGPlayerDownloadActionWorker: VGPlayerDownloadeURLSessionManagerDelega mimeType.range(of: "application") == nil){ completionHandler(.cancel) } else { - self.delegate?.downloadActionWorker(self, didReceive: response) - self.cacheMediaWorker.startWritting() + delegate?.downloadActionWorker(self, didReceive: response) + cacheMediaWorker.startWritting() completionHandler(.allow) } } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerDownloadURLSessionManager.swift b/VGPlayer/Classes/MediaCache/VGPlayerDownloadURLSessionManager.swift index 82b350e..b4806bd 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerDownloadURLSessionManager.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerDownloadURLSessionManager.swift @@ -29,30 +29,30 @@ open class VGPlayerDownloadURLSessionManager: NSObject, URLSessionDataDelegate { } public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Swift.Void) { - self.delegate?.urlSession(session, dataTask: dataTask, didReceive: response, completionHandler: completionHandler) + delegate?.urlSession(session, dataTask: dataTask, didReceive: response, completionHandler: completionHandler) } public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { - self.bufferDataQueue.sync { - self.bufferData.append(data) + bufferDataQueue.sync { + bufferData.append(data) if self.bufferData.length > kBufferSize { let chunkRange = NSRange(location: 0, length: self.bufferData.length) - let chunkData = self.bufferData.subdata(with: chunkRange) - self.bufferData.replaceBytes(in: chunkRange, withBytes: nil, length: 0) - self.delegate?.urlSession(session, dataTask: dataTask, didReceive: chunkData) + let chunkData = bufferData.subdata(with: chunkRange) + bufferData.replaceBytes(in: chunkRange, withBytes: nil, length: 0) + delegate?.urlSession(session, dataTask: dataTask, didReceive: chunkData) } } } public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { - self.bufferDataQueue.sync { - if self.bufferData.length > 0 && error == nil { - let chunkRange = NSRange(location: 0, length: self.bufferData.length) - let chunkData = self.bufferData.subdata(with: chunkRange) - self.bufferData.replaceBytes(in: chunkRange, withBytes: nil, length: 0) - self.delegate?.urlSession(session, dataTask: task as! URLSessionDataTask, didReceive: chunkData) + bufferDataQueue.sync { + if bufferData.length > 0 && error == nil { + let chunkRange = NSRange(location: 0, length: bufferData.length) + let chunkData = bufferData.subdata(with: chunkRange) + bufferData.replaceBytes(in: chunkRange, withBytes: nil, length: 0) + delegate?.urlSession(session, dataTask: task as! URLSessionDataTask, didReceive: chunkData) } } - self.delegate?.urlSession(session, task: task, didCompleteWithError: error) + delegate?.urlSession(session, task: task, didCompleteWithError: error) } } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerDownloader.swift b/VGPlayer/Classes/MediaCache/VGPlayerDownloader.swift index 4da13c9..202bdb1 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerDownloader.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerDownloader.swift @@ -17,27 +17,27 @@ public struct VGPlayerDownloaderStatus { fileprivate let downloaderStatusQueue = DispatchQueue(label: "com.vgplayer.downloaderStatusQueue") init() { - self.downloadingURLs = NSMutableSet() + downloadingURLs = NSMutableSet() } public func add(URL: URL) { - self.downloaderStatusQueue.sync { - self.downloadingURLs.add(URL) + downloaderStatusQueue.sync { + downloadingURLs.add(URL) } } public func remove(URL: URL) { - self.downloaderStatusQueue.sync { - self.downloadingURLs.remove(URL) + downloaderStatusQueue.sync { + downloadingURLs.remove(URL) } } public func contains(URL: URL) -> Bool{ - return self.downloadingURLs.contains(URL) + return downloadingURLs.contains(URL) } public func urls() -> NSSet { - return self.downloadingURLs.copy() as! NSSet + return downloadingURLs.copy() as! NSSet } } @@ -70,13 +70,13 @@ open class VGPlayerDownloader: NSObject { fileprivate var actionWorker: VGPlayerDownloadActionWorker? deinit { - VGPlayerDownloaderStatus.shared.remove(URL: self.url) + VGPlayerDownloaderStatus.shared.remove(URL: url) } public init(url: URL) { self.url = url - self.cacheMediaWorker = VGPlayerCacheMediaWorker(url: url) - self.cacheMedia = self.cacheMediaWorker.cacheConfiguration?.cacheMedia + cacheMediaWorker = VGPlayerCacheMediaWorker(url: url) + cacheMedia = cacheMediaWorker.cacheConfiguration?.cacheMedia super.init() } @@ -89,59 +89,59 @@ open class VGPlayerDownloader: NSObject { var range = NSRange(location: Int(fromOffset), length: length) if isEnd { - if let contentLength = self.cacheMediaWorker.cacheConfiguration?.cacheMedia?.contentLength { + if let contentLength = cacheMediaWorker.cacheConfiguration?.cacheMedia?.contentLength { range.length = Int(contentLength) - range.location } else { range.length = 0 - range.location } } - let actions = self.cacheMediaWorker.cachedDataActions(forRange: range) - self.actionWorker = VGPlayerDownloadActionWorker(actions: actions, url: self.url, cacheMediaWorker: self.cacheMediaWorker) - self.actionWorker?.delegate = self - self.actionWorker?.start() + let actions = cacheMediaWorker.cachedDataActions(forRange: range) + actionWorker = VGPlayerDownloadActionWorker(actions: actions, url: url, cacheMediaWorker: cacheMediaWorker) + actionWorker?.delegate = self + actionWorker?.start() } open func dowloadFrameStartToEnd() { if isCurrentURLDownloading() { handleCurrentURLDownloadingError() return } - VGPlayerDownloaderStatus.shared.add(URL: self.url) + VGPlayerDownloaderStatus.shared.add(URL: url) - self.isDownloadToEnd = true + isDownloadToEnd = true let range = NSRange(location: 0, length: 2) - let actions = self.cacheMediaWorker.cachedDataActions(forRange: range) - self.actionWorker = VGPlayerDownloadActionWorker(actions: actions, url: self.url, cacheMediaWorker: self.cacheMediaWorker) - self.actionWorker?.delegate = self - self.actionWorker?.start() + let actions = cacheMediaWorker.cachedDataActions(forRange: range) + actionWorker = VGPlayerDownloadActionWorker(actions: actions, url: url, cacheMediaWorker: cacheMediaWorker) + actionWorker?.delegate = self + actionWorker?.start() } open func cancel() { - VGPlayerDownloaderStatus.shared.remove(URL: self.url) - self.actionWorker?.cancel() - self.actionWorker?.delegate = nil - self.actionWorker = nil + VGPlayerDownloaderStatus.shared.remove(URL: url) + actionWorker?.cancel() + actionWorker?.delegate = nil + actionWorker = nil } open func invalidateAndCancel() { - VGPlayerDownloaderStatus.shared.remove(URL: self.url) - self.actionWorker?.cancel() - self.actionWorker?.delegate = nil - self.actionWorker = nil + VGPlayerDownloaderStatus.shared.remove(URL: url) + actionWorker?.cancel() + actionWorker?.delegate = nil + actionWorker = nil } // check internal func isCurrentURLDownloading() -> Bool { - return VGPlayerDownloaderStatus.shared.contains(URL: self.url) + return VGPlayerDownloaderStatus.shared.contains(URL: url) } internal func handleCurrentURLDownloadingError() { if isCurrentURLDownloading() { - let userInfo = [NSLocalizedDescriptionKey: "URL: \(self.url) alreay in downloading queue."] + let userInfo = [NSLocalizedDescriptionKey: "URL: \(url) alreay in downloading queue."] let error = NSError(domain: "com.vgplayer.download", code: -1, userInfo: userInfo) - self.delegate?.downloader(self, didFinishedWithError: error as Error) + delegate?.downloader(self, didFinishedWithError: error as Error) } } } @@ -150,22 +150,22 @@ open class VGPlayerDownloader: NSObject { extension VGPlayerDownloader: VGPlayerDownloadActionWorkerDelegate { public func downloadActionWorker(_ actionWorker: VGPlayerDownloadActionWorker, didFinishWithError error: Error?) { - VGPlayerDownloaderStatus.shared.remove(URL: self.url) - if error == nil && self.isDownloadToEnd { - self.isDownloadToEnd = false - let length = (self.cacheMediaWorker.cacheConfiguration?.cacheMedia?.contentLength)! - 2 + VGPlayerDownloaderStatus.shared.remove(URL: url) + if error == nil && isDownloadToEnd { + isDownloadToEnd = false + let length = (cacheMediaWorker.cacheConfiguration?.cacheMedia?.contentLength)! - 2 dowloaderTask(2, Int(length), true) } else { - self.delegate?.downloader(self, didFinishedWithError: error) + delegate?.downloader(self, didFinishedWithError: error) } } public func downloadActionWorker(_ actionWorker: VGPlayerDownloadActionWorker, didReceive data: Data, isLocal: Bool) { - self.delegate?.downloader(self, didReceiveData: data) + delegate?.downloader(self, didReceiveData: data) } public func downloadActionWorker(_ actionWorker: VGPlayerDownloadActionWorker, didReceive response: URLResponse) { - if self.cacheMedia == nil { + if cacheMedia == nil { let cacheMedia = VGPlayerCacheMedia() if response.isKind(of: HTTPURLResponse.classForCoder()) { @@ -192,14 +192,14 @@ extension VGPlayerDownloader: VGPlayerDownloadActionWorkerDelegate { } } self.cacheMedia = cacheMedia - let isSetCacheMedia = self.cacheMediaWorker.set(cacheMedia: cacheMedia) + let isSetCacheMedia = cacheMediaWorker.set(cacheMedia: cacheMedia) if !isSetCacheMedia { let nsError = NSError(domain: "com.vgplayer.cacheMedia", code: -1, userInfo: [NSLocalizedDescriptionKey:"Set cache media failed."]) - self.delegate?.downloader(self, didFinishedWithError: nsError as Error) + delegate?.downloader(self, didFinishedWithError: nsError as Error) return } } - self.delegate?.downloader(self, didReceiveResponse: response) + delegate?.downloader(self, didReceiveResponse: response) } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerResourceLoader.swift b/VGPlayer/Classes/MediaCache/VGPlayerResourceLoader.swift index 4254f2c..b914eec 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerResourceLoader.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerResourceLoader.swift @@ -22,40 +22,40 @@ open class VGPlayerResourceLoader: NSObject { fileprivate var isCancelled: Bool = false deinit { - self.downloader.invalidateAndCancel() + downloader.invalidateAndCancel() } public init(url: URL) { self.url = url - self.downloader = VGPlayerDownloader(url: url) + downloader = VGPlayerDownloader(url: url) super.init() } open func add(_ request: AVAssetResourceLoadingRequest) { - for (_, value) in self.pendingRequestWorkers { + for (_, value) in pendingRequestWorkers { value.cancel() value.finish() } - self.pendingRequestWorkers.removeAll() + pendingRequestWorkers.removeAll() startWorker(request) } open func remove(_ request: AVAssetResourceLoadingRequest) { let key = self.key(forRequest: request) - let loadingRequest = VGPlayerResourceLoadingRequest(self.downloader, request) + let loadingRequest = VGPlayerResourceLoadingRequest(downloader, request) loadingRequest.finish() - self.pendingRequestWorkers.removeValue(forKey: key) + pendingRequestWorkers.removeValue(forKey: key) } open func cancel() { - self.downloader.cancel() + downloader.cancel() } internal func startWorker(_ request: AVAssetResourceLoadingRequest) { let key = self.key(forRequest: request) - let loadingRequest = VGPlayerResourceLoadingRequest(self.downloader, request) + let loadingRequest = VGPlayerResourceLoadingRequest(downloader, request) loadingRequest.delegate = self - self.pendingRequestWorkers[key] = loadingRequest + pendingRequestWorkers[key] = loadingRequest loadingRequest.startWork() } @@ -74,7 +74,7 @@ extension VGPlayerResourceLoader: VGPlayerResourceLoadingRequestDelegate { public func resourceLoadingRequest(_ resourceLoadingRequest: VGPlayerResourceLoadingRequest, didCompleteWithError error: Error?) { remove(resourceLoadingRequest.request) if error != nil { - self.delegate?.resourceLoader(self, didFailWithError: error) + delegate?.resourceLoader(self, didFailWithError: error) } } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerResourceLoaderManager.swift b/VGPlayer/Classes/MediaCache/VGPlayerResourceLoaderManager.swift index bd85563..d04bab8 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerResourceLoaderManager.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerResourceLoaderManager.swift @@ -24,14 +24,14 @@ open class VGPlayerResourceLoaderManager: NSObject { } open func cleanCache() { - self.loaders.removeAll() + loaders.removeAll() } open func cancelLoaders() { - for (_, value) in self.loaders { + for (_, value) in loaders { value.cancel() } - self.loaders.removeAll() + loaders.removeAll() } internal func key(forResourceLoaderWithURL url: URL) -> String? { @@ -41,7 +41,7 @@ open class VGPlayerResourceLoaderManager: NSObject { internal func loader(forRequest request: AVAssetResourceLoadingRequest) -> VGPlayerResourceLoader? { guard let requestKey = key(forResourceLoaderWithURL: request.request.url!) else { return nil } - let loader = self.loaders[requestKey] + let loader = loaders[requestKey] return loader } @@ -77,7 +77,7 @@ extension VGPlayerResourceLoaderManager: AVAssetResourceLoaderDelegate { loader = VGPlayerResourceLoader(url: originURL!) loader?.delegate = self let key = self.key(forResourceLoaderWithURL: resourceURL) - self.loaders[key!] = loader + loaders[key!] = loader // fix https://github.com/vitoziv/VIMediaCache/pull/29 } loader?.add(loadingRequest) @@ -99,7 +99,7 @@ extension VGPlayerResourceLoaderManager: AVAssetResourceLoaderDelegate { extension VGPlayerResourceLoaderManager: VGPlayerResourceLoaderDelegate { public func resourceLoader(_ resourceLoader: VGPlayerResourceLoader, didFailWithError error: Error?) { resourceLoader.cancel() - self.delegate?.resourceLoaderManager(resourceLoader.url, didFailWithError: error) + delegate?.resourceLoaderManager(resourceLoader.url, didFailWithError: error) } } diff --git a/VGPlayer/Classes/MediaCache/VGPlayerResourceLoadingRequest.swift b/VGPlayer/Classes/MediaCache/VGPlayerResourceLoadingRequest.swift index b6900c5..a49cba7 100644 --- a/VGPlayer/Classes/MediaCache/VGPlayerResourceLoadingRequest.swift +++ b/VGPlayer/Classes/MediaCache/VGPlayerResourceLoadingRequest.swift @@ -21,19 +21,19 @@ open class VGPlayerResourceLoadingRequest: NSObject { public init(_ downloader: VGPlayerDownloader, _ resourceLoadingRequest: AVAssetResourceLoadingRequest) { self.downloader = downloader - self.request = resourceLoadingRequest + request = resourceLoadingRequest super.init() - self.downloader.delegate = self + downloader.delegate = self fillCacheMedia() } internal func fillCacheMedia() { - if self.downloader.cacheMedia != nil, - let contentType = self.downloader.cacheMedia?.contentType { - if let cacheMedia = self.downloader.cacheMedia { - self.request.contentInformationRequest?.contentType = contentType - self.request.contentInformationRequest?.contentLength = cacheMedia.contentLength - self.request.contentInformationRequest?.isByteRangeAccessSupported = cacheMedia.isByteRangeAccessSupported + if downloader.cacheMedia != nil, + let contentType = downloader.cacheMedia?.contentType { + if let cacheMedia = downloader.cacheMedia { + request.contentInformationRequest?.contentType = contentType + request.contentInformationRequest?.contentLength = cacheMedia.contentLength + request.contentInformationRequest?.isByteRangeAccessSupported = cacheMedia.isByteRangeAccessSupported } } } @@ -44,13 +44,13 @@ open class VGPlayerResourceLoadingRequest: NSObject { } open func finish() { - if !self.request.isFinished { - self.request.finishLoading(with: loaderCancelledError()) + if !request.isFinished { + request.finishLoading(with: loaderCancelledError()) } } open func startWork() { - if let dataRequest = self.request.dataRequest { + if let dataRequest = request.dataRequest { var offset = dataRequest.requestedOffset let length = dataRequest.requestedLength if dataRequest.currentOffset != 0 { @@ -62,35 +62,35 @@ open class VGPlayerResourceLoadingRequest: NSObject { isEnd = true } } - self.downloader.dowloaderTask(offset, length, isEnd) + downloader.dowloaderTask(offset, length, isEnd) } } open func cancel() { - self.downloader.cancel() + downloader.cancel() } } // MARK: - VGPlayerDownloaderDelegate extension VGPlayerResourceLoadingRequest: VGPlayerDownloaderDelegate { public func downloader(_ downloader: VGPlayerDownloader, didReceiveData data: Data) { - self.request.dataRequest?.respond(with: data) + request.dataRequest?.respond(with: data) } public func downloader(_ downloader: VGPlayerDownloader, didFinishedWithError error: Error?) { if error?._code == NSURLErrorCancelled { return } if (error == nil) { - self.request.finishLoading() + request.finishLoading() } else { - self.request.finishLoading(with: error) + request.finishLoading(with: error) } - self.delegate?.resourceLoadingRequest(self, didCompleteWithError: error) + delegate?.resourceLoadingRequest(self, didCompleteWithError: error) } public func downloader(_ downloader: VGPlayerDownloader, didReceiveResponse response: URLResponse) { - self.fillCacheMedia() + fillCacheMedia() } } diff --git a/VGPlayer/Classes/VGPlayer.swift b/VGPlayer/Classes/VGPlayer.swift index 9376a4f..ff71090 100644 --- a/VGPlayer/Classes/VGPlayer.swift +++ b/VGPlayer/Classes/VGPlayer.swift @@ -146,16 +146,16 @@ open class VGPlayer: NSObject { //MARK:- life cycle public init(URL: URL?, playerView: VGPlayerView?) { - self.mediaFormat = VGPlayerUtils.decoderVideoFormat(URL) - self.contentURL = URL - self.error = VGPlayerError() + mediaFormat = VGPlayerUtils.decoderVideoFormat(URL) + contentURL = URL + error = VGPlayerError() if let view = playerView { - self.displayView = view + displayView = view } else { - self.displayView = VGPlayerView() + displayView = VGPlayerView() } super.init() - if self.contentURL != nil { + if contentURL != nil { configurationPlayer(contentURL!) } } @@ -184,18 +184,18 @@ open class VGPlayer: NSObject { self.playerAsset = AVURLAsset(url: URL, options: .none) if URL.absoluteString.hasPrefix("file:///") { let keys = ["tracks", "playable"]; - self.playerItem = AVPlayerItem(asset: self.playerAsset!, automaticallyLoadedAssetKeys: keys) + playerItem = AVPlayerItem(asset: playerAsset!, automaticallyLoadedAssetKeys: keys) } else { // remote add cache - self.playerItem = resourceLoaderManager.playerItem(URL) + playerItem = resourceLoaderManager.playerItem(URL) } - self.player = AVPlayer(playerItem: self.playerItem) - self.displayView.reloadPlayerView() + player = AVPlayer(playerItem: playerItem) + displayView.reloadPlayerView() } // time KVO internal func addPlayerObservers() { - self.timeObserver = self.player?.addPeriodicTimeObserver(forInterval: .init(value: 1, timescale: 1), queue: DispatchQueue.main, using: { [weak self] time in + timeObserver = player?.addPeriodicTimeObserver(forInterval: .init(value: 1, timescale: 1), queue: DispatchQueue.main, using: { [weak self] time in guard let strongSelf = self else { return } if let currentTime = strongSelf.player?.currentTime().seconds, let totalDuration = strongSelf.player?.currentItem?.duration.seconds{ strongSelf.currentDuration = currentTime @@ -206,7 +206,7 @@ open class VGPlayer: NSObject { } internal func removePlayerObservers() { - self.player?.removeTimeObserver(timeObserver!) + player?.removeTimeObserver(timeObserver!) } } @@ -216,31 +216,31 @@ extension VGPlayer { open func replaceVideo(_ URL: URL) { reloadPlayer() - self.mediaFormat = VGPlayerUtils.decoderVideoFormat(URL) - self.contentURL = URL + mediaFormat = VGPlayerUtils.decoderVideoFormat(URL) + contentURL = URL configurationPlayer(URL) } open func reloadPlayer() { - self.seeking = false - self.totalDuration = 0.0 - self.currentDuration = 0.0 - self.error = VGPlayerError() - self.state = .none - self.buffering = false - self.bufferState = .none - self.cleanPlayer() + seeking = false + totalDuration = 0.0 + currentDuration = 0.0 + error = VGPlayerError() + state = .none + buffering = false + bufferState = .none + cleanPlayer() } open func cleanPlayer() { - self.player?.pause() - self.player?.cancelPendingPrerolls() - self.player?.replaceCurrentItem(with: nil) - self.player = nil - self.playerAsset?.cancelLoading() - self.playerAsset = nil - self.playerItem?.cancelPendingSeeks() - self.playerItem = nil + player?.pause() + player?.cancelPendingPrerolls() + player?.replaceCurrentItem(with: nil) + player = nil + playerAsset?.cancelLoading() + playerAsset = nil + playerItem?.cancelPendingSeeks() + playerItem = nil } open func play() { @@ -252,9 +252,9 @@ extension VGPlayer { open func pause() { guard state == .paused else { - self.player?.pause() - self.state = .paused - self.displayView.pause() + player?.pause() + state = .paused + displayView.pause() return } } @@ -264,7 +264,7 @@ extension VGPlayer { } open func seekTime(_ time: TimeInterval, completion: ((Bool) -> Swift.Void)?) { - if time.isNaN || self.playerItem?.status != .readyToPlay { + if time.isNaN || playerItem?.status != .readyToPlay { if completion != nil { completion!(false) } @@ -296,20 +296,20 @@ extension VGPlayer { internal func startPlayerBuffering() { pause() - self.bufferState = .buffering - self.buffering = true + bufferState = .buffering + buffering = true } internal func stopPlayerBuffering() { - self.bufferState = .stop - self.buffering = false + bufferState = .stop + buffering = false } internal func collectPlayerErrorLogEvent() { - self.error.playerItemErrorLogEvent = playerItem?.errorLog()?.events - self.error.error = playerItem?.error - self.error.extendedLogData = playerItem?.errorLog()?.extendedLogData() - self.error.extendedLogDataStringEncoding = playerItem?.errorLog()?.extendedLogDataStringEncoding + error.playerItemErrorLogEvent = playerItem?.errorLog()?.events + error.error = playerItem?.error + error.extendedLogData = playerItem?.errorLog()?.extendedLogData() + error.extendedLogDataStringEncoding = playerItem?.errorLog()?.extendedLogDataStringEncoding } } @@ -320,9 +320,9 @@ extension VGPlayer { internal func addPlayerItemObservers() { let options = NSKeyValueObservingOptions([.new, .initial]) - self.playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: options, context: &playerItemContext) - self.playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.loadedTimeRanges), options: options, context: &playerItemContext) - self.playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.playbackBufferEmpty), options: options, context: &playerItemContext) + playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: options, context: &playerItemContext) + playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.loadedTimeRanges), options: options, context: &playerItemContext) + playerItem?.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.playbackBufferEmpty), options: options, context: &playerItemContext) } internal func addPlayerNotifications() { @@ -332,9 +332,9 @@ extension VGPlayer { } internal func removePlayerItemObservers() { - self.playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.status)) - self.playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.loadedTimeRanges)) - self.playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.playbackBufferEmpty)) + playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.status)) + playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.loadedTimeRanges)) + playerItem?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.playbackBufferEmpty)) } internal func removePlayerNotifations() { @@ -345,16 +345,16 @@ extension VGPlayer { @objc internal func playerItemDidPlayToEnd(_ notification: Notification) { - if self.state != .playFinished { - self.state = .playFinished + if state != .playFinished { + state = .playFinished } } @objc internal func applicationWillEnterForeground(_ notification: Notification) { - if self.displayView.playerLayer != nil { - self.displayView.playerLayer?.player = player + if let playerLayer = displayView.playerLayer { + playerLayer.player = player } switch self.backgroundMode { @@ -368,15 +368,18 @@ extension VGPlayer { } @objc internal func applicationDidEnterBackground(_ notification: Notification) { - if self.displayView.playerLayer != nil { - self.displayView.playerLayer?.player = nil + + if let playerLayer = displayView.playerLayer { + playerLayer.player = nil } + switch self.backgroundMode { case .suspend: pause() case .autoPlayAndPaused: pause() case .proceed: + play() break } } @@ -398,13 +401,13 @@ extension VGPlayer { case AVPlayerItemStatus.unknown: startPlayerBuffering() case AVPlayerItemStatus.readyToPlay: - self.bufferState = .readyToPlay + bufferState = .readyToPlay case AVPlayerItemStatus.failed: - self.state = .error + state = .error collectPlayerErrorLogEvent() stopPlayerBuffering() - self.delegate?.vgPlayer(self, playerFailed: error) - self.displayView.playFailed(error) + delegate?.vgPlayer(self, playerFailed: error) + displayView.playFailed(error) } } else if keyPath == #keyPath(AVPlayerItem.playbackBufferEmpty){ @@ -417,29 +420,29 @@ extension VGPlayer { } else if keyPath == #keyPath(AVPlayerItem.loadedTimeRanges) { // 计算缓冲 - let loadedTimeRanges = self.player?.currentItem?.loadedTimeRanges + let loadedTimeRanges = player?.currentItem?.loadedTimeRanges if let bufferTimeRange = loadedTimeRanges?.first?.timeRangeValue { let star = bufferTimeRange.start.seconds // The start time of the time range. let duration = bufferTimeRange.duration.seconds // The duration of the time range. let bufferTime = star + duration - if let itemDuration = self.playerItem?.duration.seconds { - self.delegate?.vgPlayer(self, bufferedDidChange: bufferTime, totalDuration: itemDuration) - self.displayView.bufferedDidChange(bufferTime, totalDuration: itemDuration) - self.totalDuration = itemDuration + if let itemDuration = playerItem?.duration.seconds { + delegate?.vgPlayer(self, bufferedDidChange: bufferTime, totalDuration: itemDuration) + displayView.bufferedDidChange(bufferTime, totalDuration: itemDuration) + totalDuration = itemDuration if itemDuration == bufferTime { - self.bufferState = .bufferFinished + bufferState = .bufferFinished } } - if let currentTime = self.playerItem?.currentTime().seconds{ - if (bufferTime - currentTime) >= self.bufferInterval && self.state != .paused { + if let currentTime = playerItem?.currentTime().seconds{ + if (bufferTime - currentTime) >= bufferInterval && state != .paused { play() } if (bufferTime - currentTime) < bufferInterval { - self.bufferState = .buffering - self.buffering = true + bufferState = .buffering + buffering = true } else { buffering = false bufferState = .readyToPlay diff --git a/VGPlayer/Classes/VGPlayerSlider.swift b/VGPlayer/Classes/VGPlayerSlider.swift index 6bd3c91..4c89288 100644 --- a/VGPlayer/Classes/VGPlayerSlider.swift +++ b/VGPlayer/Classes/VGPlayerSlider.swift @@ -41,21 +41,21 @@ open class VGPlayerSlider: UISlider { } func configureSlider() { - self.maximumValue = 1.0 - self.minimumValue = 0.0 - self.value = 0.0 - self.maximumTrackTintColor = UIColor.clear - self.minimumTrackTintColor = UIColor.white + maximumValue = 1.0 + minimumValue = 0.0 + value = 0.0 + maximumTrackTintColor = UIColor.clear + minimumTrackTintColor = UIColor.white let thumbImage = VGPlayerUtils.imageResource("VGPlayer_ic_slider_thumb") let normalThumbImage = VGPlayerUtils.imageSize(image: thumbImage!, scaledToSize: CGSize(width: 15, height: 15)) - self.setThumbImage(normalThumbImage, for: .normal) + setThumbImage(normalThumbImage, for: .normal) let highlightedThumbImage = VGPlayerUtils.imageSize(image: thumbImage!, scaledToSize: CGSize(width: 20, height: 20)) - self.setThumbImage(highlightedThumbImage, for: .highlighted) + setThumbImage(highlightedThumbImage, for: .highlighted) - self.backgroundColor = UIColor.clear - self.progressView.tintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.7988548801) - self.progressView.trackTintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.2964201627) + backgroundColor = UIColor.clear + progressView.tintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.7988548801) + progressView.trackTintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.2964201627) } func configureProgressView(_ frame: CGRect) { diff --git a/VGPlayer/Classes/VGPlayerView.swift b/VGPlayer/Classes/VGPlayerView.swift index 87d8293..670610c 100644 --- a/VGPlayer/Classes/VGPlayerView.swift +++ b/VGPlayer/Classes/VGPlayerView.swift @@ -143,10 +143,10 @@ open class VGPlayerView: UIView { } open func reloadPlayerLayer() { - self.playerLayer = AVPlayerLayer(player: self.vgPlayer?.player) - self.layer.insertSublayer(self.playerLayer!, at: 0) - self.updateDisplayerView(frame: self.bounds) - self.timeSlider.isUserInteractionEnabled = self.vgPlayer?.mediaFormat != .m3u8 + playerLayer = AVPlayerLayer(player: self.vgPlayer?.player) + layer.insertSublayer(self.playerLayer!, at: 0) + updateDisplayerView(frame: self.bounds) + timeSlider.isUserInteractionEnabled = vgPlayer?.mediaFormat != .m3u8 reloadGravity() } @@ -155,14 +155,14 @@ open class VGPlayerView: UIView { /// /// - Parameter state: state open func playStateDidChange(_ state: VGPlayerState) { - self.playButtion.isSelected = state == .playing - self.replayButton.isHidden = !(state == .playFinished) - self.replayButton.isHidden = !(state == .playFinished) + playButtion.isSelected = state == .playing + replayButton.isHidden = !(state == .playFinished) + replayButton.isHidden = !(state == .playFinished) if state == .playing || state == .playFinished { setupTimer() } if state == .playFinished { - self.loadingIndicator.isHidden = true + loadingIndicator.isHidden = true } } @@ -171,19 +171,19 @@ open class VGPlayerView: UIView { /// - Parameter state: buffer state open func bufferStateDidChange(_ state: VGPlayerBufferstate) { if state == .buffering { - self.loadingIndicator.isHidden = false - self.loadingIndicator.startAnimating() + loadingIndicator.isHidden = false + loadingIndicator.startAnimating() } else { - self.loadingIndicator.isHidden = true - self.loadingIndicator.stopAnimating() + loadingIndicator.isHidden = true + loadingIndicator.stopAnimating() } - var current = formatSecondsToString((self.vgPlayer?.currentDuration)!) - if (self.vgPlayer?.totalDuration.isNaN)! { // HLS + var current = formatSecondsToString((vgPlayer?.currentDuration)!) + if (vgPlayer?.totalDuration.isNaN)! { // HLS current = "00:00" } if state == .readyToPlay && !isTimeSliding { - self.timeLabel.text = "\(current + " / " + (formatSecondsToString((self.vgPlayer?.totalDuration)!)))" + timeLabel.text = "\(current + " / " + (formatSecondsToString((vgPlayer?.totalDuration)!)))" } } @@ -193,7 +193,7 @@ open class VGPlayerView: UIView { /// - bufferedDuration: buffer duration /// - totalDuration: total duratiom open func bufferedDidChange(_ bufferedDuration: TimeInterval, totalDuration: TimeInterval) { - self.timeSlider.setProgress(Float(bufferedDuration / totalDuration), animated: true) + timeSlider.setProgress(Float(bufferedDuration / totalDuration), animated: true) } /// player diration @@ -207,13 +207,13 @@ open class VGPlayerView: UIView { current = "00:00" } if !isTimeSliding { - self.timeLabel.text = "\(current + " / " + (formatSecondsToString(totalDuration)))" - self.timeSlider.value = Float(currentDuration / totalDuration) + timeLabel.text = "\(current + " / " + (formatSecondsToString(totalDuration)))" + timeSlider.value = Float(currentDuration / totalDuration) } } open func configurationUI() { - self.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) + backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) configurationTopView() configurationBottomView() configurationReplayButton() @@ -221,14 +221,14 @@ open class VGPlayerView: UIView { } open func reloadPlayerView() { - self.playerLayer = AVPlayerLayer(player: nil) - self.timeSlider.value = Float(0) - self.timeSlider.setProgress(0, animated: false) - self.replayButton.isHidden = true - self.isTimeSliding = false - self.loadingIndicator.isHidden = false - self.loadingIndicator.startAnimating() - self.timeLabel.text = "--:-- / --:--" + playerLayer = AVPlayerLayer(player: nil) + timeSlider.value = Float(0) + timeSlider.setProgress(0, animated: false) + replayButton.isHidden = true + isTimeSliding = false + loadingIndicator.isHidden = false + loadingIndicator.startAnimating() + timeLabel.text = "--:-- / --:--" reloadPlayerLayer() } @@ -248,18 +248,18 @@ open class VGPlayerView: UIView { extension VGPlayerView { open func updateDisplayerView(frame: CGRect) { - self.playerLayer?.frame = frame + playerLayer?.frame = frame } open func reloadGravity() { - if self.vgPlayer != nil { - switch self.vgPlayer!.gravityMode { + if vgPlayer != nil { + switch vgPlayer!.gravityMode { case .resize: - self.playerLayer?.videoGravity = .resize + playerLayer?.videoGravity = .resize case .resizeAspect: - self.playerLayer?.videoGravity = .resizeAspect + playerLayer?.videoGravity = .resizeAspect case .resizeAspectFill: - self.playerLayer?.videoGravity = .resizeAspectFill + playerLayer?.videoGravity = .resizeAspectFill } } } @@ -267,8 +267,8 @@ extension VGPlayerView { open func enterFullscreen() { let statusBarOrientation = UIApplication.shared.statusBarOrientation if statusBarOrientation == .portrait{ - self.parentView = (self.superview)! - self.viewFrame = self.frame + parentView = (self.superview)! + viewFrame = self.frame } UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation") UIApplication.shared.statusBarOrientation = .landscapeRight @@ -302,17 +302,17 @@ extension VGPlayerView { extension VGPlayerView { internal func play() { - self.playButtion.isSelected = true + playButtion.isSelected = true } internal func pause() { - self.playButtion.isSelected = false + playButtion.isSelected = false } internal func displayControlAnimation() { - self.bottomView.isHidden = false - self.topView.isHidden = false - self.isDisplayControl = true + bottomView.isHidden = false + topView.isHidden = false + isDisplayControl = true UIView.animate(withDuration: 0.5, animations: { self.bottomView.alpha = 1 self.topView.alpha = 1 @@ -321,8 +321,8 @@ extension VGPlayerView { } } internal func hiddenControlAnimation() { - self.timer.invalidate() - self.isDisplayControl = false + timer.invalidate() + isDisplayControl = false UIView.animate(withDuration: 0.5, animations: { self.bottomView.alpha = 0 self.topView.alpha = 0 @@ -332,8 +332,8 @@ extension VGPlayerView { } } internal func setupTimer() { - self.timer.invalidate() - self.timer = Timer.vgPlayer_scheduledTimerWithTimeInterval(self.controlViewDuration, block: { [weak self] in + timer.invalidate() + timer = Timer.vgPlayer_scheduledTimerWithTimeInterval(self.controlViewDuration, block: { [weak self] in guard let strongSelf = self else { return } strongSelf.displayControlView(false) }, repeats: false) @@ -345,7 +345,7 @@ extension VGPlayerView { internal func configurationVolumeSlider() { let volumeView = MPVolumeView() if let view = volumeView.subviews.first as? UISlider { - self.volumeSlider = view + volumeSlider = view } } } @@ -355,23 +355,23 @@ extension VGPlayerView { extension VGPlayerView { internal func addGestureRecognizer() { - self.singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(onSingleTapGesture(_:))) - self.singleTapGesture.numberOfTapsRequired = 1 - self.singleTapGesture.numberOfTouchesRequired = 1 - self.singleTapGesture.delegate = self - addGestureRecognizer(self.singleTapGesture) + singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(onSingleTapGesture(_:))) + singleTapGesture.numberOfTapsRequired = 1 + singleTapGesture.numberOfTouchesRequired = 1 + singleTapGesture.delegate = self + addGestureRecognizer(singleTapGesture) - self.doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(onDoubleTapGesture(_:))) - self.doubleTapGesture.numberOfTapsRequired = 2 - self.doubleTapGesture.numberOfTouchesRequired = 1 - self.doubleTapGesture.delegate = self - addGestureRecognizer(self.doubleTapGesture) + doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(onDoubleTapGesture(_:))) + doubleTapGesture.numberOfTapsRequired = 2 + doubleTapGesture.numberOfTouchesRequired = 1 + doubleTapGesture.delegate = self + addGestureRecognizer(doubleTapGesture) - self.panGesture = UIPanGestureRecognizer(target: self, action: #selector(onPanGesture(_:))) - self.panGesture.delegate = self - addGestureRecognizer(self.panGesture) + panGesture = UIPanGestureRecognizer(target: self, action: #selector(onPanGesture(_:))) + panGesture.delegate = self + addGestureRecognizer(panGesture) - self.singleTapGesture.require(toFail: doubleTapGesture) + singleTapGesture.require(toFail: doubleTapGesture) } } @@ -390,45 +390,45 @@ extension VGPlayerView: UIGestureRecognizerDelegate { extension VGPlayerView { @objc internal func timeSliderValueChanged(_ sender: VGPlayerSlider) { - self.isTimeSliding = true - if let duration = self.vgPlayer?.totalDuration { + isTimeSliding = true + if let duration = vgPlayer?.totalDuration { let currentTime = Double(sender.value) * duration - self.timeLabel.text = "\(formatSecondsToString(currentTime) + " / " + (formatSecondsToString(duration)))" + timeLabel.text = "\(formatSecondsToString(currentTime) + " / " + (formatSecondsToString(duration)))" } } @objc internal func timeSliderTouchDown(_ sender: VGPlayerSlider) { - self.isTimeSliding = true - self.timer.invalidate() + isTimeSliding = true + timer.invalidate() } @objc internal func timeSliderTouchUpInside(_ sender: VGPlayerSlider) { - self.isTimeSliding = true + isTimeSliding = true - if let duration = self.vgPlayer?.totalDuration { + if let duration = vgPlayer?.totalDuration { let currentTime = Double(sender.value) * duration - self.vgPlayer?.seekTime(currentTime, completion: { [weak self] (finished) in + vgPlayer?.seekTime(currentTime, completion: { [weak self] (finished) in guard let strongSelf = self else { return } if finished { strongSelf.isTimeSliding = false strongSelf.setupTimer() } }) - self.timeLabel.text = "\(formatSecondsToString(currentTime) + " / " + (formatSecondsToString(duration)))" + timeLabel.text = "\(formatSecondsToString(currentTime) + " / " + (formatSecondsToString(duration)))" } } @objc internal func onPlayerButton(_ sender: UIButton) { if !sender.isSelected { - self.vgPlayer?.play() + vgPlayer?.play() } else { - self.vgPlayer?.pause() + vgPlayer?.pause() } } @objc internal func onFullscreen(_ sender: UIButton) { sender.isSelected = !sender.isSelected - self.isFullScreen = sender.isSelected + isFullScreen = sender.isSelected if isFullScreen { enterFullscreen() } else { @@ -441,8 +441,8 @@ extension VGPlayerView { /// /// - Parameter gesture: Single Tap Gesture @objc open func onSingleTapGesture(_ gesture: UITapGestureRecognizer) { - self.isDisplayControl = !self.isDisplayControl - displayControlView(self.isDisplayControl) + isDisplayControl = !isDisplayControl + displayControlView(isDisplayControl) } /// Double Tap Event @@ -450,14 +450,14 @@ extension VGPlayerView { /// - Parameter gesture: Double Tap Gesture @objc open func onDoubleTapGesture(_ gesture: UITapGestureRecognizer) { - guard self.vgPlayer == nil else { - switch self.vgPlayer!.state { + guard vgPlayer == nil else { + switch vgPlayer!.state { case .playFinished: break case .playing: - self.vgPlayer?.pause() + vgPlayer?.pause() case .paused: - self.vgPlayer?.play() + vgPlayer?.play() case .none: break case .error: @@ -479,31 +479,31 @@ extension VGPlayerView { let x = fabs(translation.x) let y = fabs(translation.y) if x < y { - self.panGestureDirection = .vertical - if location.x > self.bounds.width / 2 { - self.isVolume = true + panGestureDirection = .vertical + if location.x > bounds.width / 2 { + isVolume = true } else { - self.isVolume = false + isVolume = false } } else if x > y{ guard vgPlayer?.mediaFormat == .m3u8 else { - self.panGestureDirection = .horizontal + panGestureDirection = .horizontal return } } case .changed: - switch self.panGestureDirection { + switch panGestureDirection { case .horizontal: - if self.vgPlayer?.currentDuration == 0 { break } - self.sliderSeekTimeValue = panGestureHorizontal(velocity.x) + if vgPlayer?.currentDuration == 0 { break } + sliderSeekTimeValue = panGestureHorizontal(velocity.x) case .vertical: panGestureVertical(velocity.y) } case .ended: - switch self.panGestureDirection{ + switch panGestureDirection{ case .horizontal: if sliderSeekTimeValue.isNaN { return } - self.vgPlayer?.seekTime(self.sliderSeekTimeValue, completion: { [weak self] (finished) in + self.vgPlayer?.seekTime(sliderSeekTimeValue, completion: { [weak self] (finished) in guard let strongSelf = self else { return } if finished { @@ -512,7 +512,7 @@ extension VGPlayerView { } }) case .vertical: - self.isVolume = false + isVolume = false } default: @@ -521,13 +521,13 @@ extension VGPlayerView { } internal func panGestureHorizontal(_ velocityX: CGFloat) -> TimeInterval { - self.displayControlView(true) - self.isTimeSliding = true - self.timer.invalidate() - let value = self.timeSlider.value - if let _ = self.vgPlayer?.currentDuration ,let totalDuration = self.vgPlayer?.totalDuration{ + displayControlView(true) + isTimeSliding = true + timer.invalidate() + let value = timeSlider.value + if let _ = vgPlayer?.currentDuration ,let totalDuration = vgPlayer?.totalDuration { let sliderValue = (TimeInterval(value) * totalDuration) + TimeInterval(velocityX) / 100.0 * (TimeInterval(totalDuration) / 400) - self.timeSlider.setValue(Float(sliderValue/totalDuration), animated: true) + timeSlider.setValue(Float(sliderValue/totalDuration), animated: true) return sliderValue } else { return TimeInterval.nan @@ -536,7 +536,7 @@ extension VGPlayerView { } internal func panGestureVertical(_ velocityY: CGFloat) { - self.isVolume ? (self.volumeSlider.value -= Float(velocityY / 10000)) : (UIScreen.main.brightness -= velocityY / 10000) + isVolume ? (volumeSlider.value -= Float(velocityY / 10000)) : (UIScreen.main.brightness -= velocityY / 10000) } @objc internal func onCloseView(_ sender: UIButton) { @@ -544,17 +544,17 @@ extension VGPlayerView { } @objc internal func onReplay(_ sender: UIButton) { - self.vgPlayer?.replaceVideo((self.vgPlayer?.contentURL)!) - self.vgPlayer?.play() + vgPlayer?.replaceVideo((vgPlayer?.contentURL)!) + vgPlayer?.play() } @objc internal func deviceOrientationWillChange(_ sender: Notification) { let orientation = UIDevice.current.orientation let statusBarOrientation = UIApplication.shared.statusBarOrientation if statusBarOrientation == .portrait{ - if self.superview != nil { - self.parentView = (self.superview)! - self.viewFrame = self.frame + if superview != nil { + parentView = (superview)! + viewFrame = frame } } switch orientation { @@ -578,9 +578,9 @@ extension VGPlayerView { let statusBarOrientation = UIApplication.shared.statusBarOrientation if orientation == statusBarOrientation { if orientation == .landscapeLeft || orientation == .landscapeLeft { - let rectInWindow = self.convert(self.bounds, to: UIApplication.shared.keyWindow) - self.removeFromSuperview() - self.frame = rectInWindow + let rectInWindow = convert(bounds, to: UIApplication.shared.keyWindow) + removeFromSuperview() + frame = rectInWindow UIApplication.shared.keyWindow?.addSubview(self) self.snp.remakeConstraints({ [weak self] (make) in guard let strongSelf = self else { return } @@ -590,9 +590,9 @@ extension VGPlayerView { } } else { if orientation == .landscapeLeft || orientation == .landscapeRight { - let rectInWindow = self.convert(self.bounds, to: UIApplication.shared.keyWindow) - self.removeFromSuperview() - self.frame = rectInWindow + let rectInWindow = convert(bounds, to: UIApplication.shared.keyWindow) + removeFromSuperview() + frame = rectInWindow UIApplication.shared.keyWindow?.addSubview(self) self.snp.remakeConstraints({ [weak self] (make) in guard let strongSelf = self else { return } @@ -600,23 +600,23 @@ extension VGPlayerView { make.height.equalTo(strongSelf.superview!.bounds.width) }) } else if orientation == .portrait{ - if self.parentView == nil { return } - self.removeFromSuperview() - self.parentView!.addSubview(self) - let frame = self.parentView!.convert(self.viewFrame, to: UIApplication.shared.keyWindow) + if parentView == nil { return } + removeFromSuperview() + parentView!.addSubview(self) + let frame = parentView!.convert(viewFrame, to: UIApplication.shared.keyWindow) self.snp.remakeConstraints({ (make) in - make.centerX.equalTo(self.viewFrame.midX) - make.centerY.equalTo(self.viewFrame.midY) + make.centerX.equalTo(viewFrame.midX) + make.centerY.equalTo(viewFrame.midY) make.width.equalTo(frame.width) make.height.equalTo(frame.height) }) - self.viewFrame = CGRect() - self.parentView = nil + viewFrame = CGRect() + parentView = nil } } - self.isFullScreen = fullScreen - self.fullscreenButton.isSelected = fullScreen - delegate?.vgPlayerView(self, willFullscreen: self.isFullScreen) + isFullScreen = fullScreen + fullscreenButton.isSelected = fullScreen + delegate?.vgPlayerView(self, willFullscreen: isFullScreen) } } @@ -626,52 +626,52 @@ extension VGPlayerView { internal func configurationReplayButton() { addSubview(self.replayButton) let replayImage = VGPlayerUtils.imageResource("VGPlayer_ic_replay") - self.replayButton.setImage(VGPlayerUtils.imageSize(image: replayImage!, scaledToSize: CGSize(width: 30, height: 30)), for: .normal) - self.replayButton.addTarget(self, action: #selector(onReplay(_:)), for: .touchUpInside) - self.replayButton.isHidden = true + replayButton.setImage(VGPlayerUtils.imageSize(image: replayImage!, scaledToSize: CGSize(width: 30, height: 30)), for: .normal) + replayButton.addTarget(self, action: #selector(onReplay(_:)), for: .touchUpInside) + replayButton.isHidden = true } internal func configurationTopView() { - addSubview(self.topView) - self.titleLabel.text = "this is a title." - self.topView.addSubview(self.titleLabel) + addSubview(topView) + titleLabel.text = "this is a title." + topView.addSubview(titleLabel) let closeImage = VGPlayerUtils.imageResource("VGPlayer_ic_nav_back") - self.closeButton.setImage(VGPlayerUtils.imageSize(image: closeImage!, scaledToSize: CGSize(width: 15, height: 20)), for: .normal) - self.closeButton.addTarget(self, action: #selector(onCloseView(_:)), for: .touchUpInside) - self.topView.addSubview(self.closeButton) + closeButton.setImage(VGPlayerUtils.imageSize(image: closeImage!, scaledToSize: CGSize(width: 15, height: 20)), for: .normal) + closeButton.addTarget(self, action: #selector(onCloseView(_:)), for: .touchUpInside) + topView.addSubview(closeButton) } internal func configurationBottomView() { - addSubview(self.bottomView) - self.timeSlider.addTarget(self, action: #selector(timeSliderValueChanged(_:)), + addSubview(bottomView) + timeSlider.addTarget(self, action: #selector(timeSliderValueChanged(_:)), for: .valueChanged) - self.timeSlider.addTarget(self, action: #selector(timeSliderTouchUpInside(_:)), for: .touchUpInside) - self.timeSlider.addTarget(self, action: #selector(timeSliderTouchDown(_:)), for: .touchDown) - self.loadingIndicator.lineWidth = 1.0 - self.loadingIndicator.isHidden = false - self.loadingIndicator.startAnimating() - addSubview(self.loadingIndicator) - self.bottomView.addSubview(self.timeSlider) + timeSlider.addTarget(self, action: #selector(timeSliderTouchUpInside(_:)), for: .touchUpInside) + timeSlider.addTarget(self, action: #selector(timeSliderTouchDown(_:)), for: .touchDown) + loadingIndicator.lineWidth = 1.0 + loadingIndicator.isHidden = false + loadingIndicator.startAnimating() + addSubview(loadingIndicator) + bottomView.addSubview(timeSlider) let playImage = VGPlayerUtils.imageResource("VGPlayer_ic_play") let pauseImage = VGPlayerUtils.imageResource("VGPlayer_ic_pause") - self.playButtion.setImage(VGPlayerUtils.imageSize(image: playImage!, scaledToSize: CGSize(width: 15, height: 15)), for: .normal) - self.playButtion.setImage(VGPlayerUtils.imageSize(image: pauseImage!, scaledToSize: CGSize(width: 15, height: 15)), for: .selected) - self.playButtion.addTarget(self, action: #selector(onPlayerButton(_:)), for: .touchUpInside) - self.bottomView.addSubview(self.playButtion) + playButtion.setImage(VGPlayerUtils.imageSize(image: playImage!, scaledToSize: CGSize(width: 15, height: 15)), for: .normal) + playButtion.setImage(VGPlayerUtils.imageSize(image: pauseImage!, scaledToSize: CGSize(width: 15, height: 15)), for: .selected) + playButtion.addTarget(self, action: #selector(onPlayerButton(_:)), for: .touchUpInside) + bottomView.addSubview(playButtion) - self.timeLabel.textAlignment = .center - self.timeLabel.textColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) - self.timeLabel.font = UIFont.systemFont(ofSize: 12.0) - self.timeLabel.text = "--:-- / --:--" - self.bottomView.addSubview(self.timeLabel) + timeLabel.textAlignment = .center + timeLabel.textColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) + timeLabel.font = UIFont.systemFont(ofSize: 12.0) + timeLabel.text = "--:-- / --:--" + bottomView.addSubview(timeLabel) let enlargeImage = VGPlayerUtils.imageResource("VGPlayer_ic_fullscreen") let narrowImage = VGPlayerUtils.imageResource("VGPlayer_ic_fullscreen_exit") - self.fullscreenButton.setImage(VGPlayerUtils.imageSize(image: enlargeImage!, scaledToSize: CGSize(width: 15, height: 15)), for: .normal) - self.fullscreenButton.setImage(VGPlayerUtils.imageSize(image: narrowImage!, scaledToSize: CGSize(width: 15, height: 15)), for: .selected) - self.fullscreenButton.addTarget(self, action: #selector(onFullscreen(_:)), for: .touchUpInside) - self.bottomView.addSubview(self.fullscreenButton) + fullscreenButton.setImage(VGPlayerUtils.imageSize(image: enlargeImage!, scaledToSize: CGSize(width: 15, height: 15)), for: .normal) + fullscreenButton.setImage(VGPlayerUtils.imageSize(image: narrowImage!, scaledToSize: CGSize(width: 15, height: 15)), for: .selected) + fullscreenButton.addTarget(self, action: #selector(onFullscreen(_:)), for: .touchUpInside) + bottomView.addSubview(fullscreenButton) } diff --git a/VGPlayer/Classes/VGSubtitles.swift b/VGPlayer/Classes/VGSubtitles.swift index 3af16e0..665cccf 100644 --- a/VGPlayer/Classes/VGSubtitles.swift +++ b/VGPlayer/Classes/VGSubtitles.swift @@ -59,16 +59,16 @@ open class VGSubtitles { public init(filePath: URL, encoding: String.Encoding = String.Encoding.utf8) { do{ - self.subtitlesFormat = decoderSubtitlesFormat(filePath) + subtitlesFormat = decoderSubtitlesFormat(filePath) let string = try String(contentsOf: filePath, encoding: encoding) - self.subtitlesGroups = parseSubtitles(string) + subtitlesGroups = parseSubtitles(string) } catch { } } public func search(for time: TimeInterval) -> subtitles? { var result : subtitles? - for group in self.subtitlesGroups { + for group in subtitlesGroups { if group.start <= time && group.end >= time { result = group return result @@ -79,7 +79,7 @@ open class VGSubtitles { fileprivate func parseSubtitles(_ payload: String) -> [subtitles] { - switch self.subtitlesFormat { + switch subtitlesFormat { case .srt: return parseStrSubtitles(payload)! case .ass: diff --git a/VGPlayerExample/VGPlayerExample.xcworkspace/xcuserdata/vein.xcuserdatad/UserInterfaceState.xcuserstate b/VGPlayerExample/VGPlayerExample.xcworkspace/xcuserdata/vein.xcuserdatad/UserInterfaceState.xcuserstate index 2986eb0e2cf65b016a7939d567154b4077069828..ea46820812869c47134f1afbc8d492a98960cdc0 100644 GIT binary patch literal 39242 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 MM!h}D|I=Uj9~oKP4gdfE delta 9327 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 DRcPYB diff --git a/VGPlayerExample/VGPlayerExample.xcworkspace/xcuserdata/vein.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/VGPlayerExample/VGPlayerExample.xcworkspace/xcuserdata/vein.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index ed9a9b4..79dcb98 100644 --- a/VGPlayerExample/VGPlayerExample.xcworkspace/xcuserdata/vein.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/VGPlayerExample/VGPlayerExample.xcworkspace/xcuserdata/vein.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -2,4 +2,54 @@ + + + + + + + + + + + + + +