diff --git a/kplayer.xcodeproj/project.pbxproj b/kplayer.xcodeproj/project.pbxproj index 7b279a3..1547eeb 100644 --- a/kplayer.xcodeproj/project.pbxproj +++ b/kplayer.xcodeproj/project.pbxproj @@ -10,10 +10,8 @@ 1C73600CB93F16F4F28C116F /* KSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736A6E8396EE306B1AD3A8 /* KSettingsView.swift */; }; 1C736048BFA120F5C7D36874 /* readme.md in Sources */ = {isa = PBXBuildFile; fileRef = 1C73685B4BBFDAFBF08C032C /* readme.md */; }; 1C7360C0F2A4F0214FE353BD /* FileHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7367ECBD369A2A0C94C499 /* FileHelper.swift */; }; - 1C7360F1D2CF83ECDD586B84 /* BMPlayerCompositionResourceDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73610B997EBA367C806C1B /* BMPlayerCompositionResourceDefinition.swift */; }; 1C73613562EB375F53A0BD03 /* ServerDownloadDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736595533B56039C417E0D /* ServerDownloadDelegate.swift */; }; 1C7361B3AF46CEB30D3F4FA0 /* KSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736AE5021E3D985FE3402D /* KSettings.swift */; }; - 1C7361D2B6E0AE689FAAF4F4 /* VideoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C7FFBDAC665AE04CB65 /* VideoController.swift */; }; 1C7361D3BA77C40275F89D4A /* TimelineMeasure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7368C7B946BC9E067D37E7 /* TimelineMeasure.swift */; }; 1C7361F376DA11F17CD3250B /* TrimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736ABA0E14A51ACAC84AB5 /* TrimView.swift */; }; 1C7362AF931E0F228E5D2AED /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360B53C4C1496320953C2 /* VideoPlayerView.swift */; }; @@ -30,14 +28,11 @@ 1C7365BEFFB35E8DE8F04CCF /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73661561AD069C92FE3B15 /* TimelineView.swift */; }; 1C73666A07CF2416B1B8D3F0 /* KSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C94157754DE1C808173 /* KSettingsModel.swift */; }; 1C7366A0CFD2B55BF8C3BAF0 /* NetworkDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */; }; - 1C7366DAC06047DE335EFC37 /* BMPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736927EA28AFBEB25D7487 /* BMPlayer.swift */; }; 1C73671FC2CCCACAA2FFC153 /* ThumbnailCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */; }; 1C73672CEAE1B9DA7805D4F2 /* CenterLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7361C26ED27AB54594317D /* CenterLine.swift */; }; - 1C73673F39A34C3275D0230A /* BMPlayerClearityChooseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DFBD072763248412F74 /* BMPlayerClearityChooseButton.swift */; }; 1C73675C34BE0990D44570BE /* ItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736253AB7A95EA41B605B7 /* ItemModel.swift */; }; 1C736771C503FB0D52AEB8F7 /* kplayer.js in Sources */ = {isa = PBXBuildFile; fileRef = 1C73625012D50E457D18A785 /* kplayer.js */; }; 1C7367AF39961D2BA72480ED /* DataLoadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736F9338CE36708244D42A /* DataLoadOperation.swift */; }; - 1C7367FA10AE13598FDDE865 /* BMPlayerProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365F45D765A218FFC100F /* BMPlayerProtocols.swift */; }; 1C736821D6DF2237A3EABCC1 /* ViewControllerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73648CEC974A2500172064 /* ViewControllerExtensions.swift */; }; 1C7368242038C0FF6C9631E7 /* VideoHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364709899FF62774B0199 /* VideoHelper.swift */; }; 1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */; }; @@ -50,24 +45,17 @@ 1C736A06A2AD75B8C14EEBBE /* HtmlParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DBB6986A8B62963FBB3 /* HtmlParser.swift */; }; 1C736A5FA5BA53B2597F2ED7 /* Kirschkeks-256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C736059262A57AADE6AB761 /* Kirschkeks-256x256.png */; }; 1C736A622876405F3EE2D043 /* EditItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7366C09381DC0052B52B69 /* EditItemView.swift */; }; - 1C736A78C1F8F41E2AEEF278 /* KVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736E2CD0C1780F4F5AE0C4 /* KVideoPlayer.swift */; }; 1C736A7B6221A1D50FB3904C /* ItemType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73631C96E6C860833052CA /* ItemType.swift */; }; 1C736B4B0889BD35DC566124 /* nspersistentcontainer-defaults-swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7361F01841F546FA7AFD58 /* nspersistentcontainer-defaults-swift.swift */; }; - 1C736CB96577F6A9A7BA03E8 /* BMPlayerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364F924BD979294C3EE4A /* BMPlayerItem.swift */; }; - 1C736CD0E54786D3A2405E51 /* BMPlayerLayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7366D766CDE0C9872E86F5 /* BMPlayerLayerView.swift */; }; 1C736D16E81BA1FB325200E0 /* HanekeFetchOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */; }; 1C736D24891597F2728230EE /* ImageLoadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */; }; 1C736D24B49451141CD4B64D /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */; }; - 1C736D895B75BDCDB35937C1 /* BMTimeSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360AE55EB115762C42EB9 /* BMTimeSlider.swift */; }; 1C736D89CF86841F4C98A1F7 /* KPersistentContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7362DE1D6BE634D7C2ACBF /* KPersistentContainer.swift */; }; - 1C736DB41BD06D359E6A0DEE /* BMSubtitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7366AAB82A46086690E164 /* BMSubtitles.swift */; }; 1C736DFD076D9CC30F0B9D58 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736677D4EF2437358B2387 /* Utility.swift */; }; 1C736E21B246C0BE7E123FD3 /* MediaModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736B41C6AC33F3FA592C63 /* MediaModel.swift */; }; 1C736EC45EE7DA5F7FCE63DA /* LocalManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73659CC9B523B957E58DC6 /* LocalManager.swift */; }; 1C736ECAE78F5C722423D7ED /* TimelineScroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736362946D7A8585B0D875 /* TimelineScroller.swift */; }; 1C736F1C31D1EC23F59125F0 /* VideoTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736FC4180B42C3A357E9BF /* VideoTimelineView.swift */; }; - 1C736F278DDC77F40C8CB1D4 /* BMPlayerControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736E51F1A03E3A1200BDB6 /* BMPlayerControlView.swift */; }; - 1C736F3570EADA086682E6BC /* BMPlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360D6580FB5D09C2BBCCB /* BMPlayerManager.swift */; }; 1C736F3D082067948BA4DE84 /* FrameImagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736A5140D9B25BEC266B72 /* FrameImagesView.swift */; }; 1C736F6A223D4ADB2E1BA733 /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736069C214E9522BB1BD97 /* ItemCell.swift */; }; 1C736F7D29B76C7037CEF778 /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73647019E6C2E822127BA3 /* DatabaseManager.swift */; }; @@ -105,11 +93,8 @@ 1C736069C214E9522BB1BD97 /* ItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = ""; }; 1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HanekeFetchOperation.swift; sourceTree = ""; }; 1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageLoadOperation.swift; sourceTree = ""; }; - 1C7360AE55EB115762C42EB9 /* BMTimeSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMTimeSlider.swift; sourceTree = ""; }; 1C7360B53C4C1496320953C2 /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoPlayerView.swift; path = svideo/VideoPlayerView.swift; sourceTree = ""; }; 1C7360B6D0757D4FB6433E7B /* AsyncImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncImage.swift; sourceTree = ""; }; - 1C7360D6580FB5D09C2BBCCB /* BMPlayerManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerManager.swift; sourceTree = ""; }; - 1C73610B997EBA367C806C1B /* BMPlayerCompositionResourceDefinition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerCompositionResourceDefinition.swift; sourceTree = ""; }; 1C73611D226B48C24DB37535 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; 1C73615FFA2AA98BD1C56CD4 /* links.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = links.html; sourceTree = ""; }; 1C7361C26ED27AB54594317D /* CenterLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CenterLine.swift; path = timeline/CenterLine.swift; sourceTree = ""; }; @@ -129,23 +114,18 @@ 1C7364709899FF62774B0199 /* VideoHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoHelper.swift; sourceTree = ""; }; 1C73648CEC974A2500172064 /* ViewControllerExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllerExtensions.swift; sourceTree = ""; }; 1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkDelegate.swift; sourceTree = ""; }; - 1C7364F924BD979294C3EE4A /* BMPlayerItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerItem.swift; sourceTree = ""; }; 1C736595533B56039C417E0D /* ServerDownloadDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerDownloadDelegate.swift; sourceTree = ""; }; 1C73659CC9B523B957E58DC6 /* LocalManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalManager.swift; sourceTree = ""; }; 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; - 1C7365F45D765A218FFC100F /* BMPlayerProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerProtocols.swift; sourceTree = ""; }; 1C73661561AD069C92FE3B15 /* TimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TimelineView.swift; path = timeline/TimelineView.swift; sourceTree = ""; }; 1C736677D4EF2437358B2387 /* Utility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = ""; }; - 1C7366AAB82A46086690E164 /* BMSubtitles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMSubtitles.swift; sourceTree = ""; }; 1C7366C09381DC0052B52B69 /* EditItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditItemView.swift; sourceTree = ""; }; - 1C7366D766CDE0C9872E86F5 /* BMPlayerLayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerLayerView.swift; sourceTree = ""; }; 1C73673DC671535E3A049F54 /* PhotoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoController.swift; sourceTree = ""; }; 1C736777456388CA571DA17B /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 1C7367ECBD369A2A0C94C499 /* FileHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileHelper.swift; sourceTree = ""; }; 1C73685B4BBFDAFBF08C032C /* readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = readme.md; sourceTree = ""; }; 1C73688DAB88F9360FB62A49 /* MediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaItem.swift; sourceTree = ""; }; 1C7368C7B946BC9E067D37E7 /* TimelineMeasure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TimelineMeasure.swift; path = timeline/TimelineMeasure.swift; sourceTree = ""; }; - 1C736927EA28AFBEB25D7487 /* BMPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayer.swift; sourceTree = ""; }; 1C7369EC16B19B32B515169E /* NetData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetData.swift; sourceTree = ""; }; 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 1C736A5140D9B25BEC266B72 /* FrameImagesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FrameImagesView.swift; path = timeline/FrameImagesView.swift; sourceTree = ""; }; @@ -155,16 +135,12 @@ 1C736B41C6AC33F3FA592C63 /* MediaModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaModel.swift; sourceTree = ""; }; 1C736B794396F2E50387B8F2 /* stringutil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = stringutil.swift; sourceTree = ""; }; 1C736BC4450890C45F8FBC63 /* LayoutTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutTools.swift; sourceTree = ""; }; - 1C736C7FFBDAC665AE04CB65 /* VideoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoController.swift; sourceTree = ""; }; 1C736C94157754DE1C808173 /* KSettingsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSettingsModel.swift; sourceTree = ""; }; 1C736CF935C2A6AB916BE494 /* scratch.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = scratch.txt; sourceTree = ""; }; 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderCell.swift; sourceTree = ""; }; 1C736DBB6986A8B62963FBB3 /* HtmlParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HtmlParser.swift; sourceTree = ""; }; 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; 1C736DCD945ABAE984FF43EF /* KNetworkProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KNetworkProtocol.swift; sourceTree = ""; }; - 1C736DFBD072763248412F74 /* BMPlayerClearityChooseButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerClearityChooseButton.swift; sourceTree = ""; }; - 1C736E2CD0C1780F4F5AE0C4 /* KVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVideoPlayer.swift; sourceTree = ""; }; - 1C736E51F1A03E3A1200BDB6 /* BMPlayerControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerControlView.swift; sourceTree = ""; }; 1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailCache.swift; sourceTree = ""; }; 1C736F9338CE36708244D42A /* DataLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataLoadOperation.swift; sourceTree = ""; }; 1C736FC4180B42C3A357E9BF /* VideoTimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoTimelineView.swift; path = timeline/VideoTimelineView.swift; sourceTree = ""; }; @@ -215,7 +191,6 @@ 1C736069C214E9522BB1BD97 /* ItemCell.swift */, 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */, 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */, - 1C736C7FFBDAC665AE04CB65 /* VideoController.swift */, 1C73602350ACE2436736F981 /* BrowserController.swift */, 1C7366C09381DC0052B52B69 /* EditItemView.swift */, ); @@ -303,17 +278,6 @@ 1C736F3946A38499113D351A /* video */ = { isa = PBXGroup; children = ( - 1C736927EA28AFBEB25D7487 /* BMPlayer.swift */, - 1C736DFBD072763248412F74 /* BMPlayerClearityChooseButton.swift */, - 1C736E51F1A03E3A1200BDB6 /* BMPlayerControlView.swift */, - 1C7364F924BD979294C3EE4A /* BMPlayerItem.swift */, - 1C7366D766CDE0C9872E86F5 /* BMPlayerLayerView.swift */, - 1C7365F45D765A218FFC100F /* BMPlayerProtocols.swift */, - 1C7366AAB82A46086690E164 /* BMSubtitles.swift */, - 1C7360AE55EB115762C42EB9 /* BMTimeSlider.swift */, - 1C7360D6580FB5D09C2BBCCB /* BMPlayerManager.swift */, - 1C73610B997EBA367C806C1B /* BMPlayerCompositionResourceDefinition.swift */, - 1C736E2CD0C1780F4F5AE0C4 /* KVideoPlayer.swift */, ); path = video; sourceTree = ""; @@ -601,25 +565,14 @@ 1C73675C34BE0990D44570BE /* ItemModel.swift in Sources */, 1C73691A9C7174E0C6B57267 /* stringutil.swift in Sources */, 1C736821D6DF2237A3EABCC1 /* ViewControllerExtensions.swift in Sources */, - 1C7361D2B6E0AE689FAAF4F4 /* VideoController.swift in Sources */, 1C736953BDBBAFC40884132A /* BrowserController.swift in Sources */, 1C73671FC2CCCACAA2FFC153 /* ThumbnailCache.swift in Sources */, - 1C7366DAC06047DE335EFC37 /* BMPlayer.swift in Sources */, - 1C73673F39A34C3275D0230A /* BMPlayerClearityChooseButton.swift in Sources */, - 1C736F278DDC77F40C8CB1D4 /* BMPlayerControlView.swift in Sources */, C91E05892795AC5C0003AB79 /* KTag+CoreDataClass.swift in Sources */, - 1C736CB96577F6A9A7BA03E8 /* BMPlayerItem.swift in Sources */, - 1C736CD0E54786D3A2405E51 /* BMPlayerLayerView.swift in Sources */, - 1C7367FA10AE13598FDDE865 /* BMPlayerProtocols.swift in Sources */, - 1C736DB41BD06D359E6A0DEE /* BMSubtitles.swift in Sources */, - 1C736D895B75BDCDB35937C1 /* BMTimeSlider.swift in Sources */, - 1C736F3570EADA086682E6BC /* BMPlayerManager.swift in Sources */, 1C736E21B246C0BE7E123FD3 /* MediaModel.swift in Sources */, 1C736A7B6221A1D50FB3904C /* ItemType.swift in Sources */, 1C7360C0F2A4F0214FE353BD /* FileHelper.swift in Sources */, 1C7366A0CFD2B55BF8C3BAF0 /* NetworkDelegate.swift in Sources */, 1C7368242038C0FF6C9631E7 /* VideoHelper.swift in Sources */, - 1C7360F1D2CF83ECDD586B84 /* BMPlayerCompositionResourceDefinition.swift in Sources */, 1C736A06A2AD75B8C14EEBBE /* HtmlParser.swift in Sources */, 1C736048BFA120F5C7D36874 /* readme.md in Sources */, 1C736771C503FB0D52AEB8F7 /* kplayer.js in Sources */, @@ -640,7 +593,6 @@ 1C736A622876405F3EE2D043 /* EditItemView.swift in Sources */, 1C73613562EB375F53A0BD03 /* ServerDownloadDelegate.swift in Sources */, 1C736EC45EE7DA5F7FCE63DA /* LocalManager.swift in Sources */, - 1C736A78C1F8F41E2AEEF278 /* KVideoPlayer.swift in Sources */, 1C736FF8FF423F01F880F94D /* SVideoPlayer.swift in Sources */, 1C73633AAF0D77F8AC3557B9 /* SVideoModel.swift in Sources */, 1C7362AF931E0F228E5D2AED /* VideoPlayerView.swift in Sources */, diff --git a/kplayer/AppDelegate.swift b/kplayer/AppDelegate.swift index 5152697..e1a669c 100644 --- a/kplayer/AppDelegate.swift +++ b/kplayer/AppDelegate.swift @@ -60,6 +60,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele roots.append(LocalManager.sharedInstance.favorites) roots.append(MediaItem(name: "extern", path:"", root: "", type: ItemType.FAVROOT)) + roots.append(MediaItem(name: "tags", path:"", root: "", type: ItemType.TAGROOT)) roots.append(web) controller.model.items = roots diff --git a/kplayer/core/DatabaseManager.swift b/kplayer/core/DatabaseManager.swift index 30cd391..f04cb10 100644 --- a/kplayer/core/DatabaseManager.swift +++ b/kplayer/core/DatabaseManager.swift @@ -143,4 +143,43 @@ class DatabaseManager { } } } + + func createTag(_ answer: String) { + let tag = KTag(context: managedObjectContext) + tag.name = answer + + do { + try managedObjectContext.save() + } catch { + print("Error") + } + } + + func loadTags(completionHandler: @escaping Weiter) -> Void { + var res = [MediaItem]() + + let fetchRequest = KTag.fetchRequest() + + let results = try! managedObjectContext.fetch(fetchRequest) + + for t in results { + let tag = MediaItem(name: t.name!, path: t.name!, root: "tags", type: ItemType.DETAILS) + let snapshots = t.tagged as! Set + + for s in snapshots { + let i = s.item! + let sitem = MediaItem(name: i.name!, path: i.path!, root: i.root!, type: ItemType.VIDEO) + tag.children.append(sitem) + } + + res.append(tag) + } + + let m = MediaItem(name: "new", path: "new", root: "tags", type: ItemType.TAG) + m.local = true + + res.append(m) + + completionHandler(res) + } } diff --git a/kplayer/core/ItemType.swift b/kplayer/core/ItemType.swift index a766ec5..fe7a854 100644 --- a/kplayer/core/ItemType.swift +++ b/kplayer/core/ItemType.swift @@ -16,6 +16,11 @@ enum ItemType: String, Codable, CustomStringConvertible { */ case FAVROOT = "favroot" + /** + Repräsentiert eine Wurzel, die lokal gespeichert ist. + */ + case TAGROOT = "tagroot" + /** Repräsentiert eine Wurzel, in der nur Webseiten angezeigt werden. */ @@ -46,6 +51,11 @@ enum ItemType: String, Codable, CustomStringConvertible { */ case SNAPSHOT = "snapshot" + /** + Snapshots eines Videos. + */ + case TAG = "tag" + /** Repräsentiert einen Bilder-Ordner. */ diff --git a/kplayer/core/KSettings.swift b/kplayer/core/KSettings.swift index e25effb..408deb6 100644 --- a/kplayer/core/KSettings.swift +++ b/kplayer/core/KSettings.swift @@ -18,9 +18,6 @@ class KSettings: ObservableObject { @Published var edit = false - @Published - var newPlayer = true - convenience init(model: KSettingsModel) { self.init() scale = model.scale diff --git a/kplayer/core/MediaItem.swift b/kplayer/core/MediaItem.swift index aba1845..85ef658 100644 --- a/kplayer/core/MediaItem.swift +++ b/kplayer/core/MediaItem.swift @@ -313,7 +313,7 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject, Identifiable { } func isFolder() -> Bool { - type == ItemType.REMOTEROOT || type == ItemType.FOLDER || type == ItemType.WEBROOT || type == ItemType.FAVROOT + type == ItemType.REMOTEROOT || type == ItemType.FOLDER || type == ItemType.WEBROOT || type == ItemType.FAVROOT || type == ItemType.TAGROOT } func clone() -> MediaItem { diff --git a/kplayer/detail/BrowserController.swift b/kplayer/detail/BrowserController.swift index 700187b..3e00c01 100644 --- a/kplayer/detail/BrowserController.swift +++ b/kplayer/detail/BrowserController.swift @@ -8,6 +8,23 @@ import UIKit import WebBrowser import WebKit import Alamofire +import SwiftUI + +protocol DownloadDelegate { + func killFFMPEG() + + func dlserverlen(result: @escaping (String) -> ()) + func download(url: URL, path: String, result: @escaping (URL) -> () ) + func downloadToServer(path: String, url: URL, result: @escaping (String) -> ()) + + func inProgress() -> Int +} + +protocol ItemController { + func setCurrentItem(item: MediaItem) + func setItems(items: [MediaItem]) + func setCompletionHandler(handler: @escaping (() -> Void)) +} class BrowserController : UIViewController, ItemController, WebBrowserDelegate, UINavigationControllerDelegate, WKScriptMessageHandler, WKHTTPCookieStoreObserver { var completionHandler: (() -> Void)? @@ -212,26 +229,49 @@ class BrowserController : UIViewController, ItemController, WebBrowserDelegate, return } - let vc = VideoController() - - let item = MediaItem(name: name, path: name, root: site, type: ItemType.VIDEO) item.externalURL = url + showVideo(selectedItem: item) + } - vc.setItems(items: [item]) - vc.setCurrentItem(item: item) - vc.setCompletionHandler(handler: { + func showVideo(selectedItem: MediaItem) { + var se = selectedItem + var children = [MediaItem]() + var clonedChildren = [MediaItem]() + var baseItem = selectedItem + + if baseItem.type == ItemType.SNAPSHOT { + baseItem = selectedItem.parent! + } + + children = baseItem.children + clonedChildren = baseItem.clone().children + + let model = SVideoModel(allItems: children, currentSnapshot: se, baseItem: baseItem) + + model.edit = LocalManager.sharedInstance.settings.edit + model.loop = LocalManager.sharedInstance.settings.autoloop + model.zoomed = LocalManager.sharedInstance.settings.zoomed + + let player = SVideoPlayer(completionHandler: { saved in + baseItem.children = clonedChildren + self.dismiss(animated: true, completion: nil); - }) + }, model: model) + player - let navController = UINavigationController(rootViewController: (vc as UIViewController)) - navController.modalPresentationStyle = .fullScreen - navController.modalPresentationCapturesStatusBarAppearance = true - navController.navigationBar.barTintColor = UIColor.black - (vc as UIViewController).navigationItem.leftItemsSupplementBackButton = true + let pc = UIHostingController(rootView: player) + pc.view.backgroundColor = .black + + getWindow().rootViewController!.definesPresentationContext = true + pc.modalPresentationStyle = .overCurrentContext + getWindow().rootViewController!.present(pc, animated: true) + } - self.present(navController, animated: false, completion: nil) + func getWindow() -> UIWindow { + let delegate2 = UIApplication.shared.delegate! + return delegate2.window as! UIWindow } private func downloadZip(_ url: URL, path: String) { diff --git a/kplayer/detail/DetailViewController.swift b/kplayer/detail/DetailViewController.swift index 46ff703..1c559b4 100644 --- a/kplayer/detail/DetailViewController.swift +++ b/kplayer/detail/DetailViewController.swift @@ -168,14 +168,9 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout var i = [MediaItem]() if let d = detailItem { - if delegate!.settings().newPlayer { - showAll(d) - return - } - if (d.local) { - showComposition(d) - return - } + showAll(d) + return + let pc = MediaPhotoController() for it in d.children { @@ -216,38 +211,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout } } - showNewVideo(selectedItem: composition.children[0]) - } - - - private func showComposition(_ item: MediaItem) { - var assets = [URL]() - - for d in item.children { - assets.append(d.playerURL!) - } - - let vc = VideoController() - - let item = MediaItem(name: item.name, path: item.path, root: item.root, type: ItemType.VIDEO) - - vc.detailDelegate = delegate - vc.setItems(items: [item]) - vc.setCurrentItem(item: item) - vc.urls = assets - - vc.setCompletionHandler(handler: { - self.dismiss(animated: true, completion: nil); - }) - - let navController = UINavigationController(rootViewController: (vc as UIViewController)) - navController.modalPresentationStyle = .fullScreen - navController.modalPresentationCapturesStatusBarAppearance = true - navController.navigationBar.barTintColor = UIColor.black - (vc as UIViewController).navigationItem.leftItemsSupplementBackButton = true - - self.present(navController, animated: false, completion: nil) - + showVideo(selectedItem: composition.children[0]) } @objc func refreshItems(_ notification: Notification) { @@ -427,12 +391,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout } if sectionItem.isVideo() { - if self.delegate!.settings().newPlayer { - self.showNewVideo(selectedItem: selectedItem) - } - else { - self.showVideo(selectedItem: selectedItem) - } + self.showVideo(selectedItem: selectedItem) } else if sectionItem.isPic() { self.showPhotos(sectionItem.children) } else if sectionItem.isWeb() { @@ -501,7 +460,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout return delegate2.window as! UIWindow } - func showNewVideo(selectedItem: MediaItem) { + func showVideo(selectedItem: MediaItem) { var se = selectedItem var children = [MediaItem]() var clonedChildren = [MediaItem]() @@ -544,37 +503,6 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout getWindow().rootViewController!.present(pc, animated: true) } - func showVideo(selectedItem: MediaItem) { - var se = selectedItem - var children = [MediaItem]() - if selectedItem.parent != nil { - children = selectedItem.parent!.children - } - - var pc: VideoController - - pc = VideoController() - pc.detailDelegate = delegate - - pc.setCurrentItem(item: se) - pc.setItems(items: children) - pc.setCompletionHandler(handler: { - self.collectionView.reloadData() - self.collectionView.collectionViewLayout.invalidateLayout() - self.delegate!.saveItem(selectedItem: se) - - self.dismiss(animated: true, completion: nil); - }) - let navController = UINavigationController(rootViewController: pc) - navController.modalPresentationStyle = .fullScreen - navController.modalPresentationCapturesStatusBarAppearance = true - navController.navigationBar.barTintColor = UIColor.black - pc.navigationItem.leftItemsSupplementBackButton = true - - self.present(navController, animated: false, completion: nil) - - } - func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { if let detail: MediaItem = self.detailItem { var selectedItem = detail.children[indexPath.section] diff --git a/kplayer/detail/EditItemView.swift b/kplayer/detail/EditItemView.swift index 9a70583..c7cf262 100644 --- a/kplayer/detail/EditItemView.swift +++ b/kplayer/detail/EditItemView.swift @@ -111,10 +111,10 @@ struct EditItemView: View { return String(format: "%02d:%.1f", min, sec) } } - -struct EditItemView_Previews: PreviewProvider { - static var previews: some View { - EditItemView(item: MediaItem(name: "extern", path: "", root: "", type: ItemType.FAVROOT), len: 1000, delegate: VideoController()) - } -} +// +//struct EditItemView_Previews: PreviewProvider { +// static var previews: some View { +// EditItemView(item: MediaItem(name: "extern", path: "", root: "", type: ItemType.FAVROOT), len: 1000, delegate: SVideoPlayer(completionHandler: nil, model: SVideoModel(allItems: [](),currentSnapshot: nil, ))) +// } +//} diff --git a/kplayer/detail/VideoController.swift b/kplayer/detail/VideoController.swift deleted file mode 100644 index 0f89093..0000000 --- a/kplayer/detail/VideoController.swift +++ /dev/null @@ -1,821 +0,0 @@ -// -// Created by Marco Schmickler on 26.05.15. -// Copyright (c) 2015 Marco Schmickler. All rights reserved. -// - -import Foundation -import UIKit -import Haneke -import AVFoundation -import SwiftUI - -protocol DownloadDelegate { - func killFFMPEG() - - func dlserverlen(result: @escaping (String) -> ()) - func download(url: URL, path: String, result: @escaping (URL) -> () ) - func downloadToServer(path: String, url: URL, result: @escaping (String) -> ()) - - func inProgress() -> Int -} - -protocol ItemController { - func setCurrentItem(item: MediaItem) - func setItems(items: [MediaItem]) - func setCompletionHandler(handler: @escaping (() -> Void)) -} - -// Trimmer: https://github.com/Tomohiro-Yamashita/VideoTimelineView - -class VideoController: UIViewController, ItemController, BMPlayerDelegate, EditItemDelegate { - var player = BMPlayer() - - // played on startup - var currentItem: MediaItem? - - var currentSnapshot: MediaItem? - var allItems = [MediaItem]() - var detailDelegate: DetailDelegate? - var downloadDelegate: DownloadDelegate? - - var loopStart = 0.0 - - var completionHandler: (() -> Void)? - - var buttons = Dictionary() - - var barbutton: UIBarButtonItem? - var speedButton: UIBarButtonItem? - var loopButton: UIBarButtonItem? - var aspectButton: UIBarButtonItem? - var playButton: UIBarButtonItem? - var favButton: UIBarButtonItem? - var backButton: UIBarButtonItem? - var reviewButton: UIBarButtonItem? - - let speedOptions = [ 0.25, 0.5, 1, 2 ] - var speedOption = 2 - - var aspect = 1 - - var loopMode = false - - var thumbnailTime: TimeInterval = 0.0 - - var edit = false - var allowEdit = true - var index = 0 - - var ffmpeg = false - - var urls : [URL]? - - var kv : EditItemView? - var hc : UIHostingController? - - override func viewDidLoad() { - super.viewDidLoad() - - barbutton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(VideoController.captureThumbnail)); - navigationItem.rightBarButtonItems = [barbutton!] - - backButton = UIBarButtonItem(title: "0:00", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.back(_:))) - speedButton = UIBarButtonItem(title:"1.0", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.speed(_:))) - loopButton = UIBarButtonItem(title:"1.0", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.loop(_:))) - aspectButton = UIBarButtonItem(title:"1", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.aspect(_:))) - playButton = UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(VideoController.startstop(_:))) - favButton = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(VideoController.favorite(_:))) - reviewButton = UIBarButtonItem(title:"Edit ", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.doEdit(_:))) - - navigationItem.leftBarButtonItems = [backButton!, speedButton!, playButton!, loopButton!, aspectButton!, favButton!, reviewButton!] -//MediaItem(name: "extern", path: "", root: "", type: ItemType.FAVROOT) - - // pc.view.isHidden = true - - view.addSubview(player) - player.snp.makeConstraints { (make) in - // make.top.equalTo(self.view).offset(100) - make.left.right.equalTo(self.view) - make.height.equalTo(self.view) - // Note here, the aspect ratio 16:9 priority is lower than 1000 on the line, because the 4S iPhone aspect ratio is not 16:9 - // make.height.equalTo(player.snp.width).multipliedBy(9.0/16.0).priority(750) - } - - player.delegate = self -// Back button event - player.backBlock = { (b) in - let _ = self.navigationController?.popViewController(animated: true) - } - - if let c = currentItem, let url = c.playerURL { - print(url) - play(url as URL) - // player.playerLayer!.player!.volume = 0.0 - - update() - } - loopMode = detailDelegate!.settings().autoloop - if detailDelegate!.settings().edit { - doEdit(self) - } - updateLoop() - } - - func editItem() { - cancelEdit() - - let currentItem = player.playerLayer?.player?.currentItem - let totalTime : Double - - if let playerItem = currentItem { - totalTime = TimeInterval(playerItem.duration.value) / TimeInterval(playerItem.duration.timescale) - } - else { - totalTime = 1000 - } - - if (currentSnapshot!.length < 0.001) { - setEnd() - } - - kv = EditItemView(item: currentSnapshot!, len: totalTime, delegate: self) - hc = UIHostingController(rootView: kv!) - addChild(hc!) - - view.addSubview(hc!.view) - - hc!.view.backgroundColor = .clear - hc!.view.snp.makeConstraints { (make) in - make.width.equalTo(400) - make.height.equalTo(300) - make.right.equalToSuperview() - make.top.equalToSuperview() - } - } - - func captureZoom() { - if let item = currentSnapshot { - item.scale = Double(self.player.zoom) - item.offset = CGPoint(x: self.player.xpos, y: self.player.ypos) - } - } - - func setStart() { - if let item = currentSnapshot { - let ctime = currentTime() - - item.time = ctime - - item.objectWillChange.send() - } - } - - private func currentTime() -> Double { - CMTimeGetSeconds(player.playerLayer!.playerItem!.currentTime()) - } - - func setEnd() { - if let item = currentSnapshot { - let ctime = currentTime() - - if (ctime > item.time) { - item.length = ctime - item.time - item.objectWillChange.send() - } - } - } - - func cancelEdit() { - if hc == nil { - return - } - - hc!.view.removeFromSuperview() - kv = nil - hc = nil - } - - func seek(_ value: Double) { - self.player.seekSmoothlyToTime(newChaseTime: value) - } - - override var prefersStatusBarHidden: Bool { - return true - } - - func setItems(items: [MediaItem]) { - allItems = items - } - - func setCurrentItem(item: MediaItem) { - currentItem = item - } - - func setCompletionHandler(handler: @escaping (() -> Void)) { - completionHandler = handler - } - - @objc func doEdit(_ sender: AnyObject) { - if (!allowEdit) { - return - } - - if (edit) { - edit = false - reviewButton!.tintColor = UIColor.blue - } - else { - edit = true - loopMode = false - updateLoop() - reviewButton!.tintColor = UIColor.yellow - } - } - - func showAlert(title:String, message:String ) { - - let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - - let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil) - alertVC.addAction(okAction) - - DispatchQueue.main.async() { () -> Void in - self.present(alertVC, animated: true, completion: nil) - } - } - - @objc func favorite(_ sender: AnyObject) { - downloadDelegate?.killFFMPEG() - - print("favorite") - let inProgress = downloadDelegate?.inProgress() - let alertController = UIAlertController(title: "In Progress: \(inProgress)", message: "Download", preferredStyle: .alert) - - downloadDelegate?.dlserverlen { c in - alertController.title = "On Server: \(c)"; - } - - if let c = currentSnapshot { - if (c.loop) { - let oneAction = UIAlertAction(title: "One", style: .default) { (action) in - self.save(currentSnapshot: c, name: "1") - } - let twoAction = UIAlertAction(title: "Two", style: .default) { (action) in - self.save(currentSnapshot: c, name: "2") - } - let threeAction = UIAlertAction(title: "Three", style: .default) { (action) in - self.save(currentSnapshot: c, name: "3") - } - alertController.addAction(oneAction) - alertController.addAction(twoAction) - alertController.addAction(threeAction) - } - } - - let downloadAction = UIAlertAction(title: "Download to fav", style: .default) { (action) in - let url = self.currentItem!.playerURL - self.downloadDelegate?.download(url: url!, path: "download") { url in - self.showAlert(title: url.lastPathComponent, message: "ready") - } - } - - let url = self.currentItem!.playerURL - if url!.pathExtension != "m3u8" { - alertController.addAction(downloadAction) - } - - let serverAction = UIAlertAction(title: "Download to server", style: .default) { (action) in - let url = self.currentItem!.playerURL - if url!.pathExtension == "m3u8" { - self.ffmpeg = true - } - self.downloadDelegate?.downloadToServer(path: self.currentItem!.root, url: url!, result: { - (r) in - print(r) - self.showAlert(title: "download ready", message: r) - if (r == "exists") { - - } - }) - } - alertController.addAction(serverAction) - - let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in - } - alertController.addAction(cancelAction) - - present(alertController, animated: true) - } - - func save(currentSnapshot c: MediaItem, name: String) { - do { - try FileHelper.createDir(name: name) - - var file = FileHelper.getDocumentsDirectory().appendingPathComponent(name).appendingPathComponent(c.name) - - if file.pathExtension != "mp4" { - file = file.appendingPathExtension("mp4") - } - print (file) - var dur = player.loopEnd - loopStart - if (dur < 0) { - return - } - - VideoHelper.export(item: player.avPlayer!.currentItem!, clipStart: loopStart, clipDuration: dur, file: file, progress: { p in print(p) }) { url in - self.showAlert(title: c.name, message: "saved") - } - var s : MediaModel; - if (c.type == ItemType.SNAPSHOT && c.parent != nil) { - s = c.parent!.toMediaModel() - do { - if c.thumbUrlAbsolute != "" { - let local = try Data(contentsOf: URL(string: c.thumbUrlAbsolute)!) - let tfile = FileHelper.getDocumentsDirectory().appendingPathComponent(name).appendingPathComponent(s.name).appendingPathExtension("jpg") - try local.write(to: tfile) - } - } - catch { - // ignore - } - } - else { - s = c.toMediaModel() - } - - let jfile = FileHelper.getDocumentsDirectory().appendingPathComponent(name).appendingPathComponent(s.name).appendingPathExtension("json") - let jsonEncoder = JSONEncoder() - let jsonData = try! jsonEncoder.encode(s) - let json = String(data: jsonData, encoding: String.Encoding.utf8) - print(json) - try json!.write(to: jfile, atomically: true, encoding: .utf8) - } catch { - print(error) - } - } - - @objc func startstop(_ sender: AnyObject) { - if player.isPlaying { - player.pause() - } - else { - if player.isPlayToTheEnd { - player.seekSmoothlyToTime(newChaseTime: 0) - player.isPlayToTheEnd = false - } - player.play() - } - print("play") - } - - @objc func loop(_ sender: AnyObject) { - if edit { - loopMode = false - } - else { - loopMode = !loopMode - } - updateLoop() - } - - func updateLoop() { - if loopMode { - loopButton!.title = "loop" - } - else { - loopButton!.title = "cont" - } - } - - @objc func aspect(_ sender: AnyObject) { - aspect += 1 - if aspect > 3 { - aspect = 1 - } - switch aspect { - case 1: - player.aspectx = 1.0 - player.aspecty = 1.0 - case 2: - player.aspectx = 0.9 - player.aspecty = 1.0 - case 3: - player.aspectx = 1.0 - player.aspecty = 0.9 - default: - print("aspect") - } - // todo player.verticalMoved(0) - player.transformLayer() - aspectButton!.title = "\(aspect)" - } - - @objc func speed(_ sender: AnyObject) { - speedOption += 1 - if speedOption >= speedOptions.count { - speedOption = 0 - } - let speed = Float(speedOptions[speedOption]) - player.playerLayer!.player!.rate = speed - - speedButton!.title = "\(speed)" - print("speed \(speed)") - } - - @IBAction func back(_ sender: AnyObject) { - player.playerLayer?.pause() - player.playerLayer?.prepareToDeinit() - - completionHandler!() - } - - func play(_ url: URL) { - var def = [BMPlayerResourceDefinition]() - var index = 0; - var count = 0; - - if allItems.isEmpty { - print("no items found") - return - } - - for i in allItems { - if let a = urls { - let r = BMPlayerCompositionResourceDefinition(url: i.playerURL!, definition: i.name) - r.assets = a - def.append(r) - } - else { - - let r = BMPlayerResourceDefinition(url: i.playerURL!, definition: i.name); - def.append(r) - if (LocalManager.sharedInstance.fixDocumentURL(url.absoluteString) == LocalManager.sharedInstance.fixDocumentURL(i.playerURL?.absoluteString)) { - index = count - } - count += 1 - } - } - let asset = BMPlayerResource(name: "video", definitions: def) - // let asset = BMPlayerResource(url: url) - - player.setVideo(resource: asset, definitionIndex: index) - player.playerLayer!.player!.automaticallyWaitsToMinimizeStalling = false - if let item = player.playerLayer?.playerItem { - item.canUseNetworkResourcesForLiveStreamingWhilePaused = true - item.preferredForwardBufferDuration = 10 - } - - } - - - func addItemButton(_ newItem: MediaItem) { - let frame = CGRect(x: 0, y: 0, width: 66.0, height: 44.0); - - let button = UIButton(frame: frame) - button.showsTouchWhenHighlighted = true - button.addTarget(self, action: #selector(thumbnailClicked(_:)), for: .touchDown) - - if newItem.image != nil { - let icon = newItem.image!.scaleToSize(66.0, height: 44.0) - - button.setBackgroundImage(icon, for: UIControl.State()); - } else { - if newItem.thumbUrl != nil { - let URL = Foundation.URL(string: newItem.thumbUrlAbsolute)! - - Shared.imageCache.fetch(URL: URL).onSuccess { - i in - let icon = i.scaleToSize(66.0, height: 44.0) - button.setBackgroundImage(icon, for: UIControl.State.normal); - } - } - } - - let barbutton = UIBarButtonItem(customView: button); - - if navigationItem.rightBarButtonItems == nil { - navigationItem.rightBarButtonItems = [] - } - navigationItem.rightBarButtonItems!.append(barbutton) - - buttons[button] = newItem - } - - @objc func thumbnailClicked(_ source: UIButton) { - if let currentSnapshot = buttons[source] { - if (edit) { - self.currentSnapshot = currentSnapshot - editItem() - } - else { - gotoSnapshot(currentSnapshot: currentSnapshot) - } - } - } - - private func gotoSnapshot(currentSnapshot: MediaItem) { - player.forceSeekSmoothlyToTime(newChaseTime: currentSnapshot.time) - loopStart = currentSnapshot.time - player.loopEnd = loopStart + currentSnapshot.length - - if loopMode && currentSnapshot.scale > 0 { - player.zoom = Float(currentSnapshot.scale) - player.xpos = currentSnapshot.offset.x - player.ypos = currentSnapshot.offset.y - player.transformLayer() - } - - self.currentSnapshot = currentSnapshot - } - - @objc func update() { - reviewButton!.title = currentItem!.name - - if currentItem!.type == ItemType.SNAPSHOT { - player.seek(currentItem!.time) - loopStart = currentItem!.time - player.loopEnd = currentItem!.time + currentItem!.length - currentItem = currentItem!.parent - } else { - if !currentItem!.children.isEmpty { - player.seekSmoothlyToTime(newChaseTime: currentItem!.children[0].time) - } - else { - let duration = player.playerLayer!.playerItem!.duration - if !duration.isIndefinite { - print(duration) - player.seekSmoothlyToTime(newChaseTime: duration.seconds / 2.0) - } - } - } - - navigationItem.rightBarButtonItems = [barbutton!] - - for c in currentItem!.children { - addItemButton(c) - } - - player.play() - } - - func installGestures(_ moviePlayer: UIView) { - let twoFingersTwoTapsGesture = UITapGestureRecognizer(target: self, action: #selector(captureThumbnail)) - twoFingersTwoTapsGesture.numberOfTapsRequired = 2 - twoFingersTwoTapsGesture.numberOfTouchesRequired = 2 - moviePlayer.addGestureRecognizer(twoFingersTwoTapsGesture) - - let sR = UISwipeGestureRecognizer(target: self, action: #selector(swipeRight)) - sR.direction = UISwipeGestureRecognizer.Direction.right - sR.numberOfTouchesRequired = 1 - moviePlayer.addGestureRecognizer(sR) - - let sL = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeft)) - sL.direction = UISwipeGestureRecognizer.Direction.left - sL.numberOfTouchesRequired = 1 - moviePlayer.addGestureRecognizer(sL) - - let sR2 = UISwipeGestureRecognizer(target: self, action: #selector(swipeDown)) - sR2.direction = UISwipeGestureRecognizer.Direction.down - sR2.numberOfTouchesRequired = 1 - moviePlayer.addGestureRecognizer(sR2) - - let sR3 = UISwipeGestureRecognizer(target: self, action: #selector(swipeUp)) - sR3.direction = UISwipeGestureRecognizer.Direction.up - sR3.numberOfTouchesRequired = 1 - moviePlayer.addGestureRecognizer(sR3) - - } - - @objc func swipeUp() { - print("u") - print("Type: \(currentItem!.type) Count: \(currentItem!.children.count) Index: \(index) Current: \(currentItem!.index)") - - if !edit && (currentItem!.children.isEmpty || !(index < currentItem!.children.count - 1)) { - print ("switch") - var newIndex = currentItem!.index + 1 - - if currentItem!.parent!.children.count <= newIndex { - newIndex = 0 - } - - currentItem = currentItem!.parent!.children[newIndex] - - print("'Switched Type: \(currentItem!.type) Count: \(currentItem!.children.count) Index: \(index) Current: \(currentItem!.index)") - - index = 0 - // player.playWithURL(currentItem!.playerURL) - Timer.scheduledTimer(timeInterval: 1.2, target: self, selector: #selector(update), userInfo: nil, repeats: false) - - return - } - - if !(currentItem!.children.isEmpty) { - print ("switch internal") - if index < currentItem!.children.count - 1 { - index+=1; - } else { - index = 0; - } - let child = currentItem!.children[index] - // player.currentPlaybackTime = child.time! - // player.currentPlaybackRate = Float(speedOptions[speedOption]) - } - - } - - @objc func swipeRight() { -// print("r") -// player.currentPlaybackRate = Float(0.0) -// player.currentPlaybackTime = player.currentPlaybackTime - 30.0 -// Timer.scheduledTimer(timeInterval: 0.9, -// target: self, -// selector: #selector(resumePlay), -// userInfo: nil, -// repeats: false) - - - } - - @objc func swipeDown() { - print("d") - if !edit { - var newIndex = currentItem!.index - 1 - - if newIndex < 0 { - newIndex = 0 - } - - currentItem = currentItem!.parent!.children[newIndex] - index = 0; - - // player.contentURL = currentItem!.playerURL - player.play() - Timer.scheduledTimer(timeInterval: 1.2, target: self, selector: #selector(update), userInfo: nil, repeats: false) - - return - } - // player.currentPlaybackTime = player.currentPlaybackTime + 10.0 - Timer.scheduledTimer(timeInterval: 0.9, - target: self, - selector: #selector(resumePlay), - userInfo: nil, - repeats: false) - - - } - - @objc func swipeLeft() { - print("l") -// player.currentPlaybackRate = Float(0.0) -// player.currentPlaybackTime = player.currentPlaybackTime + 30.0 - Timer.scheduledTimer(timeInterval: 0.9, - target: self, - selector: #selector(resumePlay), - userInfo: nil, - repeats: false) - - - } - - @objc func resumePlay() { -// player.currentPlaybackRate = Float(speedOptions[speedOption]) - print("resumePlay") - } - - @objc func captureThumbnail() { - if edit { - let asset = player.playerLayer!.playerItem!.asset - - do { - let imgGenerator = AVAssetImageGenerator(asset: asset) - imgGenerator.appliesPreferredTrackTransform = true - let time = player.playerLayer!.playerItem!.currentTime() - let cgImage = try imgGenerator.copyCGImage(at: time, actualTime: nil) - let thumbnail = UIImage(cgImage: cgImage) - - showThumbnail(thumbnail: thumbnail, time: time) - - } catch let error { - print("*** Error generating thumbnail: \(error.localizedDescription)") - } - // thumbnailTime = player.currentPlaybackTime - print("tap \(thumbnailTime)") -// moviePlayer!.requestThumbnailImages(atTimes: [thumbnailTime], -// timeOption: MPMovieTimeOption.exact); - } - else { - detailDelegate!.favItem(currentItem!) - } - } - - func showThumbnail(thumbnail: UIImage, time: CMTime) { - let newItem = MediaItem(name: currentItem!.name, path: currentItem!.path, root: currentItem!.root, type: ItemType.SNAPSHOT) - newItem.image = thumbnail - newItem.time = time.seconds - newItem.parent = currentItem! - newItem.local = currentItem!.local - currentItem!.children.append(newItem) - - print(newItem.time) - - addItemButton(newItem) - } - - func moveUp() { - if !loopMode { - return - } - - let t = Date().timeIntervalSince1970 - if lastMove + 2 > t { - return - } - lastMove = t - - if let c = currentItem?.children { - if !c.isEmpty{ - if let s = currentSnapshot { - if var i = c.firstIndex { x in x===s } { - print(i) - i+=1 - if i >= c.count { - i = 0 - } - gotoSnapshot(currentSnapshot: c[i]) - } - } - else { - gotoSnapshot(currentSnapshot: c[0]) - } - } - } - } - - var lastMove = 0.0 - - func moveDown() { - if !loopMode { - return - } - - let t = Date().timeIntervalSince1970 - if lastMove + 2 > t { - return - } - lastMove = t - - if let c = currentItem?.children { - if !c.isEmpty{ - if let s = currentSnapshot { - if var i = c.firstIndex { x in x===s } { - print(i) - i-=1 - if i < 0 { - i = c.count-1 - } - gotoSnapshot(currentSnapshot: c[i]) - } - } - else { - gotoSnapshot(currentSnapshot: c[0]) - } - } - } - } - - func bmPlayer(player: BMPlayer) { - let speed = Float(speedOptions[speedOption]) - if let pl = player.playerLayer!.player { - pl.rate = speed - } - } - - func bmPlayer(player: BMPlayer, playerStateDidChange state: BMPlayerState) { - print("state") - - } - - func bmPlayer(player: BMPlayer, loadedTimeDidChange loadedDuration: TimeInterval, totalDuration: TimeInterval) { - // print("load") - } - - func bmPlayer(player: BMPlayer, playTimeDidChange currentTime: TimeInterval, totalTime: TimeInterval) { - if loopMode { - if currentTime > player.loopEnd && loopStart < player.loopEnd { - player.forceSeekSmoothlyToTime(newChaseTime: loopStart) - } - } - - if let b = backButton { - b.title = BMPlayer.formatSecondsToString(currentTime) - } - } - - func bmPlayer(player: BMPlayer, playerIsPlaying playing: Bool) { - print("playing") - } - - func bmPlayer(player: BMPlayer, playerOrientChanged isFullscreen: Bool) { - print("orient") - } -} diff --git a/kplayer/master/KSettingsView.swift b/kplayer/master/KSettingsView.swift index 479dc55..b95dc22 100644 --- a/kplayer/master/KSettingsView.swift +++ b/kplayer/master/KSettingsView.swift @@ -27,9 +27,6 @@ struct KSettingsView: View { Toggle(isOn: $kSettings.edit, label: { Text("Edit") }) - Toggle(isOn: $kSettings.newPlayer, label: { - Text("New Player") - }) } } Button(action: { diff --git a/kplayer/master/MasterViewController.swift b/kplayer/master/MasterViewController.swift index fa7a83d..1ba2cb7 100644 --- a/kplayer/master/MasterViewController.swift +++ b/kplayer/master/MasterViewController.swift @@ -103,13 +103,22 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating, UITa let submitAction = UIAlertAction(title: "Submit", style: .default) { [unowned ac] _ in let answer = ac.textFields![0].text! - do { - try FileHelper.createDir(name: answer) - item.name = answer - item.path = answer - self.tableView.reloadData() - } catch { - print(error) + if (item.root == "/tags") { + DatabaseManager.sharedInstance.createTag(answer) + let m = MediaItem(name: answer, path: answer, root: "tags", type: ItemType.TAG) + m.local = true + item.children.append(m) + m.parent = item + } + else { + do { + try FileHelper.createDir(name: answer) + item.name = answer + item.path = answer + self.tableView.reloadData() + } catch { + print(error) + } } } diff --git a/kplayer/master/NetworkDelegate.swift b/kplayer/master/NetworkDelegate.swift index 47d5cc4..ce0629f 100644 --- a/kplayer/master/NetworkDelegate.swift +++ b/kplayer/master/NetworkDelegate.swift @@ -52,6 +52,13 @@ class NetworkDelegate: MasterDelegate, DetailDelegate { return } + if selectedItem.type == ItemType.TAGROOT { + + DatabaseManager.sharedInstance.loadTags(completionHandler: weiter) + + return + } + if (NetworkManager.sharedInstance.offline) { completionHandler(selectedItem) } diff --git a/kplayer/photo/PhotoController.swift b/kplayer/photo/PhotoController.swift index 7823bd1..9be21c5 100644 --- a/kplayer/photo/PhotoController.swift +++ b/kplayer/photo/PhotoController.swift @@ -225,22 +225,6 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView } return } - - let controller = VideoController() - controller.edit = false - controller.allowEdit = false - - controller.currentItem = currentItem - controller.setItems(items: [currentItem]) - controller.navigationItem.leftItemsSupplementBackButton = true - navigationController!.navigationBar.barTintColor = UIColor.black - navigationController!.pushViewController(controller, animated: true) - - controller.completionHandler = { - () in -// NetworkManager.sharedInstance.saveItem(self.currentItem!) - self.dismiss(animated: true, completion: nil); - } } override func loadView() { diff --git a/kplayer/video/BMPlayer.swift b/kplayer/video/BMPlayer.swift deleted file mode 100644 index 5432404..0000000 --- a/kplayer/video/BMPlayer.swift +++ /dev/null @@ -1,820 +0,0 @@ -// -// BMPlayer.swift -// Pods -// -// Created by BrikerMan on 16/4/28. -// -// - -import UIKit -import SnapKit -import MediaPlayer - -/// BMPlayerDelegate to obserbe player state -public protocol BMPlayerDelegate : class { - func bmPlayer(player: BMPlayer) - func bmPlayer(player: BMPlayer, playerStateDidChange state: BMPlayerState) - func bmPlayer(player: BMPlayer, loadedTimeDidChange loadedDuration: TimeInterval, totalDuration: TimeInterval) - func bmPlayer(player: BMPlayer, playTimeDidChange currentTime : TimeInterval, totalTime: TimeInterval) - func bmPlayer(player: BMPlayer, playerIsPlaying playing: Bool) - func bmPlayer(player: BMPlayer, playerOrientChanged isFullscreen: Bool) - func moveUp() - func moveDown() -} - -/** - internal enum to check the pan direction - - - horizontal: horizontal - - vertical: vertical -*/ -enum BMPanDirection: Int { - case horizontal = 0 - case vertical = 1 -} - -open class BMPlayer: UIView, UIGestureRecognizerDelegate { - open var zoom = Float(1.0) - open var aspectx = Float(1.0) - open var aspecty = Float(1.0) - var xpos = 0.0 - var ypos = 0.0 - var loopEnd = 0.0 - - open var pinchGesture: UIPinchGestureRecognizer! - open var moveGesture: UIPanGestureRecognizer! - - open weak var delegate: BMPlayerDelegate? - - open var backBlock:((Bool) -> Void)? - - /// Gesture to change volume / brightness - open var panGesture: UIPanGestureRecognizer! - - private func initGesture() { - pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(self.pinched(_:))) - self.addGestureRecognizer(pinchGesture) - // moveGesture = UIPanGestureRecognizer(target: self, action: #selector(self.moved(_:))) - // moveGesture.minimumNumberOfTouches = 2 - // moveGesture.maximumNumberOfTouches = 2 - // self.addGestureRecognizer(moveGesture) - } - - func panDir(_ pan: UIPanGestureRecognizer) { - - let velocityPoint = pan.velocity(in: self) - - xpos += (Double(velocityPoint.x) / 50.0) - ypos += (Double(velocityPoint.y) / 50.0) - - transformLayer() - } - - @objc fileprivate func moved(_ gestureRecognizer: UIPanGestureRecognizer) { - } - - @objc fileprivate func pinched(_ gestureRecognizer: UIPinchGestureRecognizer) { - if gestureRecognizer.state == .began || gestureRecognizer.state == .changed { - zoom *= Float(gestureRecognizer.scale) - - if zoom < 0.1 { - zoom = 1.0 - xpos = 0 - ypos = 0 - } - - gestureRecognizer.scale = 1.0 - - transformLayer() - } - - } - - func transformLayer() { - let t = CATransform3DMakeTranslation(CGFloat(xpos), CGFloat(ypos), 0.0) - playerLayer!.layer.transform = CATransform3DScale(t, CGFloat(zoom * aspectx), CGFloat(zoom * aspecty), 1.0) - } - - /// AVLayerVideoGravityType - open var videoGravity = AVLayerVideoGravity.resizeAspect { - didSet { - self.playerLayer?.videoGravity = videoGravity - } - } - - open var isPlaying: Bool { - get { - return playerLayer?.isPlaying ?? false - } - } - - //Closure fired when play time changed - open var playTimeDidChange:((TimeInterval, TimeInterval) -> Void)? - - //Closure fired when play state chaged - @available(*, deprecated, message: "Use newer `isPlayingStateChanged`") - open var playStateDidChange:((Bool) -> Void)? - - open var playOrientChanged:((Bool) -> Void)? - - open var isPlayingStateChanged:((Bool) -> Void)? - - open var playStateChanged:((BMPlayerState) -> Void)? - - open var avPlayer: AVPlayer? { - return playerLayer?.player - } - - open var playerLayer: BMPlayerLayerView? - - fileprivate var resource: BMPlayerResource! - - fileprivate var currentDefinition = 0 - - var controlView: BMPlayerControlView! - - fileprivate var customControlView: BMPlayerControlView? - - fileprivate var isFullScreen:Bool { - get { - return UIApplication.shared.statusBarOrientation.isLandscape - } - } - - /// 滑动方向 - fileprivate var panDirection = BMPanDirection.horizontal - - /// 音量滑竿 - fileprivate var volumeViewSlider: UISlider! - - fileprivate let BMPlayerAnimationTimeInterval: Double = 4.0 - fileprivate let BMPlayerControlBarAutoFadeOutTimeInterval: Double = 0.5 - - /// 用来保存时间状态 - fileprivate var sumTime : TimeInterval = 0 - var totalDuration : TimeInterval = 0 - fileprivate var currentPosition : TimeInterval = 0 - fileprivate var shouldSeekTo : TimeInterval = 0 - - fileprivate var isURLSet = false - fileprivate var isSliderSliding = false - fileprivate var isPauseByUser = false - fileprivate var isVolume = false - fileprivate var isSkip = false - fileprivate var skipAmount = 0.0 - - fileprivate var isMaskShowing = false - fileprivate var isSlowed = false - fileprivate var isMirrored = false - var isPlayToTheEnd = false - //视频画面比例 - fileprivate var aspectRatio: BMPlayerAspectRatio = .default - - //Cache is playing result to improve callback performance - fileprivate var isPlayingCache: Bool? = nil - - var isScrub = false - var isSeekInProgress = false - var chaseTime = CMTime.zero - var continueTime = 0.0 - - // MARK: - Public functions - - /** - Play - - - parameter resource: media resource - - parameter definitionIndex: starting definition index, default start with the first definition - */ - open func setVideo(resource: BMPlayerResource, definitionIndex: Int = 0) { - isURLSet = false - self.resource = resource - - currentDefinition = definitionIndex - controlView.prepareUI(for: resource, selectedIndex: definitionIndex) - - if BMPlayerConf.shouldAutoPlay { - isURLSet = true - let asset = resource.definitions[definitionIndex] - let size = asset.avURLAsset.videoSize() - - if (size.height < 1500) { - zoom = LocalManager.sharedInstance.settings.scale - if (zoom < 1.0) { - xpos = -100 - } - - transformLayer() - } - - playerLayer?.playAsset(asset: asset.avURLAsset) - - } else { - controlView.showCover(url: resource.cover) - controlView.hideLoader() - } - } - - /** - auto start playing, call at viewWillAppear, See more at pause - */ - open func autoPlay() { - if !isPauseByUser && isURLSet && !isPlayToTheEnd { - play() - } - } - - func isFile() -> Bool { - guard resource != nil else { return false } - - let asset = resource.definitions[currentDefinition] - - return asset.url.isFileURL - } - - /** - Play - */ - open func play() { - guard resource != nil else { return } - - if !isURLSet { - let asset = resource.definitions[currentDefinition] - playerLayer?.playAsset(asset: asset.avURLAsset) - controlView.hideCoverImageView() - isURLSet = true - } - - panGesture.isEnabled = true - playerLayer?.play() - isPauseByUser = false - - if let d = delegate { d.bmPlayer(player: self) } - } - - /** - Pause - - - parameter allow: should allow to response `autoPlay` function - */ - open func pause(allowAutoPlay allow: Bool = false) { - playerLayer?.pause() - isPauseByUser = !allow - } - - /** - seek - - - parameter to: target time - */ - open func seek(_ to:TimeInterval, completion: (()->Void)? = nil) { - chaseTime = CMTime(value: Int64(to * 10000), timescale: CMTimeScale(10000)) - playerLayer?.seek(to: to, completion: completion) - } - - /** - update UI to fullScreen - */ - open func updateUI(_ isFullScreen: Bool) { - controlView.updateUI(isFullScreen) - } - - /** - increade volume with step, default step 0.1 - - - parameter step: step - */ - open func addVolume(step: Float = 0.1) { - self.volumeViewSlider.value += step - } - - /** - decreace volume with step, default step 0.1 - - - parameter step: step - */ - open func reduceVolume(step: Float = 0.1) { - self.volumeViewSlider.value -= step - } - - /** - prepare to dealloc player, call at View or Controllers deinit funciton. - */ - open func prepareToDealloc() { - playerLayer?.prepareToDeinit() - controlView.prepareToDealloc() - } - - /** - If you want to create BMPlayer with custom control in storyboard. - create a subclass and override this method. - - - return: costom control which you want to use - */ - open func storyBoardCustomControl() -> BMPlayerControlView? { - return nil - } - - // https://gist.github.com/shaps80/ac16b906938ad256e1f47b52b4809512 - public func forceSeekSmoothlyToTime(newChaseTime: Double) { - chaseTime = CMTime.zero - seekSmoothlyToTime(newChaseTime: CMTime(value: Int64(newChaseTime * 10000), timescale: CMTimeScale(10000))) - } - public func seekSmoothlyToTime(newChaseTime: Double) { - seekSmoothlyToTime(newChaseTime: CMTime(value: Int64(newChaseTime * 10000), timescale: CMTimeScale(10000))) - } - - public func seekSmoothlyToTime(newChaseTime: CMTime) { - if CMTimeCompare(newChaseTime, chaseTime) != 0 { - chaseTime = newChaseTime - - if !isSeekInProgress { - trySeekToChaseTime() - } - } - } - - private func trySeekToChaseTime() { - guard playerLayer!.player?.status == .readyToPlay else { return } - actuallySeekToTime() - } - - private func actuallySeekToTime() { - isSeekInProgress = true - let seekTimeInProgress = chaseTime - - playerLayer!.player?.seek(to: seekTimeInProgress, toleranceBefore: CMTime.zero, toleranceAfter: CMTime.zero) { [weak self] _ in - guard let `self` = self else { return } - - if CMTimeCompare(seekTimeInProgress, self.chaseTime) == 0 { - self.isSeekInProgress = false - } else { - self.trySeekToChaseTime() - } - } - } - - public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { - if touch.view?.isDescendant(of: controlView.topWrapperView) == true { - return true - } - else { - return true - } - } - // MARK: - Action Response - - @objc open func panDirection(_ pan: UIPanGestureRecognizer) { - let resolution = 10000.0 - - if pan.numberOfTouches <= 1 { - // 根据在view上Pan的位置,确定是调音量还是亮度 - let locationPoint = pan.location(in: self) - - // 我们要响应水平移动和垂直移动 - // 根据上次和本次移动的位置,算出一个速率的point - let velocityPoint = pan.velocity(in: self) - - // 判断是垂直移动还是水平移动 - switch pan.state { - case UIGestureRecognizer.State.began: - // 使用绝对值来判断移动的方向 - let x = abs(velocityPoint.x) - let y = abs(velocityPoint.y) - - if (locationPoint.y < self.bounds.size.height * 1 / 7) { - self.isSkip = (zoom <= 1.0) - isScrub = false - - if (!isPlaying) { - isScrub = true - let currentTime = CMTimeGetSeconds(playerLayer!.player!.currentTime()) - continueTime = currentTime - let vel = velocityPoint.x + velocityPoint.y - var time = CMTimeMake(value: Int64((currentTime + (Float64(vel) / resolution))*10000), timescale: 10000) - seekSmoothlyToTime(newChaseTime: time) - } - - } else { - isScrub = false - self.isSkip = true - self.skipAmount = 0.0 - } - - if x > y { - if BMPlayerConf.enablePlaytimeGestures { - self.panDirection = BMPanDirection.horizontal - - - // 给sumTime初值 - if let player = playerLayer?.player { - let time = player.currentTime() - self.sumTime = TimeInterval(time.value) / TimeInterval(time.timescale) - } - } - } else { - self.panDirection = BMPanDirection.vertical - if locationPoint.x > self.bounds.size.width / 2 { - self.isVolume = false - } else { - self.isVolume = false - } - } - - case UIGestureRecognizer.State.changed: - if !self.isSkip && isPlaying { - xpos += (Double(velocityPoint.x) * 0.1); - ypos += (Double(velocityPoint.y) * 0.1); - transformLayer() - } - if (isScrub) { - let vel = velocityPoint.x + velocityPoint.y - var time = CMTimeMake(value: Int64((Float64(vel) / resolution)*10000), timescale: 10000) - seekSmoothlyToTime(newChaseTime: CMTimeAdd(chaseTime, time)) - } - switch self.panDirection { - case BMPanDirection.horizontal: - self.horizontalMoved(velocityPoint.x) - case BMPanDirection.vertical: - self.verticalMoved(velocityPoint.y) - } - - case UIGestureRecognizer.State.ended: - // 移动结束也需要判断垂直或者平移 - // 比如水平移动结束时,要快进到指定位置,如果这里没有判断,当我们调节音量完之后,会出现屏幕跳动的bug - switch (self.panDirection) { - case BMPanDirection.horizontal: - controlView.hideSeekToView() - isSliderSliding = false - - if isSkip && !isScrub { - print(skipAmount) - if (locationPoint.y < self.bounds.size.height * 1 / 8) { - if skipAmount > 0 { - self.sumTime += TimeInterval(5) - } else if skipAmount < -0 { - self.sumTime -= TimeInterval(5) - } - } - else { - if (skipAmount > 1500) { - self.sumTime += TimeInterval(30) - - if sumTime > loopEnd { - loopEnd = 1000000; - } - } else if skipAmount > 0 { - self.sumTime += TimeInterval(10) - } else if skipAmount > -1500 { - self.sumTime -= TimeInterval(10) - } else { - self.sumTime -= TimeInterval(30) - } - } - controlView.controlViewAnimation(isShow: true) - - if isPlayToTheEnd { - isPlayToTheEnd = false - seek(self.sumTime, completion: { [weak self] in - self?.play() - }) - } else { - seek(self.sumTime, completion: { [weak self] in - self?.autoPlay() - }) - } - } - // 把sumTime滞空,不然会越加越多 - self.sumTime = 0.0 - - if (isScrub && !isFile()) { - seek(continueTime) - } - - isScrub = false - - case BMPanDirection.vertical: - self.isVolume = false - } - default: - break - } - } - else { - panDir(pan) - } - } - - open func verticalMoved(_ value: CGFloat) { -print(value) - if (value < -100) { - delegate?.moveDown() - // controlView(controlView: controlView, didChooseDefinition: currentDefinition+1); - } - - if (value > 100) { - delegate?.moveUp() - // controlView(controlView: controlView, didChooseDefinition: currentDefinition+1); - } - - if !isSkip { - } - } - - open func horizontalMoved(_ value: CGFloat) { - guard BMPlayerConf.enablePlaytimeGestures else { return } - - isSliderSliding = true - - if !isSkip { - } - else { - skipAmount += Double(value) - } - } - - @objc open func onOrientationChanged() { - self.updateUI(isFullScreen) - delegate?.bmPlayer(player: self, playerOrientChanged: isFullScreen) - playOrientChanged?(isFullScreen) - } - - @objc fileprivate func fullScreenButtonPressed() { - controlView.updateUI(!self.isFullScreen) - if isFullScreen { - UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation") - UIApplication.shared.setStatusBarHidden(false, with: .fade) - UIApplication.shared.statusBarOrientation = .portrait - } else { - UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation") - UIApplication.shared.setStatusBarHidden(false, with: .fade) - UIApplication.shared.statusBarOrientation = .landscapeRight - } - } - - // MARK: - 生命周期 - deinit { - playerLayer?.pause() - playerLayer?.prepareToDeinit() - NotificationCenter.default.removeObserver(self, name: UIApplication.didChangeStatusBarOrientationNotification, object: nil) - } - - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - if let customControlView = storyBoardCustomControl() { - self.customControlView = customControlView - } - initUI() - initUIData() - configureVolume() - preparePlayer() - initGesture() - } - -// @available(*, deprecated:3.0, message:"Use newer init(customControlView:_)") -// public convenience init(customControllView: BMPlayerControlView?) { -// self.init(customControlView: customControllView) -// } - - @objc public init(customControlView: BMPlayerControlView?) { - super.init(frame:CGRect.zero) - self.customControlView = customControlView - initUI() - initUIData() - configureVolume() - preparePlayer() - initGesture() - } - - public convenience init() { - self.init(customControlView:nil) - } - - // MARK: - 初始化 - fileprivate func initUI() { - self.backgroundColor = UIColor.black - - if let customView = customControlView { - controlView = customView - } else { - controlView = BMPlayerControlView() - } - - addSubview(controlView) - controlView.updateUI(isFullScreen) - controlView.delegate = self - controlView.player = self - controlView.snp.makeConstraints { (make) in - make.edges.equalTo(self) - } - - panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.panDirection(_:))) - panGesture.delegate = self - // panGesture.minimumNumberOfTouches = 1 - // panGesture.maximumNumberOfTouches = 1 - self.addGestureRecognizer(panGesture) - } - - fileprivate func initUIData() { - NotificationCenter.default.addObserver(self, selector: #selector(self.onOrientationChanged), name: UIApplication.didChangeStatusBarOrientationNotification, object: nil) - } - - fileprivate func configureVolume() { - let volumeView = MPVolumeView() - for view in volumeView.subviews { - if let slider = view as? UISlider { - self.volumeViewSlider = slider - } - } - } - - fileprivate func preparePlayer() { - playerLayer = BMPlayerLayerView() - playerLayer!.videoGravity = videoGravity - insertSubview(playerLayer!, at: 0) - playerLayer!.snp.makeConstraints { [weak self](make) in - guard let `self` = self else { return } - make.edges.equalTo(self) - } - playerLayer!.delegate = self - controlView.showLoader() - self.layoutIfNeeded() - } -} - -extension BMPlayer: BMPlayerLayerViewDelegate { - public func bmPlayer(player: BMPlayerLayerView, playerIsPlaying playing: Bool) { - controlView.playStateDidChange(isPlaying: playing) - delegate?.bmPlayer(player: self, playerIsPlaying: playing) - playStateDidChange?(player.isPlaying) - isPlayingStateChanged?(player.isPlaying) - } - - public func bmPlayer(player: BMPlayerLayerView, loadedTimeDidChange loadedDuration: TimeInterval, totalDuration: TimeInterval) { - BMPlayerManager.shared.log("loadedTimeDidChange - \(loadedDuration) - \(totalDuration)") - controlView.loadedTimeDidChange(loadedDuration: loadedDuration, totalDuration: totalDuration) - delegate?.bmPlayer(player: self, loadedTimeDidChange: loadedDuration, totalDuration: totalDuration) - controlView.totalDuration = totalDuration - self.totalDuration = totalDuration - } - - public func bmPlayer(player: BMPlayerLayerView, playerStateDidChange state: BMPlayerState) { - BMPlayerManager.shared.log("playerStateDidChange - \(state)") - - controlView.playerStateDidChange(state: state) - switch state { - case .readyToPlay: - if !isPauseByUser { - play() - } - if shouldSeekTo != 0 { - seek(shouldSeekTo, completion: {[weak self] in - guard let `self` = self else { return } - if !self.isPauseByUser { - self.play() - } else { - self.pause() - } - }) - shouldSeekTo = 0 - } - - case .bufferFinished: - autoPlay() - - case .playedToTheEnd: - isPlayToTheEnd = true - - default: - break - } - panGesture.isEnabled = state != .playedToTheEnd - delegate?.bmPlayer(player: self, playerStateDidChange: state) - playStateChanged?(state) - } - - public func bmPlayer(player: BMPlayerLayerView, playTimeDidChange currentTime: TimeInterval, totalTime: TimeInterval) { - // BMPlayerManager.shared.log("playTimeDidChange - \(currentTime) - \(totalTime)") - delegate?.bmPlayer(player: self, playTimeDidChange: currentTime, totalTime: totalTime) - self.currentPosition = currentTime - totalDuration = totalTime - if isSliderSliding { - return - } - controlView.playTimeDidChange(currentTime: currentTime, totalTime: totalTime) - controlView.totalDuration = totalDuration - playTimeDidChange?(currentTime, totalTime) - } -} - -extension BMPlayer: BMPlayerControlViewDelegate { - open func controlView(controlView: BMPlayerControlView, - didChooseDefinition index: Int) { - shouldSeekTo = currentPosition - playerLayer?.resetPlayer() - currentDefinition = index - playerLayer?.playAsset(asset: resource.definitions[index].avURLAsset) - } - - open func controlView(controlView: BMPlayerControlView, - didPressButton button: UIButton) { - if let action = BMPlayerControlView.ButtonType(rawValue: button.tag) { - switch action { - case .back: - backBlock?(isFullScreen) - if isFullScreen { - fullScreenButtonPressed() - } else { - playerLayer?.prepareToDeinit() - } - - case .play: - if button.isSelected { - pause() - } else { - if isPlayToTheEnd { - seek(0, completion: {[weak self] in - self?.play() - }) - controlView.hidePlayToTheEndView() - isPlayToTheEnd = false - } - play() - } - - case .replay: - isPlayToTheEnd = false - seek(0) - play() - - case .fullscreen: - fullScreenButtonPressed() - - default: - print("[Error] unhandled Action") - } - } - } - - open func controlView(controlView: BMPlayerControlView, - slider: UISlider, - onSliderEvent event: UIControl.Event) { - switch event { - case .touchDown: - playerLayer?.onTimeSliderBegan() - isSliderSliding = true - - case .valueChanged: - let target = self.totalDuration * Double(slider.value) - - seekSmoothlyToTime(newChaseTime: CMTime(seconds: target, preferredTimescale: 10000)) - - break - case .touchUpInside : - isSliderSliding = false - let target = self.totalDuration * Double(slider.value) - - if isPlayToTheEnd { - isPlayToTheEnd = false - seek(target, completion: {[weak self] in - self?.play() - }) - controlView.hidePlayToTheEndView() - } else { - seek(target, completion: {[weak self] in - self?.autoPlay() - }) - } - default: - break - } - } - - open func controlView(controlView: BMPlayerControlView, didChangeVideoAspectRatio: BMPlayerAspectRatio) { - self.playerLayer?.aspectRatio = self.aspectRatio - } - - open func controlView(controlView: BMPlayerControlView, didChangeVideoPlaybackRate rate: Float) { - self.playerLayer?.player?.rate = rate - } -} - -extension AVAsset{ - func videoSize()->CGSize{ - let tracks = self.tracks(withMediaType: AVMediaType.video) - if (tracks.count > 0){ - let videoTrack = tracks[0] - let size = videoTrack.naturalSize - let txf = videoTrack.preferredTransform - let realVidSize = size.applying(txf) - print(videoTrack) - print(txf) - print(size) - print(realVidSize) - return realVidSize - } - return CGSize(width: 0, height: 0) - } - -} \ No newline at end of file diff --git a/kplayer/video/BMPlayerClearityChooseButton.swift b/kplayer/video/BMPlayerClearityChooseButton.swift deleted file mode 100644 index 22c59db..0000000 --- a/kplayer/video/BMPlayerClearityChooseButton.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// File.swift -// Pods -// -// Created by BrikerMan on 16/5/21. -// -// - -import UIKit - -class BMPlayerClearityChooseButton: UIButton { - override init(frame: CGRect) { - super.init(frame: frame) - initUI() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - initUI() - } - - func initUI() { - self.titleLabel?.font = UIFont.systemFont(ofSize: 12) - self.layer.cornerRadius = 2 - self.layer.borderWidth = 1 - self.layer.borderColor = UIColor(white: 1, alpha: 0.8).cgColor - self.setTitleColor(UIColor(white: 1, alpha: 0.9), for: .normal) - } -} diff --git a/kplayer/video/BMPlayerCompositionResourceDefinition.swift b/kplayer/video/BMPlayerCompositionResourceDefinition.swift deleted file mode 100644 index 5120de7..0000000 --- a/kplayer/video/BMPlayerCompositionResourceDefinition.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by Marco Schmickler on 05.05.21. -// Copyright (c) 2021 Marco Schmickler. All rights reserved. -// - -import Foundation -import AVFoundation - -class BMPlayerCompositionResourceDefinition : BMPlayerResourceDefinition { - var assets: [URL]? - - override var avURLAsset: AVAsset { - get { - let asset = VideoHelper.combine(urls: assets!) - - return asset - } - } -} diff --git a/kplayer/video/BMPlayerControlView.swift b/kplayer/video/BMPlayerControlView.swift deleted file mode 100644 index 6eb7e7c..0000000 --- a/kplayer/video/BMPlayerControlView.swift +++ /dev/null @@ -1,757 +0,0 @@ -// -// BMPlayerControlView.swift -// Pods -// -// Created by BrikerMan on 16/4/29. -// -// - -import UIKit -import NVActivityIndicatorView - - -@objc public protocol BMPlayerControlViewDelegate: class { - /** - call when control view choose a definition - - - parameter controlView: control view - - parameter index: index of definition - */ - func controlView(controlView: BMPlayerControlView, didChooseDefinition index: Int) - - /** - call when control view pressed an button - - - parameter controlView: control view - - parameter button: button type - */ - func controlView(controlView: BMPlayerControlView, didPressButton button: UIButton) - - /** - call when slider action trigged - - - parameter controlView: control view - - parameter slider: progress slider - - parameter event: action - */ - func controlView(controlView: BMPlayerControlView, slider: UISlider, onSliderEvent event: UIControl.Event) - - /** - call when needs to change playback rate - - - parameter controlView: control view - - parameter rate: playback rate - */ - @objc optional func controlView(controlView: BMPlayerControlView, didChangeVideoPlaybackRate rate: Float) -} - -open class BMPlayerControlView: UIView { - - open weak var delegate: BMPlayerControlViewDelegate? - open weak var player: BMPlayer? - - // MARK: Variables - open var resource: BMPlayerResource? - - open var selectedIndex = 0 - open var isFullscreen = false - open var isMaskShowing = true - - open var totalDuration: TimeInterval = 0 - open var delayItem: DispatchWorkItem? - - var playerLastState: BMPlayerState = .notSetURL - - fileprivate var isSelectDefinitionViewOpened = false - - // MARK: UI Components - /// main views which contains the topMaskView and bottom mask view - open var mainMaskView = UIView() - open var topMaskView = UIView() - open var bottomMaskView = UIView() - - /// Image view to show video cover - open var maskImageView = UIImageView() - - /// top views - open var topWrapperView = UIView() - open var backButton = UIButton(type : UIButton.ButtonType.custom) - open var titleLabel = UILabel() - open var chooseDefinitionView = UIView() - - /// bottom view - open var bottomWrapperView = UIView() - open var currentTimeLabel = UILabel() - open var totalTimeLabel = UILabel() - - /// Progress slider - open var timeSlider = BMTimeSlider() - - /// load progress view - open var progressView = UIProgressView() - - /* play button - playButton.isSelected = player.isPlaying - */ - open var playButton = UIButton(type: UIButton.ButtonType.custom) - - /* fullScreen button - fullScreenButton.isSelected = player.isFullscreen - */ - open var fullscreenButton = UIButton(type: UIButton.ButtonType.custom) - - open var subtitleLabel = UILabel() - open var subtitleBackView = UIView() - open var subtileAttribute: [NSAttributedString.Key : Any]? - - /// Activty Indector for loading - open var loadingIndicator = NVActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) - - open var seekToView = UIView() - open var seekToViewImage = UIImageView() - open var seekToLabel = UILabel() - - open var replayButton = UIButton(type: UIButton.ButtonType.custom) - - /// Gesture used to show / hide control view - open var tapGesture: UITapGestureRecognizer! - open var doubleTapGesture: UITapGestureRecognizer! - - // MARK: - handle player state change - /** - call on when play time changed, update duration here - - - parameter currentTime: current play time - - parameter totalTime: total duration - */ - open func playTimeDidChange(currentTime: TimeInterval, totalTime: TimeInterval) { - currentTimeLabel.text = BMPlayer.formatSecondsToString(currentTime) - totalTimeLabel.text = BMPlayer.formatSecondsToString(totalTime) - timeSlider.value = Float(currentTime) / Float(totalTime) - showSubtile(from: resource?.subtitle, at: currentTime) - } - - - /** - change subtitle resource - - - Parameter subtitles: new subtitle object - */ - open func update(subtitles: BMSubtitles?) { - resource?.subtitle = subtitles - } - - /** - call on load duration changed, update load progressView here - - - parameter loadedDuration: loaded duration - - parameter totalDuration: total duration - */ - open func loadedTimeDidChange(loadedDuration: TimeInterval, totalDuration: TimeInterval) { - progressView.setProgress(Float(loadedDuration)/Float(totalDuration), animated: true) - } - - open func playerStateDidChange(state: BMPlayerState) { - switch state { - case .readyToPlay: - hideLoader() - - case .buffering: - showLoader() - - case .bufferFinished: - hideLoader() - - case .playedToTheEnd: - playButton.isSelected = false - showPlayToTheEndView() - controlViewAnimation(isShow: true) - - default: - break - } - playerLastState = state - } - - /** - Call when User use the slide to seek function - - - parameter toSecound: target time - - parameter totalDuration: total duration of the video - - parameter isAdd: isAdd - */ - open func showSeekToView(to toSecound: TimeInterval, total totalDuration:TimeInterval, isAdd: Bool) { - seekToView.isHidden = false - seekToLabel.text = BMPlayer.formatSecondsToString(toSecound) - - let rotate = isAdd ? 0 : CGFloat(Double.pi) - seekToViewImage.transform = CGAffineTransform(rotationAngle: rotate) - - let targetTime = BMPlayer.formatSecondsToString(toSecound) - timeSlider.value = Float(toSecound / totalDuration) - currentTimeLabel.text = targetTime - } - - // MARK: - UI update related function - /** - Update UI details when player set with the resource - - - parameter resource: video resouce - - parameter index: defualt definition's index - */ - open func prepareUI(for resource: BMPlayerResource, selectedIndex index: Int) { - self.resource = resource - self.selectedIndex = index - titleLabel.text = resource.name - prepareChooseDefinitionView() - autoFadeOutControlViewWithAnimation() - } - - open func playStateDidChange(isPlaying: Bool) { - autoFadeOutControlViewWithAnimation() - playButton.isSelected = isPlaying - } - - /** - auto fade out controll view with animtion - */ - open func autoFadeOutControlViewWithAnimation() { - cancelAutoFadeOutAnimation() - delayItem = DispatchWorkItem { [weak self] in - if self?.playerLastState != .playedToTheEnd { - self?.controlViewAnimation(isShow: false) - } - } - DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + BMPlayerConf.animateDelayTimeInterval, - execute: delayItem!) - } - - /** - cancel auto fade out controll view with animtion - */ - open func cancelAutoFadeOutAnimation() { - delayItem?.cancel() - } - - /** - Implement of the control view animation, override if need's custom animation - - - parameter isShow: is to show the controlview - */ - open func controlViewAnimation(isShow: Bool) { - let alpha: CGFloat = isShow ? 1.0 : 0.0 - self.isMaskShowing = isShow - - UIApplication.shared.setStatusBarHidden(!isShow, with: .fade) - - UIView.animate(withDuration: 0.3, animations: {[weak self] in - guard let wSelf = self else { return } - wSelf.topMaskView.alpha = alpha - - wSelf.bottomMaskView.alpha = alpha - wSelf.mainMaskView.backgroundColor = UIColor(white: 0, alpha: isShow ? 0.0 : 0.0) // todo marco - - if isShow { - if wSelf.isFullscreen { wSelf.chooseDefinitionView.alpha = 1.0 } - } else { - wSelf.replayButton.isHidden = true - wSelf.chooseDefinitionView.snp.updateConstraints { (make) in - make.height.equalTo(35) - } - wSelf.chooseDefinitionView.alpha = 0.0 - } - wSelf.layoutIfNeeded() - }) { [weak self](_) in - if isShow { - self?.autoFadeOutControlViewWithAnimation() - } - } - } - - /** - Implement of the UI update when screen orient changed - - - parameter isForFullScreen: is for full screen - */ - open func updateUI(_ isForFullScreen: Bool) { - isFullscreen = isForFullScreen - fullscreenButton.isSelected = isForFullScreen - chooseDefinitionView.isHidden = !BMPlayerConf.enableChooseDefinition || !isForFullScreen - if isForFullScreen { - if BMPlayerConf.topBarShowInCase.rawValue == 2 { - topMaskView.isHidden = true - } else { - topMaskView.isHidden = false - } - } else { - if BMPlayerConf.topBarShowInCase.rawValue >= 1 { - topMaskView.isHidden = true - } else { - topMaskView.isHidden = false - } - } - } - - /** - Call when video play's to the end, override if you need custom UI or animation when played to the end - */ - open func showPlayToTheEndView() { - replayButton.isHidden = false - } - - open func hidePlayToTheEndView() { - replayButton.isHidden = true - } - - open func showLoader() { - loadingIndicator.isHidden = false - loadingIndicator.startAnimating() - } - - open func hideLoader() { - loadingIndicator.isHidden = true - } - - open func hideSeekToView() { - seekToView.isHidden = true - } - - open func showCoverWithLink(_ cover:String) { - self.showCover(url: URL(string: cover)) - } - - open func showCover(url: URL?) { - if let url = url { - DispatchQueue.global(qos: .default).async { [weak self] in - let data = try? Data(contentsOf: url) - DispatchQueue.main.async(execute: { [weak self] in - guard let `self` = self else { return } - if let data = data { - self.maskImageView.image = UIImage(data: data) - } else { - self.maskImageView.image = nil - } - self.hideLoader() - }); - } - } - } - - open func hideCoverImageView() { - self.maskImageView.isHidden = true - } - - open func prepareChooseDefinitionView() { - guard let resource = resource else { - return - } - for item in chooseDefinitionView.subviews { - item.removeFromSuperview() - } - - for i in 0.. UIImage? { - let bundle = Bundle(for: BMPlayer.self) - return UIImage(named: fileName, in: bundle, compatibleWith: nil) - } -} - diff --git a/kplayer/video/BMPlayerItem.swift b/kplayer/video/BMPlayerItem.swift deleted file mode 100644 index 7379cad..0000000 --- a/kplayer/video/BMPlayerItem.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// BMPlayerItem.swift -// Pods -// -// Created by BrikerMan on 16/5/21. -// -// - -import Foundation -import AVFoundation - -public class BMPlayerResource { - public let name: String - public let cover: URL? - public var subtitle: BMSubtitles? - public let definitions: [BMPlayerResourceDefinition] - - - /** - Player recource item with url, used to play single difinition video - - - parameter name: video name - - parameter url: video url - - parameter cover: video cover, will show before playing, and hide when play - - parameter subtitles: video subtitles - */ - public convenience init(url: URL, name: String = "", cover: URL? = nil, subtitle: URL? = nil) { - let definition = BMPlayerResourceDefinition(url: url, definition: "") - - var subtitles: BMSubtitles? = nil - if let subtitle = subtitle { - subtitles = BMSubtitles(url: subtitle) - } - - self.init(name: name, definitions: [definition], cover: cover, subtitles: subtitles) - } - - /** - Play resouce with multi definitions - - - parameter name: video name - - parameter definitions: video definitions - - parameter cover: video cover - - parameter subtitles: video subtitles - */ - public init(name: String = "", definitions: [BMPlayerResourceDefinition], cover: URL? = nil, subtitles: BMSubtitles? = nil) { - self.name = name - self.cover = cover - self.subtitle = subtitles - self.definitions = definitions - } -} - - -open class BMPlayerResourceDefinition { - public let url: URL - public let definition: String - - /// An instance of NSDictionary that contains keys for specifying options for the initialization of the AVURLAsset. See AVURLAssetPreferPreciseDurationAndTimingKey and AVURLAssetReferenceRestrictionsKey above. - public var options: [String : Any]? - - open var avURLAsset: AVAsset { - get { - guard !url.isFileURL, url.pathExtension != "m3u8" else { - return AVURLAsset(url: url) - } - return BMPlayerManager.asset(for: self) - } - } - - /** - Video recource item with defination name and specifying options - - - parameter url: video url - - parameter definition: url deifination - - parameter options: specifying options for the initialization of the AVURLAsset - - you can add http-header or other options which mentions in https://developer.apple.com/reference/avfoundation/avurlasset/initialization_options - - to add http-header init options like this - ``` - let header = ["User-Agent":"BMPlayer"] - let definiton.options = ["AVURLAssetHTTPHeaderFieldsKey":header] - ``` - */ - public init(url: URL, definition: String, options: [String : Any]? = nil) { - self.url = url - self.definition = definition - self.options = options - } -} diff --git a/kplayer/video/BMPlayerLayerView.swift b/kplayer/video/BMPlayerLayerView.swift deleted file mode 100644 index a32aaba..0000000 --- a/kplayer/video/BMPlayerLayerView.swift +++ /dev/null @@ -1,506 +0,0 @@ -// -// BMPlayerLayerView.swift -// Pods -// -// Created by BrikerMan on 16/4/28. -// -// - -import UIKit -import AVFoundation - -/** - Player status emun - - - notSetURL: not set url yet - - readyToPlay: player ready to play - - buffering: player buffering - - bufferFinished: buffer finished - - playedToTheEnd: played to the End - - error: error with playing - */ -public enum BMPlayerState { - case notSetURL - case readyToPlay - case buffering - case bufferFinished - case playedToTheEnd - case error -} - - -/** - video aspect ratio types - - - `default`: video default aspect - - sixteen2NINE: 16:9 - - four2THREE: 4:3 - */ -public enum BMPlayerAspectRatio : Int { - case `default` = 0 - case sixteen2NINE - case four2THREE -} - -public protocol BMPlayerLayerViewDelegate : class { - func bmPlayer(player: BMPlayerLayerView, playerStateDidChange state: BMPlayerState) - func bmPlayer(player: BMPlayerLayerView, loadedTimeDidChange loadedDuration: TimeInterval, totalDuration: TimeInterval) - func bmPlayer(player: BMPlayerLayerView, playTimeDidChange currentTime: TimeInterval, totalTime: TimeInterval) - func bmPlayer(player: BMPlayerLayerView, playerIsPlaying playing: Bool) -} - -open class BMPlayerLayerView: UIView { - - open weak var delegate: BMPlayerLayerViewDelegate? - - /// 视频跳转秒数置0 - open var seekTime = 0 - - /// 播放属性 - open var playerItem: AVPlayerItem? { - didSet { - onPlayerItemChange() - } - } - - /// 播放属性 - open lazy var player: AVPlayer? = { - if let item = self.playerItem { - let player = AVPlayer(playerItem: item) - return player - } - return nil - }() - - - open var videoGravity = AVLayerVideoGravity.resizeAspect { - didSet { - self.playerLayer?.videoGravity = videoGravity - } - } - - open var isPlaying: Bool = false { - didSet { - if oldValue != isPlaying { - delegate?.bmPlayer(player: self, playerIsPlaying: isPlaying) - } - } - } - - var aspectRatio: BMPlayerAspectRatio = .default { - didSet { - self.setNeedsLayout() - } - } - - /// 计时器 - var timer: Timer? - - fileprivate var urlAsset: AVAsset? - - fileprivate var lastPlayerItem: AVPlayerItem? - /// playerLayer - fileprivate var playerLayer: AVPlayerLayer? - /// 音量滑杆 - fileprivate var volumeViewSlider: UISlider! - /// 播放器的几种状态 - fileprivate var state = BMPlayerState.notSetURL { - didSet { - if state != oldValue { - delegate?.bmPlayer(player: self, playerStateDidChange: state) - } - } - } - /// 是否为全屏 - fileprivate var isFullScreen = false - /// 是否锁定屏幕方向 - fileprivate var isLocked = false - /// 是否在调节音量 - fileprivate var isVolume = false - /// 是否播放本地文件 - fileprivate var isLocalVideo = false - /// slider上次的值 - fileprivate var sliderLastValue: Float = 0 - /// 是否点了重播 - fileprivate var repeatToPlay = false - /// 播放完了 - fileprivate var playDidEnd = false - // playbackBufferEmpty会反复进入,因此在bufferingOneSecond延时播放执行完之前再调用bufferingSomeSecond都忽略 - // 仅在bufferingSomeSecond里面使用 - fileprivate var isBuffering = false - fileprivate var hasReadyToPlay = false - fileprivate var shouldSeekTo: TimeInterval = 0 - - // MARK: - Actions - open func playURL(url: URL) { - let asset = AVURLAsset(url: url) - playAsset(asset: asset) - } - - open func playAsset(asset: AVAsset) { - urlAsset = asset - onSetVideoAsset() - play() - } - - - open func play() { - if let player = player { - player.play() - setupTimer() - isPlaying = true - } - } - - open func pause() { - player?.pause() - isPlaying = false - timer?.fireDate = Date.distantFuture - } - - deinit { - NotificationCenter.default.removeObserver(self) - } - - - // MARK: - layoutSubviews - override open func layoutSubviews() { - super.layoutSubviews() - switch self.aspectRatio { - case .default: - self.playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspect - self.playerLayer?.frame = self.bounds - break - case .sixteen2NINE: - self.playerLayer?.videoGravity = AVLayerVideoGravity.resize - self.playerLayer?.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.width/(16/9)) - break - case .four2THREE: - self.playerLayer?.videoGravity = AVLayerVideoGravity.resize - let _w = self.bounds.height * 4 / 3 - self.playerLayer?.frame = CGRect(x: (self.bounds.width - _w )/2, y: 0, width: _w, height: self.bounds.height) - break - } - } - - open func resetPlayer() { - // 初始化状态变量 - - self.playDidEnd = false - self.playerItem = nil - self.lastPlayerItem = nil - self.seekTime = 0 - - self.timer?.invalidate() - - self.pause() - // 移除原来的layer - self.playerLayer?.removeFromSuperlayer() - // 替换PlayerItem为nil - self.player?.replaceCurrentItem(with: nil) - player?.removeObserver(self, forKeyPath: "rate") - - // 把player置为nil - self.player = nil - } - - open func prepareToDeinit() { - self.resetPlayer() - } - - open func onTimeSliderBegan() { - if self.player?.currentItem?.status == AVPlayerItem.Status.readyToPlay { - self.timer?.fireDate = Date.distantFuture - } - } - - open func seek(to secounds: TimeInterval, completion:(()->Void)?) { - if secounds.isNaN { - return - } - setupTimer() - if self.player?.currentItem?.status == AVPlayerItem.Status.readyToPlay { - let draggedTime = CMTime(value: Int64(secounds)*10000, timescale: 10000) - // self.player!.cancelPendingPrerolls() - self.playerItem!.cancelPendingSeeks() - self.player!.seek(to: draggedTime, toleranceBefore: CMTimeMake(value: 1, timescale: 1), toleranceAfter: CMTimeMake(value: 1, timescale: 1), completionHandler: { (finished) in - completion?() - }) - } else { - self.shouldSeekTo = secounds - } - } - - // MARK: - 设置视频URL - fileprivate func onSetVideoAsset() { - repeatToPlay = false - playDidEnd = false - configPlayer() - } - - fileprivate func onPlayerItemChange() { - if lastPlayerItem == playerItem { - return - } - - if let item = lastPlayerItem { - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: item) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemFailedToPlayToEndTime, object: item) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemNewErrorLogEntry, object: item) - item.removeObserver(self, forKeyPath: "status") - item.removeObserver(self, forKeyPath: "loadedTimeRanges") - item.removeObserver(self, forKeyPath: "playbackBufferEmpty") - item.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp") - } - - lastPlayerItem = playerItem - - if let item = playerItem { - NotificationCenter.default.addObserver(self, selector: #selector(moviePlayDidEnd), - name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, - object: playerItem) - - item.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil) - item.addObserver(self, forKeyPath: "loadedTimeRanges", options: NSKeyValueObservingOptions.new, context: nil) - // 缓冲区空了,需要等待数据 - item.addObserver(self, forKeyPath: "playbackBufferEmpty", options: NSKeyValueObservingOptions.new, context: nil) - // 缓冲区有足够数据可以播放了 - item.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: NSKeyValueObservingOptions.new, context: nil) - } - } - - // Getting error from Notification payload - @objc fileprivate func newErrorLogEntry(_ notification: Notification) { - guard let object = notification.object, let playerItem = object as? AVPlayerItem else { - return - } - guard let errorLog: AVPlayerItemErrorLog = playerItem.errorLog() else { - return - } - print("Error: \(errorLog)") - } - - @objc fileprivate func failedToPlayToEndTime(_ notification: Notification) { - let error = notification.userInfo!["AVPlayerItemFailedToPlayToEndTimeErrorKey"] - print(error) - } - - fileprivate func configPlayer(){ - player?.removeObserver(self, forKeyPath: "rate") - playerItem = AVPlayerItem(asset: urlAsset!) - playerItem?.preferredForwardBufferDuration = TimeInterval(floatLiteral: 100.0) - playerItem?.canUseNetworkResourcesForLiveStreamingWhilePaused = true - - player = AVPlayer(playerItem: playerItem!) - player?.automaticallyWaitsToMinimizeStalling = true - player!.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.new, context: nil) - self.connectPlayerLayer() - setNeedsLayout() - layoutIfNeeded() - - NotificationCenter.default.addObserver(self, selector: #selector(self.connectPlayerLayer), name: UIApplication.willEnterForegroundNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.disconnectPlayerLayer), name: UIApplication.didEnterBackgroundNotification, object: nil) - - let center = NotificationCenter.default - center.addObserver(self, selector: #selector(self.newErrorLogEntry), name: .AVPlayerItemNewErrorLogEntry, object: playerItem) - center.addObserver(self, selector:#selector(self.failedToPlayToEndTime), name: .AVPlayerItemFailedToPlayToEndTime, object: playerItem) - } - - func setupTimer() { - timer?.invalidate() - timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(playerTimerAction), userInfo: nil, repeats: true) - timer?.fireDate = Date() - } - - // MARK: - 计时器事件 - @objc fileprivate func playerTimerAction() { - guard let playerItem = playerItem else { return } - - if playerItem.duration.timescale != 0 { - let currentTime = CMTimeGetSeconds(self.player!.currentTime()) - let totalTime = TimeInterval(playerItem.duration.value) / TimeInterval(playerItem.duration.timescale) - delegate?.bmPlayer(player: self, playTimeDidChange: currentTime, totalTime: totalTime) - } - updateStatus(includeLoading: true) - } - - // Observe If AVPlayerItem.status Changed to Fail - func obsrveValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { - if let player: AVPlayer = object as? AVPlayer { - if (keyPath == #keyPath(AVPlayer.currentItem.status)) { - let newStatus: AVPlayerItem.Status - if let newStatusAsNumber = change?[NSKeyValueChangeKey.newKey] as? NSNumber { - newStatus = AVPlayerItem.Status(rawValue: newStatusAsNumber.intValue)! - } else { - newStatus = .unknown - } - if newStatus == .failed { - NSLog("Error: \(String(describing: self.player?.currentItem?.error?.localizedDescription)), error: \(String(describing: self.player?.currentItem?.error))") - } - } - } - } - - fileprivate func updateStatus(includeLoading: Bool = false) { - if let player = player { - if let playerItem = playerItem, includeLoading { - if playerItem.isPlaybackLikelyToKeepUp || playerItem.isPlaybackBufferFull { - self.state = .bufferFinished - } else if playerItem.status == .failed { - self.state = .error - } else { - self.state = .buffering - } - } - if player.rate == 0.0 { - if player.error != nil { - self.state = .error - return - } - if let currentItem = player.currentItem { - if player.currentTime() >= currentItem.duration { - moviePlayDidEnd() - return - } - if currentItem.isPlaybackLikelyToKeepUp || currentItem.isPlaybackBufferFull { - - } - } - } - } - } - - // MARK: - Notification Event - @objc fileprivate func moviePlayDidEnd() { - if state != .playedToTheEnd { - if let playerItem = playerItem { - delegate?.bmPlayer(player: self, - playTimeDidChange: CMTimeGetSeconds(playerItem.duration), - totalTime: CMTimeGetSeconds(playerItem.duration)) - } - - self.state = .playedToTheEnd - self.isPlaying = false - self.playDidEnd = true - self.timer?.invalidate() - } - } - - // MARK: - KVO - override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { - if let item = object as? AVPlayerItem, let keyPath = keyPath { - if item == self.playerItem { - switch keyPath { - case "status": - if item.status == .failed || player?.status == AVPlayer.Status.failed { - self.state = .error - print(item.error) - } else if player?.status == AVPlayer.Status.readyToPlay { - self.state = .buffering - if shouldSeekTo > 0 { - seek(to: shouldSeekTo, completion: { [weak self] in - self?.shouldSeekTo = 0 - self?.hasReadyToPlay = true - self?.state = .readyToPlay - }) - } else { - self.hasReadyToPlay = true - self.state = .readyToPlay - } - } - - case "loadedTimeRanges": - // 计算缓冲进度 - if let timeInterVarl = self.availableDuration() { - let duration = item.duration - let totalDuration = CMTimeGetSeconds(duration) - delegate?.bmPlayer(player: self, loadedTimeDidChange: timeInterVarl, totalDuration: totalDuration) - } - - case "playbackBufferEmpty": - // 当缓冲是空的时候 - if self.playerItem!.isPlaybackBufferEmpty { - self.state = .buffering - self.bufferingSomeSecond() - } - case "playbackLikelyToKeepUp": - if item.isPlaybackBufferEmpty { - if state != .bufferFinished && hasReadyToPlay { - self.state = .bufferFinished - self.playDidEnd = true - } - } - default: - break - } - } - } - - if keyPath == "rate" { - updateStatus() - } - } - - /** - 缓冲进度 - - - returns: 缓冲进度 - */ - fileprivate func availableDuration() -> TimeInterval? { - if let loadedTimeRanges = player?.currentItem?.loadedTimeRanges, - let first = loadedTimeRanges.first { - - let timeRange = first.timeRangeValue - let startSeconds = CMTimeGetSeconds(timeRange.start) - let durationSecound = CMTimeGetSeconds(timeRange.duration) - let result = startSeconds + durationSecound - return result - } - return nil - } - - /** - 缓冲比较差的时候 - */ - fileprivate func bufferingSomeSecond() { - print("buffering some second") - self.state = .buffering - // playbackBufferEmpty会反复进入,因此在bufferingOneSecond延时播放执行完之前再调用bufferingSomeSecond都忽略 - - if isBuffering { - return - } - isBuffering = true - // 需要先暂停一小会之后再播放,否则网络状况不好的时候时间在走,声音播放不出来 - player?.pause() - let popTime = DispatchTime.now() + Double(Int64( Double(NSEC_PER_SEC) * 1.0 )) / Double(NSEC_PER_SEC) - - DispatchQueue.main.asyncAfter(deadline: popTime) {[weak self] in - guard let `self` = self else { return } - // 如果执行了play还是没有播放则说明还没有缓存好,则再次缓存一段时间 - self.isBuffering = false - if let item = self.playerItem { - if !item.isPlaybackLikelyToKeepUp { - self.bufferingSomeSecond() - } else { - // 如果此时用户已经暂停了,则不再需要开启播放了 - self.state = BMPlayerState.bufferFinished - } - } - } - } - - @objc fileprivate func connectPlayerLayer() { - playerLayer?.removeFromSuperlayer() - playerLayer = AVPlayerLayer(player: player) - playerLayer!.videoGravity = videoGravity - - layer.addSublayer(playerLayer!) - } - - @objc fileprivate func disconnectPlayerLayer() { - playerLayer?.removeFromSuperlayer() - playerLayer = nil - } -} - diff --git a/kplayer/video/BMPlayerManager.swift b/kplayer/video/BMPlayerManager.swift deleted file mode 100644 index 03fa08c..0000000 --- a/kplayer/video/BMPlayerManager.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// BMPlayerManager.swift -// Pods -// -// Created by BrikerMan on 16/5/21. -// -// -import UIKit -import AVFoundation -import NVActivityIndicatorView - -public let BMPlayerConf = BMPlayerManager.shared - -public enum BMPlayerTopBarShowCase: Int { - case always = 0 /// 始终显示 - case horizantalOnly = 1 /// 只在横屏界面显示 - case none = 2 /// 不显示 -} - -open class BMPlayerManager { - /// 单例 - public static let shared = BMPlayerManager() - - /// tint color - open var tintColor = UIColor.white - - /// Loader - open var loaderType = NVActivityIndicatorType.ballRotateChase - - /// should auto play - open var shouldAutoPlay = true - - open var topBarShowInCase = BMPlayerTopBarShowCase.always - - open var animateDelayTimeInterval = TimeInterval(100) - - /// should show log - open var allowLog = false - - /// use gestures to set brightness, volume and play position - open var enableBrightnessGestures = true - open var enableVolumeGestures = true - open var enablePlaytimeGestures = true - open var enablePlayControlGestures = true - - open var enableChooseDefinition = true - - internal static func asset(for resouce: BMPlayerResourceDefinition) -> AVURLAsset { - return AVURLAsset(url: resouce.url, options: resouce.options) - } - - /** - 打印log - - - parameter info: log信息 - */ - func log(_ info:String) { - if allowLog { - print(info) - } - } -} \ No newline at end of file diff --git a/kplayer/video/BMPlayerProtocols.swift b/kplayer/video/BMPlayerProtocols.swift deleted file mode 100644 index 3a07da6..0000000 --- a/kplayer/video/BMPlayerProtocols.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// BMPlayerProtocols.swift -// Pods -// -// Created by BrikerMan on 16/4/30. -// -// - -import UIKit - -extension BMPlayerControlView { - public enum ButtonType: Int { - case play = 101 - case pause = 102 - case back = 103 - case fullscreen = 105 - case replay = 106 - } -} - -extension BMPlayer { - static func formatSecondsToString(_ seconds: TimeInterval) -> String { - if seconds.isNaN { - return "00:00" - } - let min = Int(seconds / 60) - let sec = Int(seconds.truncatingRemainder(dividingBy: 60)) - return String(format: "%02d:%02d", min, sec) - } -} diff --git a/kplayer/video/BMSubtitles.swift b/kplayer/video/BMSubtitles.swift deleted file mode 100644 index 26b0ffc..0000000 --- a/kplayer/video/BMSubtitles.swift +++ /dev/null @@ -1,122 +0,0 @@ -// -// BMSubtitles.swift -// Pods -// -// Created by BrikerMan on 2017/4/2. -// -// - -import Foundation - -public class BMSubtitles { - public var groups: [Group] = [] - /// subtitles delay, positive:fast, negative:forward - public var delay: TimeInterval = 0 - - public struct Group: CustomStringConvertible { - var index: Int - var start: TimeInterval - var end : TimeInterval - var text : String - - init(_ index: Int, _ start: NSString, _ end: NSString, _ text: NSString) { - self.index = index - self.start = Group.parseDuration(start as String) - self.end = Group.parseDuration(end as String) - self.text = text as String - } - - static func parseDuration(_ fromStr:String) -> TimeInterval { - var h: TimeInterval = 0.0, m: TimeInterval = 0.0, s: TimeInterval = 0.0, c: TimeInterval = 0.0 - let scanner = Scanner(string: fromStr) - scanner.scanDouble(&h) - scanner.scanString(":", into: nil) - scanner.scanDouble(&m) - scanner.scanString(":", into: nil) - scanner.scanDouble(&s) - scanner.scanString(",", into: nil) - scanner.scanDouble(&c) - return (h * 3600.0) + (m * 60.0) + s + (c / 1000.0) - } - - public var description: String { - return "Subtile Group ==========\nindex : \(index),\nstart : \(start)\nend :\(end)\ntext :\(text)" - } - } - - public init(url: URL, encoding: String.Encoding? = nil) { - DispatchQueue.global(qos: .background).async {[weak self] in - do { - let string: String - if let encoding = encoding { - string = try String(contentsOf: url, encoding: encoding) - } else { - string = try String(contentsOf: url) - } - self?.groups = BMSubtitles.parseSubRip(string) ?? [] - } catch { - print("| BMPlayer | [Error] failed to load \(url.absoluteString) \(error.localizedDescription)") - } - } - } - - /** - Search for target group for time - - - parameter time: target time - - - returns: result group or nil - */ - public func search(for time: TimeInterval) -> Group? { - let result = groups.first(where: { group -> Bool in - if group.start - delay <= time && group.end - delay >= time { - return true - } - return false - }) - return result - } - - /** - Parse str string into Group Array - - - parameter payload: target string - - - returns: result group - */ - fileprivate static func parseSubRip(_ payload: String) -> [Group]? { - var groups: [Group] = [] - let scanner = Scanner(string: payload) - while !scanner.isAtEnd { - var indexString: NSString? - scanner.scanUpToCharacters(from: .newlines, into: &indexString) - - var startString: NSString? - scanner.scanUpTo(" --> ", into: &startString) - - // skip spaces and newlines by default. - scanner.scanString("-->", into: nil) - - var endString: NSString? - scanner.scanUpToCharacters(from: .newlines, into: &endString) - - var textString: NSString? - scanner.scanUpTo("\r\n\r\n", into: &textString) - - if let text = textString { - textString = text.trimmingCharacters(in: .whitespaces) as NSString - textString = text.replacingOccurrences(of: "\r", with: "") as NSString - } - - if let indexString = indexString, - let index = Int(indexString as String), - let start = startString, - let end = endString, - let text = textString { - let group = Group(index, start, end, text) - groups.append(group) - } - } - return groups - } -} diff --git a/kplayer/video/BMTimeSlider.swift b/kplayer/video/BMTimeSlider.swift deleted file mode 100644 index 1920fe9..0000000 --- a/kplayer/video/BMTimeSlider.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// BMTimeSlider.swift -// Pods -// -// Created by BrikerMan on 2017/4/2. -// -// - -import UIKit - -public class BMTimeSlider: UISlider { - override open func trackRect(forBounds bounds: CGRect) -> CGRect { - let trackHeight: CGFloat = 2 - let position = CGPoint(x: 0, y: 14) - let customBounds = CGRect(origin: position, size: CGSize(width: bounds.size.width, height: trackHeight)) - super.trackRect(forBounds: customBounds) - return customBounds - } - - override open func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect { - let rect = super.thumbRect(forBounds: bounds, trackRect: rect, value: value) - let newx = rect.origin.x - 10 - let newRect = CGRect(x: newx, y: 0, width: 30, height: 30) - return newRect - } -} diff --git a/kplayer/video/KVideoPlayer.swift b/kplayer/video/KVideoPlayer.swift deleted file mode 100644 index 7449a78..0000000 --- a/kplayer/video/KVideoPlayer.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Created by Marco Schmickler on 14.11.21. -// Copyright (c) 2021 Marco Schmickler. All rights reserved. -// - - -import SwiftUI -import AVKit - -struct KVideoPlayer: View { - private let player = AVPlayer(url: URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!) - - var body: some View { - VideoPlayer(player: player) - .onAppear() { - // Start the player going, otherwise controls don't appear - player.play() - } - .onDisappear() { - // Stop the player when the view disappears - player.pause() - } - } -} - -struct KVideoPlayer_Previews: PreviewProvider { - static var previews: some View { - KVideoPlayer() - } -}