Browse Source

Photo

master
Marco Schmickler 11 years ago
parent
commit
1d0652a0e8
  1. 74
      kplayer.xcodeproj/project.pbxproj
  2. 13
      kplayer/AppDelegate.swift
  3. 2
      kplayer/Base.lproj/Main.storyboard
  4. 28
      kplayer/core/MediaItem.swift
  5. 106
      kplayer/core/NetworkManager.swift
  6. 116
      kplayer/detail/DetailViewController.swift
  7. 5
      kplayer/detail/ItemCell.swift
  8. 5
      kplayer/detail/VideoPlayerController.swift
  9. 1419
      kplayer/exswift/Array.swift
  10. 18
      kplayer/exswift/Bool.swift
  11. 21
      kplayer/exswift/Character.swift
  12. 421
      kplayer/exswift/Dictionary.swift
  13. 93
      kplayer/exswift/Double.swift
  14. 19
      kplayer/exswift/ExSwift.h
  15. 282
      kplayer/exswift/ExSwift.swift
  16. 83
      kplayer/exswift/Float.swift
  17. 256
      kplayer/exswift/Int.swift
  18. 64
      kplayer/exswift/NSArray.swift
  19. 318
      kplayer/exswift/NSDate.swift
  20. 80
      kplayer/exswift/Range.swift
  21. 244
      kplayer/exswift/Sequence.swift
  22. 403
      kplayer/exswift/String.swift
  23. 106
      kplayer/master/MasterViewController.swift
  24. 155
      kplayer/photo/MediaPhotoController.swift
  25. 32
      kplayer/util/HanekeFetchOperation.swift
  26. 46
      kplayer/util/ImageLoadOperation.swift
  27. 28
      kplayer/util/alamoimage.swift

74
kplayer.xcodeproj/project.pbxproj

@ -7,20 +7,36 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1C7361B71E73ECBE5891B755 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73649A4ADDAAAED634F537 /* Dictionary.swift */; };
1C7361F0F80FEC5B72946923 /* Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73605289164DF119E60720 /* Array.swift */; };
1C73626E34BA4D64ACF94AE5 /* alamoimage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C60C423AE87B8D0F22A /* alamoimage.swift */; };
1C73631EACF56BABD3B2BCFB /* LayoutTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736BC4450890C45F8FBC63 /* LayoutTools.swift */; }; 1C73631EACF56BABD3B2BCFB /* LayoutTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736BC4450890C45F8FBC63 /* LayoutTools.swift */; };
1C7363402AB2B0E5CA0B35BF /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365A537608EDDE897BF7C /* Float.swift */; };
1C73635138BBD2BB480A308F /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C736777456388CA571DA17B /* MediaPlayer.framework */; }; 1C73635138BBD2BB480A308F /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C736777456388CA571DA17B /* MediaPlayer.framework */; };
1C7363D241B56AEE78D82FAD /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73666529EEEBD464F193CD /* Sequence.swift */; };
1C7363D9DC8F9D1F866DE935 /* Kirschkeks-256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C7368DC7EF11A553145E169 /* Kirschkeks-256x256.png */; }; 1C7363D9DC8F9D1F866DE935 /* Kirschkeks-256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C7368DC7EF11A553145E169 /* Kirschkeks-256x256.png */; };
1C73640D928DE56D35175D39 /* UploadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736260E748CF136FF37EA7 /* UploadOperation.swift */; }; 1C73640D928DE56D35175D39 /* UploadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736260E748CF136FF37EA7 /* UploadOperation.swift */; };
1C73646F87B495A47D7943C7 /* NetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369EC16B19B32B515169E /* NetData.swift */; }; 1C73646F87B495A47D7943C7 /* NetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369EC16B19B32B515169E /* NetData.swift */; };
1C7364F64DCE93FCF4671D98 /* Character.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369BCA71AAF64F874F946 /* Character.swift */; };
1C736503B656C999E5E12081 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */; }; 1C736503B656C999E5E12081 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */; };
1C73654C9EA6D255CFC039C5 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */; }; 1C73654C9EA6D255CFC039C5 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */; };
1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */; }; 1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */; };
1C73677CD719D0F82D144BF6 /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C43137E3B8391E5F07B /* Bool.swift */; };
1C7368364397315E12E90F05 /* VideoPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7367379DEE94EBF3FAFA78 /* VideoPlayerController.swift */; }; 1C7368364397315E12E90F05 /* VideoPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7367379DEE94EBF3FAFA78 /* VideoPlayerController.swift */; };
1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */; }; 1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */; };
1C73689C7E6A25E758B16C54 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73653A9EBCC466FD4E3DA6 /* String.swift */; };
1C73693A1334A7792856FC58 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73611D226B48C24DB37535 /* MasterViewController.swift */; }; 1C73693A1334A7792856FC58 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73611D226B48C24DB37535 /* MasterViewController.swift */; };
1C7369ABC44CFB530EA71FB6 /* HeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */; }; 1C7369ABC44CFB530EA71FB6 /* HeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */; };
1C7369C330F1AB1E4F166050 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736E7B8BAD989DC544088E /* Range.swift */; };
1C736A88E2CF46197FAE3160 /* NSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360E65B741C57C034FC7C /* NSDate.swift */; };
1C736C5DD23466269607E07F /* alamojson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73618272969871601AB817 /* alamojson.swift */; }; 1C736C5DD23466269607E07F /* alamojson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73618272969871601AB817 /* alamojson.swift */; };
1C736C5EA9EEFF40AD42CA60 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736BCC6787411AA435D1E6 /* Double.swift */; };
1C736C885C8EE7CFBF3B8DC3 /* ExSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365E164CCEDB0A9FDF7FA /* ExSwift.swift */; };
1C736C9C89BABC38C80025FE /* Int.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7368956B34717DAFC35EFF /* Int.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 */; }; 1C736D24B49451141CD4B64D /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */; };
1C736F3BC10D1A5ECEA50A30 /* NSArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DB8164E3EF18FA6F28D /* NSArray.swift */; };
1C736F6A223D4ADB2E1BA733 /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736069C214E9522BB1BD97 /* ItemCell.swift */; }; 1C736F6A223D4ADB2E1BA733 /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736069C214E9522BB1BD97 /* ItemCell.swift */; };
1C736FB92B19FE17E4357C85 /* MediaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73688DAB88F9360FB62A49 /* MediaItem.swift */; }; 1C736FB92B19FE17E4357C85 /* MediaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73688DAB88F9360FB62A49 /* MediaItem.swift */; };
A5D637AE4588AAB5DC1CBC6B /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 127AC1F28342F9AAE3CEC5C2 /* Pods.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; A5D637AE4588AAB5DC1CBC6B /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 127AC1F28342F9AAE3CEC5C2 /* Pods.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
@ -44,22 +60,39 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
127AC1F28342F9AAE3CEC5C2 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 127AC1F28342F9AAE3CEC5C2 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1C73605289164DF119E60720 /* Array.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = "<group>"; };
1C736069C214E9522BB1BD97 /* ItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = "<group>"; }; 1C736069C214E9522BB1BD97 /* ItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = "<group>"; };
1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HanekeFetchOperation.swift; sourceTree = "<group>"; };
1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageLoadOperation.swift; sourceTree = "<group>"; };
1C7360E65B741C57C034FC7C /* NSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDate.swift; sourceTree = "<group>"; };
1C7361024E8CCBDE9C052658 /* ExSwift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExSwift.h; sourceTree = "<group>"; };
1C73611D226B48C24DB37535 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = "<group>"; }; 1C73611D226B48C24DB37535 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = "<group>"; };
1C73618272969871601AB817 /* alamojson.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = alamojson.swift; sourceTree = "<group>"; }; 1C73618272969871601AB817 /* alamojson.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = alamojson.swift; sourceTree = "<group>"; };
1C73620D01687FB4F1811C5C /* NetworkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkHelper.swift; sourceTree = "<group>"; }; 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkHelper.swift; sourceTree = "<group>"; };
1C736260E748CF136FF37EA7 /* UploadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadOperation.swift; sourceTree = "<group>"; }; 1C736260E748CF136FF37EA7 /* UploadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadOperation.swift; sourceTree = "<group>"; };
1C73649A4ADDAAAED634F537 /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; };
1C73653A9EBCC466FD4E3DA6 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
1C7365A537608EDDE897BF7C /* Float.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Float.swift; sourceTree = "<group>"; };
1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; }; 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; };
1C7365E164CCEDB0A9FDF7FA /* ExSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExSwift.swift; sourceTree = "<group>"; };
1C73666529EEEBD464F193CD /* Sequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sequence.swift; sourceTree = "<group>"; };
1C7367379DEE94EBF3FAFA78 /* VideoPlayerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoPlayerController.swift; sourceTree = "<group>"; }; 1C7367379DEE94EBF3FAFA78 /* VideoPlayerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoPlayerController.swift; sourceTree = "<group>"; };
1C73673DC671535E3A049F54 /* MediaPhotoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaPhotoController.swift; sourceTree = "<group>"; }; 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaPhotoController.swift; sourceTree = "<group>"; };
1C736777456388CA571DA17B /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 1C736777456388CA571DA17B /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
1C73688DAB88F9360FB62A49 /* MediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaItem.swift; sourceTree = "<group>"; }; 1C73688DAB88F9360FB62A49 /* MediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaItem.swift; sourceTree = "<group>"; };
1C7368956B34717DAFC35EFF /* Int.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Int.swift; sourceTree = "<group>"; };
1C7368DC7EF11A553145E169 /* Kirschkeks-256x256.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Kirschkeks-256x256.png"; sourceTree = "<group>"; }; 1C7368DC7EF11A553145E169 /* Kirschkeks-256x256.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Kirschkeks-256x256.png"; sourceTree = "<group>"; };
1C7369BCA71AAF64F874F946 /* Character.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Character.swift; sourceTree = "<group>"; };
1C7369EC16B19B32B515169E /* NetData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetData.swift; sourceTree = "<group>"; }; 1C7369EC16B19B32B515169E /* NetData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetData.swift; sourceTree = "<group>"; };
1C7369F53095B7A4D65679C2 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; }; 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
1C736BC4450890C45F8FBC63 /* LayoutTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutTools.swift; sourceTree = "<group>"; }; 1C736BC4450890C45F8FBC63 /* LayoutTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutTools.swift; sourceTree = "<group>"; };
1C736BCC6787411AA435D1E6 /* Double.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
1C736C43137E3B8391E5F07B /* Bool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bool.swift; sourceTree = "<group>"; };
1C736C60C423AE87B8D0F22A /* alamoimage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = alamoimage.swift; sourceTree = "<group>"; };
1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderCell.swift; sourceTree = "<group>"; }; 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderCell.swift; sourceTree = "<group>"; };
1C736DB8164E3EF18FA6F28D /* NSArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSArray.swift; sourceTree = "<group>"; };
1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = "<group>"; }; 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = "<group>"; };
1C736E7B8BAD989DC544088E /* Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Range.swift; sourceTree = "<group>"; };
5C6CBA548F885BF342F594EA /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; }; 5C6CBA548F885BF342F594EA /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
A170BFB886D61D57F7009BFC /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; }; A170BFB886D61D57F7009BFC /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
C98AF5CF1B124D6A00D196CC /* kplayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = kplayer.app; sourceTree = BUILT_PRODUCTS_DIR; }; C98AF5CF1B124D6A00D196CC /* kplayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = kplayer.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -121,6 +154,27 @@
path = master; path = master;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
1C73654BC4A499E5D104B61F /* exswift */ = {
isa = PBXGroup;
children = (
1C7369BCA71AAF64F874F946 /* Character.swift */,
1C736C43137E3B8391E5F07B /* Bool.swift */,
1C736DB8164E3EF18FA6F28D /* NSArray.swift */,
1C736BCC6787411AA435D1E6 /* Double.swift */,
1C73653A9EBCC466FD4E3DA6 /* String.swift */,
1C7361024E8CCBDE9C052658 /* ExSwift.h */,
1C7368956B34717DAFC35EFF /* Int.swift */,
1C7365A537608EDDE897BF7C /* Float.swift */,
1C7360E65B741C57C034FC7C /* NSDate.swift */,
1C73666529EEEBD464F193CD /* Sequence.swift */,
1C7365E164CCEDB0A9FDF7FA /* ExSwift.swift */,
1C73649A4ADDAAAED634F537 /* Dictionary.swift */,
1C736E7B8BAD989DC544088E /* Range.swift */,
1C73605289164DF119E60720 /* Array.swift */,
);
path = exswift;
sourceTree = "<group>";
};
1C7365603CAE04E39B73D843 /* util */ = { 1C7365603CAE04E39B73D843 /* util */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -130,6 +184,9 @@
1C736260E748CF136FF37EA7 /* UploadOperation.swift */, 1C736260E748CF136FF37EA7 /* UploadOperation.swift */,
1C7369EC16B19B32B515169E /* NetData.swift */, 1C7369EC16B19B32B515169E /* NetData.swift */,
1C73618272969871601AB817 /* alamojson.swift */, 1C73618272969871601AB817 /* alamojson.swift */,
1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */,
1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */,
1C736C60C423AE87B8D0F22A /* alamoimage.swift */,
); );
path = util; path = util;
sourceTree = "<group>"; sourceTree = "<group>";
@ -196,6 +253,7 @@
1C73615846EE8B07DAAFD230 /* detail */, 1C73615846EE8B07DAAFD230 /* detail */,
1C7364808E72BFA7575E75E1 /* master */, 1C7364808E72BFA7575E75E1 /* master */,
1C7363B608460DED4F522D1C /* photo */, 1C7363B608460DED4F522D1C /* photo */,
1C73654BC4A499E5D104B61F /* exswift */,
); );
path = kplayer; path = kplayer;
sourceTree = "<group>"; sourceTree = "<group>";
@ -393,6 +451,22 @@
1C736C5DD23466269607E07F /* alamojson.swift in Sources */, 1C736C5DD23466269607E07F /* alamojson.swift in Sources */,
1C73693A1334A7792856FC58 /* MasterViewController.swift in Sources */, 1C73693A1334A7792856FC58 /* MasterViewController.swift in Sources */,
1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */, 1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */,
1C7364F64DCE93FCF4671D98 /* Character.swift in Sources */,
1C73677CD719D0F82D144BF6 /* Bool.swift in Sources */,
1C736F3BC10D1A5ECEA50A30 /* NSArray.swift in Sources */,
1C736C5EA9EEFF40AD42CA60 /* Double.swift in Sources */,
1C73689C7E6A25E758B16C54 /* String.swift in Sources */,
1C736C9C89BABC38C80025FE /* Int.swift in Sources */,
1C7363402AB2B0E5CA0B35BF /* Float.swift in Sources */,
1C736A88E2CF46197FAE3160 /* NSDate.swift in Sources */,
1C7363D241B56AEE78D82FAD /* Sequence.swift in Sources */,
1C736C885C8EE7CFBF3B8DC3 /* ExSwift.swift in Sources */,
1C7361B71E73ECBE5891B755 /* Dictionary.swift in Sources */,
1C7369C330F1AB1E4F166050 /* Range.swift in Sources */,
1C7361F0F80FEC5B72946923 /* Array.swift in Sources */,
1C736D16E81BA1FB325200E0 /* HanekeFetchOperation.swift in Sources */,
1C736D24891597F2728230EE /* ImageLoadOperation.swift in Sources */,
1C73626E34BA4D64ACF94AE5 /* alamoimage.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

13
kplayer/AppDelegate.swift

@ -24,6 +24,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController
let controller = masterNavigationController.topViewController as! MasterViewController let controller = masterNavigationController.topViewController as! MasterViewController
controller.items = [
MediaItem(name: "fav", path:"fav", root: "/srv/samba/ren/fav", type: ItemType.ROOT),
MediaItem(name: "knk_archiv", path:"knk_archiv", root: "/srv/samba/ren/knk_archiv", type: ItemType.ROOT),
MediaItem(name: "knk_archiv2", path:"knk_archiv2", root: "/srv/samba/ren/knk_archiv2", type: ItemType.ROOT),
MediaItem(name: "knk_archiv3", path:"knk_archiv3", root: "/srv/samba/ren/knk_archiv3", type: ItemType.ROOT),
MediaItem(name: "knk_archiv4", path:"knk_archiv4", root: "/srv/samba/ren/knk_archiv4", type: ItemType.ROOT),
MediaItem(name: "sp", path:"sp", root: "/srv/samba/ren/sp", type: ItemType.ROOT),
MediaItem(name: "fjoy", path:"fjoy", root: "/srv/samba/ren/fjoy", type: ItemType.ROOT),
MediaItem(name: "heg", path:"heg", root: "/srv/samba/ren/heg", type: ItemType.ROOT),
MediaItem(name: "ten", path:"ten", root: "/srv/samba/ren/ten", type: ItemType.ROOT)
]
return true return true
} }

2
kplayer/Base.lproj/Main.storyboard

@ -131,7 +131,7 @@
<!--Master--> <!--Master-->
<scene sceneID="smW-Zh-WAh"> <scene sceneID="smW-Zh-WAh">
<objects> <objects>
<tableViewController title="Master" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="MasterViewController" customModule="kplayer" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController storyboardIdentifier="mastertable" title="Master" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="MasterViewController" customModule="kplayer" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="r7i-6Z-zg0"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="r7i-6Z-zg0">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>

28
kplayer/core/MediaItem.swift

@ -7,8 +7,10 @@ import Foundation
import UIKit import UIKit
enum ItemType : String, Printable { enum ItemType : String, Printable {
case ROOT = "root"
case FOLDER = "folder" case FOLDER = "folder"
case VIDEO = "video" case VIDEO = "video"
case PICS = "pics"
case SNAPSHOT = "snapshot" case SNAPSHOT = "snapshot"
var description: String { var description: String {
@ -33,25 +35,32 @@ class MediaItem : DebugPrintable {
var loaded = false var loaded = false
var featured = true var featured = true
var sortName = ""
init(name: String, path: String, root: String, type: ItemType) { init(name: String, path: String, root: String, type: ItemType) {
self.name = name self.name = name
self.path = path self.path = path
self.root = root self.root = root
self.type = type self.type = type
children = [MediaItem]() children = [MediaItem]()
sortName = computeSortName(name)
} }
var sortName: String {
var sortName = name.stringByReplacingOccurrencesOfString("full", withString: "")
func computeSortName(sname: String) -> String {
var lsortName = sname.stringByReplacingOccurrencesOfString("full", withString: "")
var fullNameArr = split(sortName) {$0 == "_"} var fullNameArr = split(sortName) {$0 == "_"}
println (lsortName)
if !fullNameArr.isEmpty {
lsortName = fullNameArr[0]
}
sortName = fullNameArr[0]
while count(sortName) < 6 {
sortName = "0" + sortName
while count(lsortName) < 6 {
lsortName = "0" + lsortName
} }
return sortName
return lsortName
} }
var thumbPath: String { var thumbPath: String {
@ -67,7 +76,8 @@ class MediaItem : DebugPrintable {
} }
var imageUrlAbsolute: String { var imageUrlAbsolute: String {
let imageUrl = thumbUrl!.stringByReplacingOccurrencesOfString("_thumb.jpg", withString: ".jpg")
var imageUrl = thumbUrl!.stringByReplacingOccurrencesOfString("_thumb.jpg", withString: ".jpg")
imageUrl = imageUrl.stringByReplacingOccurrencesOfString("?preview=true", withString: "")
return NetworkManager.sharedInstance.baseurl + "/service/download" + imageUrl return NetworkManager.sharedInstance.baseurl + "/service/download" + imageUrl
} }
@ -78,6 +88,6 @@ class MediaItem : DebugPrintable {
} }
var debugDescription: String { var debugDescription: String {
return root + " " + path + " " + name
return "\(type): \(root) \(path) \(name) (\(index)) Child count \(count(children))"
} }
} }

106
kplayer/core/NetworkManager.swift

@ -10,7 +10,7 @@ import SwiftyJSON
class NetworkManager { class NetworkManager {
static let sharedInstance = NetworkManager() static let sharedInstance = NetworkManager()
let baseurl = "http://linkstation/tomcat/media"
let baseurl = "http://linkstation.local/tomcat/media"
lazy var operationQueue: NSOperationQueue = { lazy var operationQueue: NSOperationQueue = {
var queue = NSOperationQueue() var queue = NSOperationQueue()
@ -45,10 +45,10 @@ class NetworkManager {
} }
func loadDirs(root: String, completionHandler: ([MediaItem]) -> Void) -> Void { func loadDirs(root: String, completionHandler: ([MediaItem]) -> Void) -> Void {
let url = baseurl + "/service/listvideos" + root
let url1 = baseurl + "/service/listvideos" + root
let len = count(root) let len = count(root)
var res = [MediaItem]() var res = [MediaItem]()
let url = (url1 as NSString).stringByReplacingOccurrencesOfString(" ", withString: "+")
println(url) println(url)
Alamofire.request(.GET, url).responseSwiftyJSON({ Alamofire.request(.GET, url).responseSwiftyJSON({
@ -59,7 +59,7 @@ class NetworkManager {
for (a, c) in json { for (a, c) in json {
// let (a,b) = j # // let (a,b) = j #
let s = c.object as! String let s = c.object as! String
println(s)
if s.hasSuffix(".mp4") || s.hasSuffix(".m4v") { if s.hasSuffix(".mp4") || s.hasSuffix(".m4v") {
let l = count(s) let l = count(s)
let name = (s as NSString).lastPathComponent let name = (s as NSString).lastPathComponent
@ -85,10 +85,70 @@ class NetworkManager {
}) })
} }
func loadPicDirs(root: String, completionHandler: ([MediaItem]) -> Void) -> Void {
let url1 = baseurl + "/service/listpicdirs" + root
let len = count(root)
var res = [MediaItem]()
let url = (url1 as NSString).stringByReplacingOccurrencesOfString(" ", withString: "+")
println(url)
Alamofire.request(.GET, url).responseSwiftyJSON({
(request, response, json, error) in
var hashes = NSMutableSet()
var items = Dictionary<String, MediaItem>()
for (a, c) in json {
// let (a,b) = j #
let s = c.object as! String
println(s)
if s.hasSuffix(".jpg") {
let l = count(s)
let name = (s as NSString).lastPathComponent
var pathlen = l - len - count(name)
// if (pathlen > 1000) {
println(pathlen)
println(name)
println(s)
// }
if (pathlen < 2) {
pathlen = 2
}
let path = (s as NSString).substringWithRange(NSMakeRange(len + 1, pathlen - 2))
let folderName = path.lastPathComponent
let fl = count(path)
let pfl = fl - count(folderName)
println ("\(folderName) \(pfl)")
let fpath = (path as NSString).substringWithRange(NSMakeRange(0, pfl))
let i = MediaItem(name: folderName, path: fpath, root: root, type: ItemType.PICS)
i.thumbUrl = "\(s)?preview=true"
if !name.hasPrefix(".") {
if let picfolder = items[path] {
picfolder.children.append(i)
}
else {
let iff = MediaItem(name: folderName, path: fpath, root: root, type: ItemType.PICS)
items[path] = iff
res.append(iff)
iff.children.append(i)
}
}
}
}
completionHandler(res)
})
}
func loadDir(root: String, completionHandler: ([MediaItem]) -> Void) -> Void { func loadDir(root: String, completionHandler: ([MediaItem]) -> Void) -> Void {
var itemsArray = []; var itemsArray = [];
Alamofire.request(.GET, baseurl + "/service/dirs" + root)
let url = (root as NSString).stringByReplacingOccurrencesOfString(" ", withString: "+")
Alamofire.request(.GET, baseurl + "/service/dirs" + url)
.responseString { .responseString {
(_, _, string, _) in (_, _, string, _) in
let f = split(string!) { let f = split(string!) {
@ -115,8 +175,35 @@ class NetworkManager {
} }
} }
func listDirs(root: String, completionHandler: ([MediaItem]) -> Void) -> Void {
var itemsArray = [];
let len = count(root)
let url = (root as NSString).stringByReplacingOccurrencesOfString(" ", withString: "+")
let ux = baseurl + "/service/listdirs" + url
println (ux)
Alamofire.request(.GET, ux)
.responseSwiftyJSON({
(request, response, json, error) in
var res = [MediaItem]()
for (a, c) in json {
println (c.object)
// let (a,b) = j #
let s = (c.object as! NSString).substringFromIndex(len+1)
println (s)
let i = MediaItem(name: s, path: s, root: root, type: ItemType.FOLDER)
res.append(i)
}
completionHandler(res)
})
}
func playerURL(item: MediaItem) -> String { func playerURL(item: MediaItem) -> String {
let enc = item.name // .stringByReplacingOccurrencesOfString(" ", withString: "+")
let enc = item.name.stringByReplacingOccurrencesOfString(" ", withString: "%20")
return baseurl + "/service/stream" + item.root + "/" + item.path + "/" + enc return baseurl + "/service/stream" + item.root + "/" + item.path + "/" + enc
} }
@ -129,6 +216,8 @@ class NetworkManager {
return return
} }
// Alamofire.Manager.sharedInstance.session.invalidateAndCancel()
var j = 0 var j = 0
for i in item.children { for i in item.children {
loadItem(i, index: j) loadItem(i, index: j)
@ -193,7 +282,7 @@ class NetworkManager {
} }
item.loaded = true item.loaded = true
NSNotificationCenter.defaultCenter().postNotificationName("loadedItems", object: index)
NSNotificationCenter.defaultCenter().postNotificationName("loadedItems", object: item)
// println(error) // println(error)
}) })
} }
@ -236,8 +325,7 @@ class NetworkManager {
println(p) println(p)
if hashes.containsObject(pt) { if hashes.containsObject(pt) {
println("contained") println("contained")
}
else {
} else {
let imageData = UIImageJPEGRepresentation(c.image, 1.0); let imageData = UIImageJPEGRepresentation(c.image, 1.0);
let op = UploadOperation(baseUrl: self.baseurl + "/service/upload", data: imageData, path: p) let op = UploadOperation(baseUrl: self.baseurl + "/service/upload", data: imageData, path: p)
self.operationQueue.addOperation(op) self.operationQueue.addOperation(op)

116
kplayer/detail/DetailViewController.swift

@ -7,6 +7,7 @@
// //
import UIKit import UIKit
import Alamofire
class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
@ -17,6 +18,8 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
var currentItem: MediaItem? var currentItem: MediaItem?
var defaultItemSize = CGSize(width: (15 * 16) - 6, height: 15 * 9)
var detailItem: MediaItem? { var detailItem: MediaItem? {
didSet { didSet {
println(detailItem!.children) println(detailItem!.children)
@ -56,10 +59,18 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
override func loadView() { override func loadView() {
super.loadView() super.loadView()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("refreshItems:"), name: "loadedItems", object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("refreshItems:"), name: "loadedItems", object: nil)
} }
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self, name: "loadedItems", object: nil)
}
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
@ -68,7 +79,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
layout.sectionInset = UIEdgeInsets(top: 1, left: 0, bottom: 1, right: 0) layout.sectionInset = UIEdgeInsets(top: 1, left: 0, bottom: 1, right: 0)
layout.minimumInteritemSpacing = 0.0; layout.minimumInteritemSpacing = 0.0;
layout.itemSize = CGSize(width: (15 * 16) - 6, height: 15 * 9)
layout.itemSize = defaultItemSize
layout.headerReferenceSize = CGSize(width: 50, height: 50) layout.headerReferenceSize = CGSize(width: 50, height: 50)
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout) collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
@ -91,16 +102,50 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
lpgr.delaysTouchesBegan = true lpgr.delaysTouchesBegan = true
self.collectionView.addGestureRecognizer(lpgr); self.collectionView.addGestureRecognizer(lpgr);
let barbutton = UIBarButtonItem(barButtonSystemItem: .Action, target: self, action: Selector("overview"));
navigationItem.rightBarButtonItems = [barbutton]
if detailItem != nil {
println("Details \(detailItem!.children)")
}
}
func overview() {
let pc = MediaPhotoController()
var i = [MediaItem]()
for it in detailItem!.children {
for c in it.children {
i.append(c)
}
}
pc.items = i
pc.completionHandler = {
self.dismissViewControllerAnimated(true, completion: nil);
}
let navController = UINavigationController(rootViewController: pc) // Creating a navigation controller with pc at the root of the navigation stack.
presentViewController(navController, animated: false, completion: nil)
} }
func refreshItems(notification: NSNotification) { func refreshItems(notification: NSNotification) {
let index = notification.object as! Int
let i = notification.object as! MediaItem
let index = i.index
let oid = ObjectIdentifier(self)
if let detail: MediaItem = self.detailItem { if let detail: MediaItem = self.detailItem {
if (count(detail.children) > 100) {
self.collectionView.reloadData()
if i.parent! !== detail {
return
} }
else {
println ("Object: \(oid.hashValue) Index \(index) Item: \(i) Parent: \(i.parent) Detail: \(detailItem)")
// if (count(detail.children) > 100) {
// self.collectionView.reloadData()
// }
// else {
collectionView.performBatchUpdates({ collectionView.performBatchUpdates({
var newItems = [NSIndexPath]() var newItems = [NSIndexPath]()
var j = 0 var j = 0
@ -119,7 +164,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
} }
return return
}, completion: nil) }, completion: nil)
}
// }
} }
} }
@ -234,6 +279,65 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
self.currentItem = items self.currentItem = items
performSegueWithIdentifier("showVideo", sender: self) performSegueWithIdentifier("showVideo", sender: self)
} }
else {
let len = count(items.root)
let url = NetworkManager.sharedInstance.baseurl + "/service/listfiles" + items.root + "/" + items.path + "/" + items.name
println(items)
println(url)
Alamofire.request(.GET, url).responseSwiftyJSON({
(request, response, json, error) in
var im = [MediaItem]()
var hashes = Dictionary<String, String>()
for (a, c) in json {
// let (a,b) = j #
let s = c.object as! NSString
if s.hasSuffix(".jpg") {
let l = s.length
let name = (s as NSString).lastPathComponent
var pathlen = l - len - count(name)
// if (pathlen > 1000) {
println(pathlen)
println(name)
println(s)
// }
if (pathlen < 2) {
pathlen = 2
}
let path = (s as NSString).substringWithRange(NSMakeRange(len + 1, pathlen - 2))
let folderName = path.lastPathComponent
let fl = count(path)
let pfl = fl - count(folderName)
println ("\(folderName) \(pfl)")
let fpath = (s as NSString).substringWithRange(NSMakeRange(0, pfl))
let i = MediaItem(name: folderName, path: fpath, root: items.root, type: ItemType.PICS)
i.thumbUrl = "\(s)?preview=true"
if !name.hasPrefix(".") {
im.append(i)
}
}
}
let pc = MediaPhotoController()
pc.items = im
pc.completionHandler = {
self.dismissViewControllerAnimated(true, completion: nil);
}
let navController = UINavigationController(rootViewController: pc) // Creating a navigation controller with pc at the root of the navigation stack.
self.presentViewController(navController, animated: false, completion: nil)
})
}
} }
} }

5
kplayer/detail/ItemCell.swift

@ -25,6 +25,7 @@ class ItemCell: UICollectionViewCell {
super.init(frame: frame) super.init(frame: frame)
image = UIImageView(frame: frame) image = UIImageView(frame: frame)
image.contentMode = UIViewContentMode.ScaleAspectFit
autolayout(["imag": image], autolayout(["imag": image],
constraints: constraints:
@ -35,8 +36,8 @@ class ItemCell: UICollectionViewCell {
func setItem(item: MediaItem) { func setItem(item: MediaItem) {
self.item = item self.item = item
if let url = item.thumbUrl {
image.hnk_setImageFromURL(NSURL(string: item.thumbUrlAbsolute)!, placeholder: defaultImage)
if let url = item.thumbUrl, nsurl = NSURL(string: item.thumbUrlAbsolute) {
image.hnk_setImageFromURL(nsurl, placeholder: defaultImage)
} else { } else {
if let i = item.image { if let i = item.image {
image.image = i.scaleToSize(15 * 16, height: 15 * 9) image.image = i.scaleToSize(15 * 16, height: 15 * 9)

5
kplayer/detail/VideoPlayerController.swift

@ -29,6 +29,7 @@ class VideoPlayerController: UIViewController {
var thumbnailTime: NSTimeInterval = 0.0 var thumbnailTime: NSTimeInterval = 0.0
var edit = true var edit = true
var allowEdit = true
var index = 0 var index = 0
override func viewDidLoad() { override func viewDidLoad() {
@ -52,6 +53,10 @@ class VideoPlayerController: UIViewController {
} }
func doEdit(sender: AnyObject) { func doEdit(sender: AnyObject) {
if (!allowEdit) {
return
}
if (edit) { if (edit) {
edit = false edit = false
reviewButton!.tintColor = UIColor.blueColor() reviewButton!.tintColor = UIColor.blueColor()

1419
kplayer/exswift/Array.swift
File diff suppressed because it is too large
View File

18
kplayer/exswift/Bool.swift

@ -0,0 +1,18 @@
//
// Bool.swift
// ExSwift
//
// Created by Hernandez Alvarez, David on 2/10/15.
// Copyright (c) 2015 pNre. All rights reserved.
//
import Foundation
extension Bool {
mutating func toggle() -> Bool {
self = !self
return self
}
}

21
kplayer/exswift/Character.swift

@ -0,0 +1,21 @@
//
// Character.swift
// ExSwift
//
// Created by Cenny Davidsson on 2014-12-08.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
public extension Character {
/**
If the character represents an integer that fits into an Int, returns
the corresponding integer.
*/
public func toInt () -> Int? {
return String(self).toInt()
}
}

421
kplayer/exswift/Dictionary.swift

@ -0,0 +1,421 @@
//
// Dictionary.swift
// ExSwift
//
// Created by pNre on 04/06/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
import Swift
internal extension Dictionary {
/**
Difference of self and the input dictionaries.
Two dictionaries are considered equal if they contain the same [key: value] pairs.
:param: dictionaries Dictionaries to subtract
:returns: Difference of self and the input dictionaries
*/
func difference <V: Equatable> (dictionaries: [Key: V]...) -> [Key: V] {
var result = [Key: V]()
each {
if let item = $1 as? V {
result[$0] = item
}
}
// Difference
for dictionary in dictionaries {
for (key, value) in dictionary {
if result.has(key) && result[key] == value {
result.removeValueForKey(key)
}
}
}
return result
}
/**
Union of self and the input dictionaries.
:param: dictionaries Dictionaries to join
:returns: Union of self and the input dictionaries
*/
func union (dictionaries: Dictionary...) -> Dictionary {
var result = self
dictionaries.each { (dictionary) -> Void in
dictionary.each { (key, value) -> Void in
_ = result.updateValue(value, forKey: key)
}
}
return result
}
/**
Intersection of self and the input dictionaries.
Two dictionaries are considered equal if they contain the same [key: value] copules.
:param: values Dictionaries to intersect
:returns: Dictionary of [key: value] couples contained in all the dictionaries and self
*/
func intersection <K, V where K: Equatable, V: Equatable> (dictionaries: [K: V]...) -> [K: V] {
// Casts self from [Key: Value] to [K: V]
let filtered = mapFilter { (item, value) -> (K, V)? in
if (item is K) && (value is V) {
return (item as! K, value as! V)
}
return nil
}
// Intersection
return filtered.filter({ (key: K, value: V) -> Bool in
// check for [key: value] in all the dictionaries
dictionaries.all { $0.has(key) && $0[key] == value }
})
}
/**
Checks if a key exists in the dictionary.
:param: key Key to check
:returns: true if the key exists
*/
func has (key: Key) -> Bool {
return indexForKey(key) != nil
}
/**
Creates an Array with values generated by running
each [key: value] of self through the mapFunction.
:param: mapFunction
:returns: Mapped array
*/
func toArray <V> (map: (Key, Value) -> V) -> [V] {
var mapped = [V]()
each {
mapped.append(map($0, $1))
}
return mapped
}
/**
Creates a Dictionary with the same keys as self and values generated by running
each [key: value] of self through the mapFunction.
:param: mapFunction
:returns: Mapped dictionary
*/
func mapValues <V> (map: (Key, Value) -> V) -> [Key: V] {
var mapped = [Key: V]()
each {
mapped[$0] = map($0, $1)
}
return mapped
}
/**
Creates a Dictionary with the same keys as self and values generated by running
each [key: value] of self through the mapFunction discarding nil return values.
:param: mapFunction
:returns: Mapped dictionary
*/
func mapFilterValues <V> (map: (Key, Value) -> V?) -> [Key: V] {
var mapped = [Key: V]()
each {
if let value = map($0, $1) {
mapped[$0] = value
}
}
return mapped
}
/**
Creates a Dictionary with keys and values generated by running
each [key: value] of self through the mapFunction discarding nil return values.
:param: mapFunction
:returns: Mapped dictionary
*/
func mapFilter <K, V> (map: (Key, Value) -> (K, V)?) -> [K: V] {
var mapped = [K: V]()
each {
if let value = map($0, $1) {
mapped[value.0] = value.1
}
}
return mapped
}
/**
Creates a Dictionary with keys and values generated by running
each [key: value] of self through the mapFunction.
:param: mapFunction
:returns: Mapped dictionary
*/
func map <K, V> (map: (Key, Value) -> (K, V)) -> [K: V] {
var mapped = [K: V]()
self.each({
let (_key, _value) = map($0, $1)
mapped[_key] = _value
})
return mapped
}
/**
Loops trough each [key: value] pair in self.
:param: eachFunction Function to inovke on each loop
*/
func each (each: (Key, Value) -> ()) {
for (key, value) in self {
each(key, value)
}
}
/**
Constructs a dictionary containing every [key: value] pair from self
for which testFunction evaluates to true.
:param: testFunction Function called to test each key, value
:returns: Filtered dictionary
*/
func filter (test: (Key, Value) -> Bool) -> Dictionary {
var result = Dictionary()
for (key, value) in self {
if test(key, value) {
result[key] = value
}
}
return result
}
/**
Creates a dictionary composed of keys generated from the results of
running each element of self through groupingFunction. The corresponding
value of each key is an array of the elements responsible for generating the key.
:param: groupingFunction
:returns: Grouped dictionary
*/
func groupBy <T> (group: (Key, Value) -> T) -> [T: [Value]] {
var result = [T: [Value]]()
for (key, value) in self {
let groupKey = group(key, value)
// If element has already been added to dictionary, append to it. If not, create one.
if result.has(groupKey) {
result[groupKey]! += [value]
} else {
result[groupKey] = [value]
}
}
return result
}
/**
Similar to groupBy. Doesn't return a list of values, but the number of values for each group.
:param: groupingFunction Function called to define the grouping key
:returns: Grouped dictionary
*/
func countBy <T> (group: (Key, Value) -> (T)) -> [T: Int] {
var result = [T: Int]()
for (key, value) in self {
let groupKey = group(key, value)
// If element has already been added to dictionary, append to it. If not, create one.
if result.has(groupKey) {
result[groupKey]!++
} else {
result[groupKey] = 1
}
}
return result
}
/**
Checks if test evaluates true for all the elements in self.
:param: test Function to call for each element
:returns: true if test returns true for all the elements in self
*/
func all (test: (Key, Value) -> (Bool)) -> Bool {
for (key, value) in self {
if !test(key, value) {
return false
}
}
return true
}
/**
Checks if test evaluates true for any element of self.
:param: test Function to call for each element
:returns: true if test returns true for any element of self
*/
func any (test: (Key, Value) -> (Bool)) -> Bool {
for (key, value) in self {
if test(key, value) {
return true
}
}
return false
}
/**
Returns the number of elements which meet the condition
:param: test Function to call for each element
:returns: the number of elements meeting the condition
*/
func countWhere (test: (Key, Value) -> (Bool)) -> Int {
var result = 0
for (key, value) in self {
if test(key, value) {
result++
}
}
return result
}
/**
Recombines the [key: value] couples in self trough combine using initial as initial value.
:param: initial Initial value
:param: combine Function that reduces the dictionary
:returns: Resulting value
*/
func reduce <U> (initial: U, combine: (U, Element) -> U) -> U {
return Swift.reduce(self, initial, combine)
}
/**
Returns a copy of self, filtered to only have values for the whitelisted keys.
:param: keys Whitelisted keys
:returns: Filtered dictionary
*/
func pick (keys: [Key]) -> Dictionary {
return filter { (key: Key, _) -> Bool in
return keys.contains(key)
}
}
/**
Returns a copy of self, filtered to only have values for the whitelisted keys.
:param: keys Whitelisted keys
:returns: Filtered dictionary
*/
func pick (keys: Key...) -> Dictionary {
return pick(unsafeBitCast(keys, [Key].self))
}
/**
Returns a copy of self, filtered to only have values for the whitelisted keys.
:param: keys Keys to get
:returns: Dictionary with the given keys
*/
func at (keys: Key...) -> Dictionary {
return pick(keys)
}
/**
Removes a (key, value) pair from self and returns it as tuple.
If the dictionary is empty returns nil.
:returns: (key, value) tuple
*/
mutating func shift () -> (Key, Value)? {
if let key = keys.first {
return (key, removeValueForKey(key)!)
}
return nil
}
}
/**
Difference operator
*/
public func - <K, V: Equatable> (first: [K: V], second: [K: V]) -> [K: V] {
return first.difference(second)
}
/**
Intersection operator
*/
public func & <K, V: Equatable> (first: [K: V], second: [K: V]) -> [K: V] {
return first.intersection(second)
}
/**
Union operator
*/
public func | <K: Hashable, V> (first: [K: V], second: [K: V]) -> [K: V] {
return first.union(second)
}

93
kplayer/exswift/Double.swift

@ -0,0 +1,93 @@
//
// Double.swift
// ExSwift
//
// Created by pNre on 10/07/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
public extension Double {
/**
Absolute value.
:returns: fabs(self)
*/
func abs () -> Double {
return Foundation.fabs(self)
}
/**
Squared root.
:returns: sqrt(self)
*/
func sqrt () -> Double {
return Foundation.sqrt(self)
}
/**
Rounds self to the largest integer <= self.
:returns: floor(self)
*/
func floor () -> Double {
return Foundation.floor(self)
}
/**
Rounds self to the smallest integer >= self.
:returns: ceil(self)
*/
func ceil () -> Double {
return Foundation.ceil(self)
}
/**
Rounds self to the nearest integer.
:returns: round(self)
*/
func round () -> Double {
return Foundation.round(self)
}
/**
Clamps self to a specified range.
:param: min Lower bound
:param: max Upper bound
:returns: Clamped value
*/
func clamp (min: Double, _ max: Double) -> Double {
return Swift.max(min, Swift.min(max, self))
}
/**
Just like round(), except it supports rounding to an arbitrary number, not just 1
Be careful about rounding errors
:params: increment the increment to round to
*/
func roundToNearest(increment: Double) -> Double {
let remainder = self % increment
return remainder < increment / 2 ? self - remainder : self - remainder + increment
}
/**
Random double between min and max (inclusive).
:params: min
:params: max
:returns: Random number
*/
static func random(min: Double = 0, max: Double) -> Double {
let diff = max - min;
let rand = Double(arc4random() % (UInt32(RAND_MAX) + 1))
return ((rand / Double(RAND_MAX)) * diff) + min;
}
}

19
kplayer/exswift/ExSwift.h

@ -0,0 +1,19 @@
//
// ExSwift.h
// ExSwift
//
// Created by pNre on 07/06/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for ExSwift.
FOUNDATION_EXPORT double ExSwiftVersionNumber;
//! Project version string for ExSwift.
FOUNDATION_EXPORT const unsigned char ExSwiftVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <ExSwift/PublicHeader.h>

282
kplayer/exswift/ExSwift.swift

@ -0,0 +1,282 @@
//
// ExSwift.swift
// ExSwift
//
// Created by pNre on 07/06/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
infix operator =~ {}
infix operator |~ {}
infix operator .. {}
infix operator <=> {}
public typealias Ex = ExSwift
public class ExSwift {
/**
Creates a wrapper that, executes function only after being called n times.
:param: n No. of times the wrapper has to be called before function is invoked
:param: function Function to wrap
:returns: Wrapper function
*/
public class func after <P, T> (n: Int, function: (P...) -> T) -> ((P...) -> T?) {
typealias Function = [P] -> T
var times = n
return {
(params: P...) -> T? in
// Workaround for the now illegal (T...) type.
let adaptedFunction = unsafeBitCast(function, Function.self)
if times-- <= 0 {
return adaptedFunction(params)
}
return nil
}
}
/**
Creates a wrapper that, executes function only after being called n times
:param: n No. of times the wrapper has to be called before function is invoked
:param: function Function to wrap
:returns: Wrapper function
*/
public class func after <T> (n: Int, function: Void -> T) -> (Void -> T?) {
func callAfter (args: Any?...) -> T {
return function()
}
let f = ExSwift.after(n, function: callAfter)
return { f([nil]) }
}
/**
Creates a wrapper function that invokes function once.
Repeated calls to the wrapper function will return the value of the first call.
:param: function Function to wrap
:returns: Wrapper function
*/
public class func once <P, T> (function: (P...) -> T) -> ((P...) -> T) {
typealias Function = [P] -> T
var returnValue: T? = nil
return { (params: P...) -> T in
if returnValue != nil {
return returnValue!
}
let adaptedFunction = unsafeBitCast(function, Function.self)
returnValue = adaptedFunction(params)
return returnValue!
}
}
/**
Creates a wrapper function that invokes function once.
Repeated calls to the wrapper function will return the value of the first call.
:param: function Function to wrap
:returns: Wrapper function
*/
public class func once <T> (function: Void -> T) -> (Void -> T) {
let f = ExSwift.once {
(params: Any?...) -> T in
return function()
}
return { f([nil]) }
}
/**
Creates a wrapper that, when called, invokes function with any additional
partial arguments prepended to those provided to the new function.
:param: function Function to wrap
:param: parameters Arguments to prepend
:returns: Wrapper function
*/
public class func partial <P, T> (function: (P...) -> T, _ parameters: P...) -> ((P...) -> T) {
typealias Function = [P] -> T
return { (params: P...) -> T in
let adaptedFunction = unsafeBitCast(function, Function.self)
return adaptedFunction(parameters + params)
}
}
/**
Creates a wrapper (without any parameter) that, when called, invokes function
automatically passing parameters as arguments.
:param: function Function to wrap
:param: parameters Arguments to pass to function
:returns: Wrapper function
*/
public class func bind <P, T> (function: (P...) -> T, _ parameters: P...) -> (Void -> T) {
typealias Function = [P] -> T
return { Void -> T in
let adaptedFunction = unsafeBitCast(function, Function.self)
return adaptedFunction(parameters)
}
}
/**
Creates a wrapper for function that caches the result of function's invocations.
:param: function Function with one parameter to cache
:returns: Wrapper function
*/
public class func cached <P: Hashable, R> (function: P -> R) -> (P -> R) {
var cache = [P:R]()
return { (param: P) -> R in
let key = param
if let cachedValue = cache[key] {
return cachedValue
} else {
let value = function(param)
cache[key] = value
return value
}
}
}
/**
Creates a wrapper for function that caches the result of function's invocations.
:param: function Function to cache
:param: hash Parameters based hashing function that computes the key used to store each result in the cache
:returns: Wrapper function
*/
public class func cached <P: Hashable, R> (function: (P...) -> R, hash: ((P...) -> P)) -> ((P...) -> R) {
typealias Function = [P] -> R
typealias Hash = [P] -> P
var cache = [P:R]()
return { (params: P...) -> R in
let adaptedFunction = unsafeBitCast(function, Function.self)
let adaptedHash = unsafeBitCast(hash, Hash.self)
let key = adaptedHash(params)
if let cachedValue = cache[key] {
return cachedValue
} else {
let value = adaptedFunction(params)
cache[key] = value
return value
}
}
}
/**
Creates a wrapper for function that caches the result of function's invocations.
:param: function Function to cache
:returns: Wrapper function
*/
public class func cached <P: Hashable, R> (function: (P...) -> R) -> ((P...) -> R) {
return cached(function, hash: { (params: P...) -> P in return params[0] })
}
/**
Utility method to return an NSRegularExpression object given a pattern.
:param: pattern Regex pattern
:param: ignoreCase If true the NSRegularExpression is created with the NSRegularExpressionOptions.CaseInsensitive flag
:returns: NSRegularExpression object
*/
internal class func regex (pattern: String, ignoreCase: Bool = false) -> NSRegularExpression? {
var options = NSRegularExpressionOptions.DotMatchesLineSeparators.rawValue
if ignoreCase {
options = NSRegularExpressionOptions.CaseInsensitive.rawValue | options
}
var error: NSError? = nil
let regex = NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(rawValue: options), error: &error)
return (error == nil) ? regex : nil
}
}
func <=> <T: Comparable>(lhs: T, rhs: T) -> Int {
if lhs < rhs {
return -1
} else if lhs > rhs {
return 1
} else {
return 0
}
}
/**
* Internal methods
*/
extension ExSwift {
/**
* Converts, if possible, and flattens an object from its Objective-C
* representation to the Swift one.
* @param object Object to convert
* @returns Flattenend array of converted values
*/
internal class func bridgeObjCObject <T, S> (object: S) -> [T] {
var result = [T]()
let reflection = reflect(object)
// object has an Objective-C type
if let obj = object as? T {
// object has type T
result.append(obj)
} else if reflection.disposition == .ObjCObject {
var bridgedValue: T!?
// If it is an NSArray, flattening will produce the expected result
if let array = object as? NSArray {
result += array.flatten()
} else if let bridged = reflection.value as? T {
result.append(bridged)
}
} else if reflection.disposition == .IndexContainer {
// object is a native Swift array
// recursively convert each item
(0..<reflection.count).each {
let ref = reflection[$0].1
result += Ex.bridgeObjCObject(ref.value)
}
}
return result
}
}

83
kplayer/exswift/Float.swift

@ -0,0 +1,83 @@
//
// Float.swift
// ExSwift
//
// Created by pNre on 04/06/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
public extension Float {
/**
Absolute value.
:returns: fabs(self)
*/
func abs () -> Float {
return fabsf(self)
}
/**
Squared root.
:returns: sqrtf(self)
*/
func sqrt () -> Float {
return sqrtf(self)
}
/**
Rounds self to the largest integer <= self.
:returns: floorf(self)
*/
func floor () -> Float {
return floorf(self)
}
/**
Rounds self to the smallest integer >= self.
:returns: ceilf(self)
*/
func ceil () -> Float {
return ceilf(self)
}
/**
Rounds self to the nearest integer.
:returns: roundf(self)
*/
func round () -> Float {
return roundf(self)
}
/**
Clamps self to a specified range.
:param: min Lower bound
:param: max Upper bound
:returns: Clamped value
*/
func clamp (min: Float, _ max: Float) -> Float {
return Swift.max(min, Swift.min(max, self))
}
/**
Random float between min and max (inclusive).
:param: min
:param: max
:returns: Random number
*/
static func random(min: Float = 0, max: Float) -> Float {
let diff = max - min;
let rand = Float(arc4random() % (UInt32(RAND_MAX) + 1))
return ((rand / Float(RAND_MAX)) * diff) + min;
}
}

256
kplayer/exswift/Int.swift

@ -0,0 +1,256 @@
//
// Int.swift
// ExSwift
//
// Created by pNre on 03/06/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
public extension Int {
/**
Calls function self times.
:param: function Function to call
*/
func times <T> (function: Void -> T) {
(0..<self).each { _ in function(); return }
}
/**
Calls function self times.
:param: function Function to call
*/
func times (function: Void -> Void) {
(0..<self).each { _ in function(); return }
}
/**
Calls function self times passing a value from 0 to self on each call.
:param: function Function to call
*/
func times <T> (function: (Int) -> T) {
(0..<self).each { index in function(index); return }
}
/**
Checks if a number is even.
:returns: true if self is even
*/
func isEven () -> Bool {
return (self % 2) == 0
}
/**
Checks if a number is odd.
:returns: true if self is odd
*/
func isOdd () -> Bool {
return !isEven()
}
/**
Iterates function, passing in integer values from self up to and including limit.
:param: limit Last value to pass
:param: function Function to invoke
*/
func upTo (limit: Int, function: (Int) -> ()) {
if limit < self {
return
}
(self...limit).each(function)
}
/**
Iterates function, passing in integer values from self down to and including limit.
:param: limit Last value to pass
:param: function Function to invoke
*/
func downTo (limit: Int, function: (Int) -> ()) {
if limit > self {
return
}
Array(limit...self).reverse().each(function)
}
/**
Clamps self to a specified range.
:param: range Clamping range
:returns: Clamped value
*/
func clamp (range: Range<Int>) -> Int {
return clamp(range.startIndex, range.endIndex - 1)
}
/**
Clamps self to a specified range.
:param: min Lower bound
:param: max Upper bound
:returns: Clamped value
*/
func clamp (min: Int, _ max: Int) -> Int {
return Swift.max(min, Swift.min(max, self))
}
/**
Checks if self is included a specified range.
:param: range Range
:param: strict If true, "<" is used for comparison
:returns: true if in range
*/
func isIn (range: Range<Int>, strict: Bool = false) -> Bool {
if strict {
return range.startIndex < self && self < range.endIndex - 1
}
return range.startIndex <= self && self <= range.endIndex - 1
}
/**
Checks if self is included in a closed interval.
:param: interval Interval to check
:returns: true if in the interval
*/
func isIn (interval: ClosedInterval<Int>) -> Bool {
return interval.contains(self)
}
/**
Checks if self is included in an half open interval.
:param: interval Interval to check
:returns: true if in the interval
*/
func isIn (interval: HalfOpenInterval<Int>) -> Bool {
return interval.contains(self)
}
/**
Returns an [Int] containing the digits in self.
:return: Array of digits
*/
func digits () -> [Int] {
var result = [Int]()
for char in String(self) {
let string = String(char)
if let toInt = string.toInt() {
result.append(toInt)
}
}
return result
}
/**
Absolute value.
:returns: abs(self)
*/
func abs () -> Int {
return Swift.abs(self)
}
/**
Greatest common divisor of self and n.
:param: n
:returns: GCD
*/
func gcd (n: Int) -> Int {
return n == 0 ? self : n.gcd(self % n)
}
/**
Least common multiple of self and n
:param: n
:returns: LCM
*/
func lcm (n: Int) -> Int {
return (self * n).abs() / gcd(n)
}
/**
Computes the factorial of self
:returns: Factorial
*/
func factorial () -> Int {
return self == 0 ? 1 : self * (self - 1).factorial()
}
/**
Random integer between min and max (inclusive).
:param: min Minimum value to return
:param: max Maximum value to return
:returns: Random integer
*/
static func random(min: Int = 0, max: Int) -> Int {
return Int(arc4random_uniform(UInt32((max - min) + 1))) + min
}
}
/**
NSTimeInterval conversion extensions
*/
public extension Int {
var years: NSTimeInterval {
return 365 * self.days
}
var year: NSTimeInterval {
return self.years
}
var days: NSTimeInterval {
return 24 * self.hours
}
var day: NSTimeInterval {
return self.days
}
var hours: NSTimeInterval {
return 60 * self.minutes
}
var hour: NSTimeInterval {
return self.hours
}
var minutes: NSTimeInterval {
return 60 * self.seconds
}
var minute: NSTimeInterval {
return self.minutes
}
var seconds: NSTimeInterval {
return NSTimeInterval(self)
}
var second: NSTimeInterval {
return self.seconds
}
}

64
kplayer/exswift/NSArray.swift

@ -0,0 +1,64 @@
//
// NSArray.swift
// ExSwift
//
// Created by pNre on 10/06/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
public extension NSArray {
/**
Converts an NSArray object to an OutType[] array containing the items in the NSArray of type OutType.
:returns: Array of Swift objects
*/
func cast <OutType> () -> [OutType] {
var result = [OutType]()
for item : AnyObject in self {
result += Ex.bridgeObjCObject(item) as [OutType]
}
return result
}
/**
Flattens a multidimensional NSArray to an OutType[] array
containing the items in the NSArray that can be bridged from their ObjC type to OutType.
:returns: Flattened array
*/
func flatten <OutType> () -> [OutType] {
var result = [OutType]()
let reflection = reflect(self)
for i in 0..<reflection.count {
result += Ex.bridgeObjCObject(reflection[i].1.value) as [OutType]
}
return result
}
/**
Flattens a multidimensional NSArray to a [AnyObject].
:returns: Flattened array
*/
func flattenAny () -> [AnyObject] {
var result = [AnyObject]()
for item in self {
if let array = item as? NSArray {
result += array.flattenAny()
} else {
result.append(item)
}
}
return result
}
}

318
kplayer/exswift/NSDate.swift

@ -0,0 +1,318 @@
//
// File.swift
// ExSwift
//
// Created by Piergiuseppe Longo on 23/11/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
public extension NSDate {
// MARK: NSDate Manipulation
/**
Returns a new NSDate object representing the date calculated by adding the amount specified to self date
:param: seconds number of seconds to add
:param: minutes number of minutes to add
:param: hours number of hours to add
:param: days number of days to add
:param: weeks number of weeks to add
:param: months number of months to add
:param: years number of years to add
:returns: the NSDate computed
*/
public func add(seconds: Int = 0, minutes: Int = 0, hours: Int = 0, days: Int = 0, weeks: Int = 0, months: Int = 0, years: Int = 0) -> NSDate {
var calendar = NSCalendar.currentCalendar()
let version = floor(NSFoundationVersionNumber)
if version <= NSFoundationVersionNumber10_9_2 {
var component = NSDateComponents()
component.setValue(seconds, forComponent: .CalendarUnitSecond)
var date : NSDate! = calendar.dateByAddingComponents(component, toDate: self, options: nil)!
component = NSDateComponents()
component.setValue(minutes, forComponent: .CalendarUnitMinute)
date = calendar.dateByAddingComponents(component, toDate: date, options: nil)!
component = NSDateComponents()
component.setValue(hours, forComponent: .CalendarUnitHour)
date = calendar.dateByAddingComponents(component, toDate: date, options: nil)!
component = NSDateComponents()
component.setValue(days, forComponent: .CalendarUnitDay)
date = calendar.dateByAddingComponents(component, toDate: date, options: nil)!
component = NSDateComponents()
component.setValue(weeks, forComponent: .CalendarUnitWeekOfMonth)
date = calendar.dateByAddingComponents(component, toDate: date, options: nil)!
component = NSDateComponents()
component.setValue(months, forComponent: .CalendarUnitMonth)
date = calendar.dateByAddingComponents(component, toDate: date, options: nil)!
component = NSDateComponents()
component.setValue(years, forComponent: .CalendarUnitYear)
date = calendar.dateByAddingComponents(component, toDate: date, options: nil)!
return date
}
var date : NSDate! = calendar.dateByAddingUnit(.CalendarUnitSecond, value: seconds, toDate: self, options: nil)
date = calendar.dateByAddingUnit(.CalendarUnitMinute, value: minutes, toDate: date, options: nil)
date = calendar.dateByAddingUnit(.CalendarUnitDay, value: days, toDate: date, options: nil)
date = calendar.dateByAddingUnit(.CalendarUnitHour, value: hours, toDate: date, options: nil)
date = calendar.dateByAddingUnit(.CalendarUnitWeekOfMonth, value: weeks, toDate: date, options: nil)
date = calendar.dateByAddingUnit(.CalendarUnitMonth, value: months, toDate: date, options: nil)
date = calendar.dateByAddingUnit(.CalendarUnitYear, value: years, toDate: date, options: nil)
return date
}
/**
Returns a new NSDate object representing the date calculated by adding an amount of seconds to self date
:param: seconds number of seconds to add
:returns: the NSDate computed
*/
public func addSeconds (seconds: Int) -> NSDate {
return add(seconds: seconds)
}
/**
Returns a new NSDate object representing the date calculated by adding an amount of minutes to self date
:param: minutes number of minutes to add
:returns: the NSDate computed
*/
public func addMinutes (minutes: Int) -> NSDate {
return add(minutes: minutes)
}
/**
Returns a new NSDate object representing the date calculated by adding an amount of hours to self date
:param: hours number of hours to add
:returns: the NSDate computed
*/
public func addHours(hours: Int) -> NSDate {
return add(hours: hours)
}
/**
Returns a new NSDate object representing the date calculated by adding an amount of days to self date
:param: days number of days to add
:returns: the NSDate computed
*/
public func addDays(days: Int) -> NSDate {
return add(days: days)
}
/**
Returns a new NSDate object representing the date calculated by adding an amount of weeks to self date
:param: weeks number of weeks to add
:returns: the NSDate computed
*/
public func addWeeks(weeks: Int) -> NSDate {
return add(weeks: weeks)
}
/**
Returns a new NSDate object representing the date calculated by adding an amount of months to self date
:param: months number of months to add
:returns: the NSDate computed
*/
public func addMonths(months: Int) -> NSDate {
return add(months: months)
}
/**
Returns a new NSDate object representing the date calculated by adding an amount of years to self date
:param: years number of year to add
:returns: the NSDate computed
*/
public func addYears(years: Int) -> NSDate {
return add(years: years)
}
// MARK: Date comparison
/**
Checks if self is after input NSDate
:param: date NSDate to compare
:returns: True if self is after the input NSDate, false otherwise
*/
public func isAfter(date: NSDate) -> Bool{
return (self.compare(date) == NSComparisonResult.OrderedDescending)
}
/**
Checks if self is before input NSDate
:param: date NSDate to compare
:returns: True if self is before the input NSDate, false otherwise
*/
public func isBefore(date: NSDate) -> Bool{
return (self.compare(date) == NSComparisonResult.OrderedAscending)
}
// MARK: Getter
/**
Date year
*/
public var year : Int {
get {
return getComponent(.CalendarUnitYear)
}
}
/**
Date month
*/
public var month : Int {
get {
return getComponent(.CalendarUnitMonth)
}
}
/**
Date weekday
*/
public var weekday : Int {
get {
return getComponent(.CalendarUnitWeekday)
}
}
/**
Date weekMonth
*/
public var weekMonth : Int {
get {
return getComponent(.CalendarUnitWeekOfMonth)
}
}
/**
Date days
*/
public var days : Int {
get {
return getComponent(.CalendarUnitDay)
}
}
/**
Date hours
*/
public var hours : Int {
get {
return getComponent(.CalendarUnitHour)
}
}
/**
Date minuts
*/
public var minutes : Int {
get {
return getComponent(.CalendarUnitMinute)
}
}
/**
Date seconds
*/
public var seconds : Int {
get {
return getComponent(.CalendarUnitSecond)
}
}
/**
Returns the value of the NSDate component
:param: component NSCalendarUnit
:returns: the value of the component
*/
public func getComponent (component : NSCalendarUnit) -> Int {
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(component, fromDate: self)
return components.valueForComponent(component)
}
}
extension NSDate: Strideable {
public func distanceTo(other: NSDate) -> NSTimeInterval {
return other - self
}
public func advancedBy(n: NSTimeInterval) -> Self {
return self.dynamicType(timeIntervalSinceReferenceDate: self.timeIntervalSinceReferenceDate + n)
}
}
// MARK: Arithmetic
func +(date: NSDate, timeInterval: Int) -> NSDate {
return date + NSTimeInterval(timeInterval)
}
func -(date: NSDate, timeInterval: Int) -> NSDate {
return date - NSTimeInterval(timeInterval)
}
func +=(inout date: NSDate, timeInterval: Int) {
date = date + timeInterval
}
func -=(inout date: NSDate, timeInterval: Int) {
date = date - timeInterval
}
func +(date: NSDate, timeInterval: Double) -> NSDate {
return date.dateByAddingTimeInterval(NSTimeInterval(timeInterval))
}
func -(date: NSDate, timeInterval: Double) -> NSDate {
return date.dateByAddingTimeInterval(NSTimeInterval(-timeInterval))
}
func +=(inout date: NSDate, timeInterval: Double) {
date = date + timeInterval
}
func -=(inout date: NSDate, timeInterval: Double) {
date = date - timeInterval
}
func -(date: NSDate, otherDate: NSDate) -> NSTimeInterval {
return date.timeIntervalSinceDate(otherDate)
}
extension NSDate: Equatable {
}
public func ==(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedSame
}
extension NSDate: Comparable {
}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
}

80
kplayer/exswift/Range.swift

@ -0,0 +1,80 @@
//
// Range.swift
// ExSwift
//
// Created by pNre on 04/06/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
internal extension Range {
/**
For each element in the range invokes function.
:param: function Function to call
*/
func times (function: () -> ()) {
each { (current: T) -> () in
function()
}
}
/**
For each element in the range invokes function passing the element as argument.
:param: function Function to invoke
*/
func times (function: (T) -> ()) {
each (function)
}
/**
For each element in the range invokes function passing the element as argument.
:param: function Function to invoke
*/
func each (function: (T) -> ()) {
for i in self {
function(i)
}
}
/**
Returns each element of the range in an array
:returns: Each element of the range in an array
*/
func toArray () -> [T] {
var result: [T] = []
for i in self {
result.append(i)
}
return result
}
/**
Range of Int with random bounds between from and to (inclusive).
:param: from Lower bound
:param: to Upper bound
:returns: Random range
*/
static func random (from: Int, to: Int) -> Range<Int> {
let lowerBound = Int.random(min: from, max: to)
let upperBound = Int.random(min: lowerBound, max: to)
return lowerBound...upperBound
}
}
/**
* Operator == to compare 2 ranges first, second by start & end indexes. If first.startIndex is equal to
* second.startIndex and first.endIndex is equal to second.endIndex the ranges are considered equal.
*/
public func == <U: ForwardIndexType> (first: Range<U>, second: Range<U>) -> Bool {
return first.startIndex == second.startIndex &&
first.endIndex == second.endIndex
}

244
kplayer/exswift/Sequence.swift

@ -0,0 +1,244 @@
//
// Sequence.swift
// ExSwift
//
// Created by Colin Eberhardt on 24/06/2014.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
internal extension SequenceOf {
/**
First element of the sequence.
:returns: First element of the sequence if present
*/
var first: T? {
var generator = self.generate()
return generator.next()
}
/**
Checks if call returns true for any element of self.
:param: call Function to call for each element
:returns: True if call returns true for any element of self
*/
func any (call: (T) -> Bool) -> Bool {
var generator = self.generate()
while let nextItem = generator.next() {
if call(nextItem) {
return true
}
}
return false
}
/**
Object at the specified index if exists.
:param: index
:returns: Object at index in sequence, nil if index is out of bounds
*/
func get (index: Int) -> T? {
var generator = self.generate()
for _ in 0..<(index - 1) {
generator.next()
}
return generator.next()
}
/**
Objects in the specified range.
:param: range
:returns: Subsequence in range
*/
func get (range: Range<Int>) -> SequenceOf<T> {
return self.skip(range.startIndex).take(range.endIndex - range.startIndex)
}
/**
Index of the first occurrence of item, if found.
:param: item The item to search for
:returns: Index of the matched item or nil
*/
func indexOf <U: Equatable> (item: U) -> Int? {
var index = 0
for current in self {
if let equatable = current as? U {
if equatable == item {
return index
}
}
index++
}
return nil
}
/**
Subsequence from n to the end of the sequence.
:param: n Number of elements to skip
:returns: Sequence from n to the end
*/
func skip (n: Int) -> SequenceOf<T> {
var generator = self.generate()
for _ in 0..<n {
generator.next()
}
return SequenceOf(generator)
}
/**
Filters the sequence only including items that match the test.
:param: include Function invoked to test elements for inclusion in the sequence
:returns: Filtered sequence
*/
func filter(include: (T) -> Bool) -> SequenceOf<T> {
return SequenceOf(lazy(self).filter(include))
}
/**
Opposite of filter.
:param: exclude Function invoked to test elements for exlcusion from the sequence
:returns: Filtered sequence
*/
func reject (exclude: (T -> Bool)) -> SequenceOf<T> {
return self.filter {
return !exclude($0)
}
}
/**
Skips the elements in the sequence up until the condition returns false.
:param: condition A function which returns a boolean if an element satisfies a given condition or not
:returns: Elements of the sequence starting with the element which does not meet the condition
*/
func skipWhile(condition:(T) -> Bool) -> SequenceOf<T> {
var generator = self.generate()
var checkingGenerator = self.generate()
var keepSkipping = true
while keepSkipping {
var nextItem = checkingGenerator.next()
keepSkipping = nextItem != nil ? condition(nextItem!) : false
if keepSkipping {
generator.next()
}
}
return SequenceOf(generator)
}
/**
Checks if self contains the item object.
:param: item The item to search for
:returns: true if self contains item
*/
func contains<T:Equatable> (item: T) -> Bool {
var generator = self.generate()
while let nextItem = generator.next() {
if nextItem as! T == item {
return true
}
}
return false
}
/**
Returns the first n elements from self.
:param: n Number of elements to take
:returns: First n elements
*/
func take (n: Int) -> SequenceOf<T> {
return SequenceOf(TakeSequence(self, n))
}
/**
Returns the elements of the sequence up until an element does not meet the condition.
:param: condition A function which returns a boolean if an element satisfies a given condition or not.
:returns: Elements of the sequence up until an element does not meet the condition
*/
func takeWhile (condition:(T?) -> Bool) -> SequenceOf<T> {
return SequenceOf(TakeWhileSequence(self, condition))
}
/**
Returns each element of the sequence in an array
:returns: Each element of the sequence in an array
*/
func toArray () -> [T] {
var result: [T] = []
for item in self {
result.append(item)
}
return result
}
}
/**
A sequence adapter that implements the 'take' functionality
*/
public struct TakeSequence<S: SequenceType>: SequenceType {
private let sequence: S
private let n: Int
public init(_ sequence: S, _ n: Int) {
self.sequence = sequence
self.n = n
}
public func generate() -> GeneratorOf<S.Generator.Element> {
var count = 0
var generator = self.sequence.generate()
return GeneratorOf<S.Generator.Element> {
count++
if count > self.n {
return nil
} else {
return generator.next()
}
}
}
}
/**
a sequence adapter that implements the 'takeWhile' functionality
*/
public struct TakeWhileSequence<S: SequenceType>: SequenceType {
private let sequence: S
private let condition: (S.Generator.Element?) -> Bool
public init(_ sequence:S, _ condition:(S.Generator.Element?) -> Bool) {
self.sequence = sequence
self.condition = condition
}
public func generate() -> GeneratorOf<S.Generator.Element> {
var generator = self.sequence.generate()
var endConditionMet = false
return GeneratorOf<S.Generator.Element> {
let next: S.Generator.Element? = generator.next()
if !endConditionMet {
endConditionMet = !self.condition(next)
}
if endConditionMet {
return nil
} else {
return next
}
}
}
}

403
kplayer/exswift/String.swift

@ -0,0 +1,403 @@
//
// String.swift
// ExSwift
//
// Created by pNre on 03/06/14.
// Copyright (c) 2014 pNre. All rights reserved.
//
import Foundation
public extension String {
/**
String length
*/
var length: Int { return count(self) }
/**
self.capitalizedString shorthand
*/
var capitalized: String { return capitalizedString }
/**
Returns the substring in the given range
:param: range
:returns: Substring in range
*/
subscript (range: Range<Int>) -> String? {
if range.startIndex < 0 || range.endIndex > self.length {
return nil
}
let range = Range(start: advance(startIndex, range.startIndex), end: advance(startIndex, range.endIndex))
return self[range]
}
/**
Equivalent to at. Takes a list of indexes and returns an Array
containing the elements at the given indexes in self.
:param: firstIndex
:param: secondIndex
:param: restOfIndexes
:returns: Charaters at the specified indexes (converted to String)
*/
subscript (firstIndex: Int, secondIndex: Int, restOfIndexes: Int...) -> [String] {
return at([firstIndex, secondIndex] + restOfIndexes)
}
/**
Gets the character at the specified index as String.
If index is negative it is assumed to be relative to the end of the String.
:param: index Position of the character to get
:returns: Character as String or nil if the index is out of bounds
*/
subscript (index: Int) -> String? {
if let char = Array(self).get(index) {
return String(char)
}
return nil
}
/**
Takes a list of indexes and returns an Array containing the elements at the given indexes in self.
:param: indexes Positions of the elements to get
:returns: Array of characters (as String)
*/
func at (indexes: Int...) -> [String] {
return indexes.map { self[$0]! }
}
/**
Takes a list of indexes and returns an Array containing the elements at the given indexes in self.
:param: indexes Positions of the elements to get
:returns: Array of characters (as String)
*/
func at (indexes: [Int]) -> [String] {
return indexes.map { self[$0]! }
}
/**
Returns an array of strings, each of which is a substring of self formed by splitting it on separator.
:param: separator Character used to split the string
:returns: Array of substrings
*/
func explode (separator: Character) -> [String] {
return split(self, isSeparator: { (element: Character) -> Bool in
return element == separator
})
}
/**
Finds any match in self for pattern.
:param: pattern Pattern to match
:param: ignoreCase true for case insensitive matching
:returns: Matches found (as [NSTextCheckingResult])
*/
func matches (pattern: String, ignoreCase: Bool = false) -> [NSTextCheckingResult]? {
if let regex = ExSwift.regex(pattern, ignoreCase: ignoreCase) {
// Using map to prevent a possible bug in the compiler
return regex.matchesInString(self, options: nil, range: NSMakeRange(0, length)).map { $0 as! NSTextCheckingResult }
}
return nil
}
/**
Check is string with this pattern included in string
:param: pattern Pattern to match
:param: ignoreCase true for case insensitive matching
:returns: true if contains match, otherwise false
*/
func containsMatch (pattern: String, ignoreCase: Bool = false) -> Bool? {
if let regex = ExSwift.regex(pattern, ignoreCase: ignoreCase) {
let range = NSMakeRange(0, count(self))
return regex.firstMatchInString(self, options: .allZeros, range: range) != nil
}
return nil
}
/**
Replace all pattern matches with another string
:param: pattern Pattern to match
:param: replacementString string to replace matches
:param: ignoreCase true for case insensitive matching
:returns: true if contains match, otherwise false
*/
func replaceMatches (pattern: String, withString replacementString: String, ignoreCase: Bool = false) -> String? {
if let regex = ExSwift.regex(pattern, ignoreCase: ignoreCase) {
let range = NSMakeRange(0, count(self))
return regex.stringByReplacingMatchesInString(self, options: .allZeros, range: range, withTemplate: replacementString)
}
return nil
}
/**
Inserts a substring at the given index in self.
:param: index Where the new string is inserted
:param: string String to insert
:returns: String formed from self inserting string at index
*/
func insert (var index: Int, _ string: String) -> String {
// Edge cases, prepend and append
if index > length {
return self + string
} else if index < 0 {
return string + self
}
return self[0..<index]! + string + self[index..<length]!
}
/**
Strips the specified characters from the beginning of self.
:returns: Stripped string
*/
func trimmedLeft (characterSet set: NSCharacterSet = NSCharacterSet.whitespaceAndNewlineCharacterSet()) -> String {
if let range = rangeOfCharacterFromSet(set.invertedSet) {
return self[range.startIndex..<endIndex]
}
return ""
}
@availability(*, unavailable, message="use 'trimmedLeft' instead") func ltrimmed (set: NSCharacterSet = NSCharacterSet.whitespaceAndNewlineCharacterSet()) -> String {
return trimmedLeft(characterSet: set)
}
/**
Strips the specified characters from the end of self.
:returns: Stripped string
*/
func trimmedRight (characterSet set: NSCharacterSet = NSCharacterSet.whitespaceAndNewlineCharacterSet()) -> String {
if let range = rangeOfCharacterFromSet(set.invertedSet, options: NSStringCompareOptions.BackwardsSearch) {
return self[startIndex..<range.endIndex]
}
return ""
}
@availability(*, unavailable, message="use 'trimmedRight' instead") func rtrimmed (set: NSCharacterSet = NSCharacterSet.whitespaceAndNewlineCharacterSet()) -> String {
return trimmedRight(characterSet: set)
}
/**
Strips whitespaces from both the beginning and the end of self.
:returns: Stripped string
*/
func trimmed () -> String {
return trimmedLeft().trimmedRight()
}
/**
Costructs a string using random chars from a given set.
:param: length String length. If < 1, it's randomly selected in the range 0..16
:param: charset Chars to use in the random string
:returns: Random string
*/
static func random (var length len: Int = 0, charset: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String {
if len < 1 {
len = Int.random(max: 16)
}
var result = String()
let max = charset.length - 1
len.times {
result += charset[Int.random(min: 0, max: max)]!
}
return result
}
/**
Parses a string containing a double numerical value into an optional double if the string is a well formed number.
:returns: A double parsed from the string or nil if it cannot be parsed.
*/
func toDouble() -> Double? {
let scanner = NSScanner(string: self)
var double: Double = 0
if scanner.scanDouble(&double) {
return double
}
return nil
}
/**
Parses a string containing a float numerical value into an optional float if the string is a well formed number.
:returns: A float parsed from the string or nil if it cannot be parsed.
*/
func toFloat() -> Float? {
let scanner = NSScanner(string: self)
var float: Float = 0
if scanner.scanFloat(&float) {
return float
}
return nil
}
/**
Parses a string containing a non-negative integer value into an optional UInt if the string is a well formed number.
:returns: A UInt parsed from the string or nil if it cannot be parsed.
*/
func toUInt() -> UInt? {
if let val = self.trimmed().toInt() {
if val < 0 {
return nil
}
return UInt(val)
}
return nil
}
/**
Parses a string containing a boolean value (true or false) into an optional Bool if the string is a well formed.
:returns: A Bool parsed from the string or nil if it cannot be parsed as a boolean.
*/
func toBool() -> Bool? {
let text = self.trimmed().lowercaseString
if text == "true" || text == "false" || text == "yes" || text == "no" {
return (text as NSString).boolValue
}
return nil
}
/**
Parses a string containing a date into an optional NSDate if the string is a well formed.
The default format is yyyy-MM-dd, but can be overriden.
:returns: A NSDate parsed from the string or nil if it cannot be parsed as a date.
*/
func toDate(format : String? = "yyyy-MM-dd") -> NSDate? {
let text = self.trimmed().lowercaseString
var dateFmt = NSDateFormatter()
dateFmt.timeZone = NSTimeZone.defaultTimeZone()
if let fmt = format {
dateFmt.dateFormat = fmt
}
return dateFmt.dateFromString(text)
}
/**
Parses a string containing a date and time into an optional NSDate if the string is a well formed.
The default format is yyyy-MM-dd hh-mm-ss, but can be overriden.
:returns: A NSDate parsed from the string or nil if it cannot be parsed as a date.
*/
func toDateTime(format : String? = "yyyy-MM-dd hh-mm-ss") -> NSDate? {
return toDate(format: format)
}
}
/**
Repeats the string first n times
*/
public func * (first: String, n: Int) -> String {
var result = String()
n.times {
result += first
}
return result
}
// Pattern matching using a regular expression
public func =~ (string: String, pattern: String) -> Bool {
let regex = ExSwift.regex(pattern, ignoreCase: false)!
let matches = regex.numberOfMatchesInString(string, options: nil, range: NSMakeRange(0, string.length))
return matches > 0
}
// Pattern matching using a regular expression
public func =~ (string: String, regex: NSRegularExpression) -> Bool {
let matches = regex.numberOfMatchesInString(string, options: nil, range: NSMakeRange(0, string.length))
return matches > 0
}
// This version also allowes to specify case sentitivity
public func =~ (string: String, options: (pattern: String, ignoreCase: Bool)) -> Bool {
if let matches = ExSwift.regex(options.pattern, ignoreCase: options.ignoreCase)?.numberOfMatchesInString(string, options: nil, range: NSMakeRange(0, string.length)) {
return matches > 0
}
return false
}
// Match against all the alements in an array of String
public func =~ (strings: [String], pattern: String) -> Bool {
let regex = ExSwift.regex(pattern, ignoreCase: false)!
return strings.all { $0 =~ regex }
}
public func =~ (strings: [String], options: (pattern: String, ignoreCase: Bool)) -> Bool {
return strings.all { $0 =~ options }
}
// Match against any element in an array of String
public func |~ (strings: [String], pattern: String) -> Bool {
let regex = ExSwift.regex(pattern, ignoreCase: false)!
return strings.any { $0 =~ regex }
}
public func |~ (strings: [String], options: (pattern: String, ignoreCase: Bool)) -> Bool {
return strings.any { $0 =~ options }
}

106
kplayer/master/MasterViewController.swift

@ -51,17 +51,11 @@ class MasterViewController: UITableViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
loadDirs("/srv/samba/ren/fav")
loadDirs("/srv/samba/ren/knk_archiv")
loadDirs("/srv/samba/ren/knk_archiv2")
loadDirs("/srv/samba/ren/knk_archiv3")
loadDirs("/srv/samba/ren/knk_archiv4")
// Do any additional setup after loading the view, typically from a nib. // Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem()
// self.navigationItem.leftBarButtonItem = self.editButtonItem()
let addButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "insertNewObject:")
self.navigationItem.rightBarButtonItem = addButton
// let addButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "insertNewObject:")
// self.navigationItem.rightBarButtonItem = addButton
if let split = self.splitViewController { if let split = self.splitViewController {
let controllers = split.viewControllers let controllers = split.viewControllers
self.detailViewController = controllers[controllers.count-1].topViewController as? DetailViewController self.detailViewController = controllers[controllers.count-1].topViewController as? DetailViewController
@ -75,9 +69,6 @@ class MasterViewController: UITableViewController {
// Dispose of any resources that can be recreated. // Dispose of any resources that can be recreated.
} }
func insertNewObject(sender: AnyObject) {
}
override func tableView(tableView: UITableView, accessoryButtonTappedForRowWithIndexPath indexPath: NSIndexPath) { override func tableView(tableView: UITableView, accessoryButtonTappedForRowWithIndexPath indexPath: NSIndexPath) {
let pc = MediaPhotoController() let pc = MediaPhotoController()
@ -98,6 +89,85 @@ class MasterViewController: UITableViewController {
presentViewController(navController, animated: false, completion: nil) presentViewController(navController, animated: false, completion: nil)
} }
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println ("\(indexPath.row)")
let selectedItem = items[indexPath.row]
if (selectedItem.type == ItemType.FOLDER) {
if (!selectedItem.children.isEmpty) {
if selectedItem.children[0].type != ItemType.FOLDER {
performSegueWithIdentifier("showDetail", sender: self)
return
}
}
}
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
// Imagine it's called MyCustomTableVC
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("mastertable") as! MasterViewController
if (selectedItem.type == ItemType.FOLDER) {
vc.navigationItem.title = selectedItem.name;
if !selectedItem.loaded {
let dir = selectedItem.root + "/" + selectedItem.path
// NetworkManager.sharedInstance.loadDirs(dir) { (g) in
NetworkManager.sharedInstance.loadPicDirs(dir) { (g) in
for f in g {
vc.addItem(f)
}
selectedItem.children = vc.items
selectedItem.loaded = true
var all :[MediaItem]?
for f in selectedItem.children {
if f.type == ItemType.FOLDER && f.path != "" {
self.navigationController!.pushViewController(vc, animated: true)
return
}
if f.type == ItemType.FOLDER && f.path == "" {
all = f.children
break
}
}
if all != nil {
selectedItem.children = all!
selectedItem.loaded = false
for f in all! {
f.loaded = false
f.parent = selectedItem
}
}
self.performSegueWithIdentifier("showDetail", sender: self)
return
}
}
else {
vc.items = selectedItem.children
navigationController!.pushViewController(vc, animated:true)
}
}
if (selectedItem.type == ItemType.ROOT) {
NetworkManager.sharedInstance.listDirs(selectedItem.root, completionHandler: {
(i) in
vc.items = i
vc.tableView.reloadData()
})
vc.navigationItem.title = selectedItem.name;
navigationController!.pushViewController(vc, animated:true)
}
}
override func shouldPerformSegueWithIdentifier(identifier:String!, sender: AnyObject?) -> Bool {
return false;
}
// MARK: - Segues // MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
@ -106,6 +176,8 @@ class MasterViewController: UITableViewController {
let item = items[indexPath.row] let item = items[indexPath.row]
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = item controller.detailItem = item
controller.defaultItemSize = CGSize(width: 300, height: 300)
item.children.sort({ item.children.sort({
$0.sortName < $1.sortName $0.sortName < $1.sortName
}) })
@ -115,6 +187,8 @@ class MasterViewController: UITableViewController {
i.index = j++ i.index = j++
} }
// controller.collectionView.reloadData()
NetworkManager.sharedInstance.loadItems(item) NetworkManager.sharedInstance.loadItems(item)
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem() controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true controller.navigationItem.leftItemsSupplementBackButton = true
@ -136,7 +210,6 @@ class MasterViewController: UITableViewController {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
self.configureCell(cell, atIndexPath: indexPath) self.configureCell(cell, atIndexPath: indexPath)
cell.accessoryType = UITableViewCellAccessoryType.DetailDisclosureButton
return cell return cell
} }
@ -154,6 +227,13 @@ class MasterViewController: UITableViewController {
func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) { func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
let object = items[indexPath.row] let object = items[indexPath.row]
cell.textLabel!.text = object.path cell.textLabel!.text = object.path
// if !object.children.isEmpty && object.children[0].type == ItemType.VIDEO {
// cell.accessoryType = UITableViewCellAccessoryType.DetailDisclosureButton
// }
// else {
cell.accessoryType = UITableViewCellAccessoryType.None
// }
} }

155
kplayer/photo/MediaPhotoController.swift

@ -14,22 +14,16 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView
var requests = Array<ImageLoadOperation>() var requests = Array<ImageLoadOperation>()
// var fetchers = [NetworkFetcher<UIImage>]()
let hqCache = Shared.imageCache // Cache<UIImage>(name: "hq")
lazy var operationQueue: NSOperationQueue = { lazy var operationQueue: NSOperationQueue = {
var queue = NSOperationQueue() var queue = NSOperationQueue()
queue.name = "Photo queue" queue.name = "Photo queue"
queue.maxConcurrentOperationCount = 1
queue.maxConcurrentOperationCount = 5
return queue return queue
}() }()
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
hqCache.addFormat(Format<UIImage>(name: "icons", diskCapacity: 0))
let backButton = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: Selector("back")) let backButton = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: Selector("back"))
navigationItem.leftBarButtonItems = [backButton] navigationItem.leftBarButtonItems = [backButton]
@ -40,6 +34,21 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView
self.photoAlbumView.reloadData(); self.photoAlbumView.reloadData();
self.photoScrubberView.reloadData(); self.photoScrubberView.reloadData();
let back = NSURLSessionConfiguration.ephemeralSessionConfiguration()
let bsession = NSURLSession(configuration: back)
for i in items {
let URL = NSURL(string: i.thumbUrlAbsolute)!
let fetcher = MediaFetcher<UIImage>(URL: URL, session: bsession)
let fetch = Shared.imageCache.fetch(fetcher: fetcher, formatName: HanekeGlobals.Cache.OriginalFormatName, failure: nil, success: nil)
fetch.onSuccess {
s in
println ("preload \(s)")
}
}
} }
func back() { func back() {
@ -92,57 +101,36 @@ println("\(count(items))")
func photoAlbumScrollView(photoAlbumScrollView: NIPhotoAlbumScrollView!, photoAtIndex: Int, photoSize: UnsafeMutablePointer<NIPhotoScrollViewPhotoSize>, func photoAlbumScrollView(photoAlbumScrollView: NIPhotoAlbumScrollView!, photoAtIndex: Int, photoSize: UnsafeMutablePointer<NIPhotoScrollViewPhotoSize>,
isLoading: UnsafeMutablePointer<ObjCBool>, originalPhotoDimensions: UnsafeMutablePointer<CGSize>) -> UIImage! { isLoading: UnsafeMutablePointer<ObjCBool>, originalPhotoDimensions: UnsafeMutablePointer<CGSize>) -> UIImage! {
let c = count(items) let c = count(items)
println ("Index: \(photoAtIndex) of \(c)")
// println("Index: \(photoAtIndex) of \(c)")
let newItem = items[photoAtIndex] let newItem = items[photoAtIndex]
let hqURL = NSURL(string: newItem.imageUrlAbsolute)! let hqURL = NSURL(string: newItem.imageUrlAbsolute)!
let URL = NSURL(string: newItem.thumbUrlAbsolute)!
var image: UIImage? = nil var image: UIImage? = nil
var size = NIPhotoScrollViewPhotoSizeUnknown var size = NIPhotoScrollViewPhotoSizeUnknown
hqCache.fetch(key: hqURL.absoluteString!, formatName: HanekeGlobals.Cache.OriginalFormatName).onSuccess {
Shared.imageCache.fetch(key: URL.absoluteString!, formatName: HanekeGlobals.Cache.OriginalFormatName).onSuccess {
i in i in
println ("cached \(newItem.imageUrlAbsolute)")
image = i image = i
size = NIPhotoScrollViewPhotoSizeOriginal
size = NIPhotoScrollViewPhotoSizeThumbnail
self.photoAlbumView.didLoadPhoto(image, atIndex: photoAtIndex, photoSize: size) self.photoAlbumView.didLoadPhoto(image, atIndex: photoAtIndex, photoSize: size)
} }
// var fetcher = Shared.imageCache.fetch(URL: URL)
// let fs = Shared.imageCache.formats
// if let (format, memoryCache, diskCache) = fs[HanekeGlobals.Cache.OriginalFormatName] {
// if memoryCache.objectForKey(URL!.absoluteString!) != nil {
// Shared.imageCache.fetch(URL: URL).onSuccess {
// i in
// println ("loaded \(newItem.imageUrlAbsolute)")
// image = i
// size = NIPhotoScrollViewPhotoSizeOriginal
// self.photoAlbumView.didLoadPhoto(image, atIndex:photoAtIndex, photoSize:size)
// }
// }
// }
// if (fetcher != nil) {
// fetcher!.cancelFetch()
// }
// fetcher = NetworkFetcher<UIImage>(URL: URL)
// let fetch = Shared.imageCache.fetch(fetcher: fetcher!, formatName: HanekeGlobals.Cache.OriginalFormatName, failure: nil, success: nil)
//
// fetch.onSuccess {
// i in
// println ("loaded \(newItem.imageUrlAbsolute)")
// image = i
// size = NIPhotoScrollViewPhotoSizeOriginal
// self.photoAlbumView.didLoadPhoto(image, atIndex:photoAtIndex, photoSize:size)
// }
if let i = image { if let i = image {
isLoading[0] = false isLoading[0] = false
}
else {
println ("not cached \(newItem.imageUrlAbsolute)")
} else {
let fetcher = NetworkFetcher<UIImage>(URL: URL)
let fetch = Shared.imageCache.fetch(fetcher: fetcher, formatName: HanekeGlobals.Cache.OriginalFormatName, failure: nil, success: nil)
let URL = NSURL(string: newItem.thumbUrlAbsolute)!
println (newItem.thumbUrlAbsolute)
var image: UIImage? = nil
fetch.onSuccess {
i in
println("thumb loaded \(newItem.imageUrlAbsolute)")
image = i
size = NIPhotoScrollViewPhotoSizeThumbnail
self.photoAlbumView.didLoadPhoto(image, atIndex: photoAtIndex, photoSize: size)
}
}
for r in requests { for r in requests {
let pages = self.photoAlbumView.visiblePages() as NSMutableSet! let pages = self.photoAlbumView.visiblePages() as NSMutableSet!
@ -155,87 +143,28 @@ println("\(count(items))")
} }
if !ok { if !ok {
println("canceled \(r.imageURL)")
r.cancel() r.cancel()
requests.remove(r) requests.remove(r)
} }
} }
// let op = HanekeFetchOperation(baseUrl: URL, succeeder: {
// i in
// image = i
// size = NIPhotoScrollViewPhotoSizeThumbnail
// self.photoAlbumView.didLoadPhoto(image, atIndex:photoAtIndex, photoSize:size)
// println ("thumb \(URL.absoluteString!)")
// photoSize[0] = size
// }, index: photoAtIndex)
// requests.append(op)
// self.operationQueue.addOperation(op)
let fetcher = NetworkFetcher<UIImage>(URL: URL)
let fetch = Shared.imageCache.fetch(fetcher: fetcher, formatName: HanekeGlobals.Cache.OriginalFormatName, failure: nil, success: nil)
fetch.onSuccess {
i in
println ("loaded \(newItem.imageUrlAbsolute)")
image = i
size = NIPhotoScrollViewPhotoSizeThumbnail
self.photoAlbumView.didLoadPhoto(image, atIndex:photoAtIndex, photoSize:size)
}
let op2 = ImageLoadOperation(imageURL: hqURL, succeeder: { let op2 = ImageLoadOperation(imageURL: hqURL, succeeder: {
i in i in
println ("loaded \(newItem.imageUrlAbsolute) at \(photoAtIndex)")
image = i
println("image loaded \(newItem.imageUrlAbsolute) at \(photoAtIndex)")
size = NIPhotoScrollViewPhotoSizeOriginal size = NIPhotoScrollViewPhotoSizeOriginal
self.photoAlbumView.didLoadPhoto(image, atIndex:photoAtIndex, photoSize:size)
self.photoAlbumView.didLoadPhoto(i, atIndex: photoAtIndex, photoSize: size)
photoSize[0] = size photoSize[0] = size
}, index: photoAtIndex) }, index: photoAtIndex)
requests.append(op2) requests.append(op2)
op2.qualityOfService = NSQualityOfService.UserInteractive
self.operationQueue.addOperation(op2)
// NSURLSession.sharedSession().invalidateAndCancel();
// for f in fetchers {
// println ("cancel \(f.key)")
// f.cancelFetch()
// }
// fetchers.removeAll()
// let fetcher = NetworkFetcher<UIImage>(URL: hqURL)
// fetchers.append(fetcher)
//
// let fetch = hqCache.fetch(fetcher: fetcher, formatName: "icons", failure: nil, success: nil)
//
// fetch.onSuccess {
// i in
// println ("loaded \(newItem.imageUrlAbsolute) at \(photoAtIndex)")
// image = i
// size = NIPhotoScrollViewPhotoSizeOriginal
// self.photoAlbumView.didLoadPhoto(image, atIndex:photoAtIndex, photoSize:size)
// photoSize[0] = size
// return
// }
// Shared.imageCache.fetch(URL: hqURL).onSuccess {
// i in
// println ("loaded \(newItem.imageUrlAbsolute)")
// image = i
// size = NIPhotoScrollViewPhotoSizeOriginal
// self.photoAlbumView.didLoadPhoto(image, atIndex:photoAtIndex, photoSize:size)
// }
operationQueue.addOperation(op2)
if (image == nil) { if (image == nil) {
isLoading[0] = true isLoading[0] = true
} }
}
photoSize[0] = size photoSize[0] = size
// if image == nil { return UIImage(named: "Kirschkeks-256x256.png") }
// self.photoAlbumView.didLoadPhoto(image, atIndex:photoAtIndex, photoSize:size)
return image return image
} }
@ -275,7 +204,6 @@ println("\(count(items))")
} }
let c = count(items) let c = count(items)
println ("Thumb Index: \(thumbnailIndex) of \(c)")
let newItem = items[thumbnailIndex] let newItem = items[thumbnailIndex]
let URL = NSURL(string: newItem.thumbUrlAbsolute)! let URL = NSURL(string: newItem.thumbUrlAbsolute)!
@ -284,14 +212,21 @@ println("\(count(items))")
Shared.imageCache.fetch(URL: URL).onSuccess { Shared.imageCache.fetch(URL: URL).onSuccess {
i in i in
image = i image = i
println ("thumb scrubber \(URL.absoluteString!)")
self.photoScrubberView.didLoadThumbnail(i, atIndex: thumbnailIndex); self.photoScrubberView.didLoadThumbnail(i, atIndex: thumbnailIndex);
} }
// if image == nil { return UIImage(named: "Kirschkeks-256x256.png") }
return image return image
} }
}
class MediaFetcher<T : DataConvertible> : NetworkFetcher<T> {
let bsession: NSURLSession?
init(URL : NSURL, session: NSURLSession) {
self.bsession = session
super.init(URL: URL)
}
override public var session : NSURLSession { return bsession! }
} }

32
kplayer/util/HanekeFetchOperation.swift

@ -0,0 +1,32 @@
//
// Created by Marco Schmickler on 21.03.15.
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
//
import Foundation
import Haneke
class HanekeFetchOperation: NSOperation {
let baseUrl: NSURL
let succeeder: Fetch<UIImage>.Succeeder
let index: Int
init(baseUrl: NSURL, succeeder: Fetch<UIImage>.Succeeder, index: Int) {
self.baseUrl = baseUrl
self.succeeder = succeeder
self.index = index
}
override func main() {
if self.cancelled {
return
}
Shared.imageCache.fetch(URL: baseUrl).onSuccess { i in
dispatch_async(dispatch_get_main_queue(), { self.succeeder(i) })
}
}
}

46
kplayer/util/ImageLoadOperation.swift

@ -0,0 +1,46 @@
//
// Created by Marco Schmickler on 21.03.15.
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
//
import Foundation
import Alamofire
import Darwin
class ImageLoadOperation: NSOperation {
public typealias Succeeder = (UIImage) -> ()
let imageURL: NSURL
let succeeder: Succeeder
let index: Int
init(imageURL: NSURL, succeeder: Succeeder, index: Int) {
self.imageURL = imageURL
self.succeeder = succeeder
self.index = index
}
override func main() {
if self.cancelled {
return
}
usleep(100000)
if self.cancelled {
return
}
Alamofire.request(.GET, imageURL).validate().responseImage() {
(request, _, image, error) in
if error == nil {
// if request.URLString.isEqual(self.imageURL) {
self.succeeder(image!)
// }
}
}
}
}

28
kplayer/util/alamoimage.swift

@ -0,0 +1,28 @@
//
// Created by Marco Schmickler on 22.06.15.
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
//
import Foundation
import Alamofire
extension Alamofire.Request {
class func imageResponseSerializer() -> Serializer {
return { request, response, data in
if data == nil {
return (nil, nil)
}
let i = UIImage(data: data!)
// let image = i.hnk_decompressedImage()
return (i, nil)
}
}
func responseImage(completionHandler: (NSURLRequest, NSHTTPURLResponse?, UIImage?, NSError?) -> Void) -> Self {
return response(serializer: Request.imageResponseSerializer(), completionHandler: { (request, response, image, error) in
completionHandler(request, response, image as? UIImage, error)
})
}
}
Loading…
Cancel
Save