Browse Source

init

master
Marco Schmickler 11 years ago
parent
commit
4027ef583b
  1. 3
      Podfile
  2. 32
      kplayer.xcodeproj/project.pbxproj
  3. 58
      kplayer/Base.lproj/Main.storyboard
  4. 247
      kplayer/DetailViewController.swift
  5. 19
      kplayer/ItemCell.swift
  6. 1
      kplayer/MasterViewController.swift
  7. 231
      kplayer/VideoPlayerController.swift
  8. 59
      kplayer/core/ImageLoadOperation.swift
  9. 16
      kplayer/core/MediaItem.swift
  10. 54
      kplayer/core/NetData.swift
  11. 59
      kplayer/core/NetworkHelper.swift
  12. 146
      kplayer/core/NetworkManager.swift
  13. 38
      kplayer/core/UploadOperation.swift
  14. 48
      kplayer/core/alamojson.swift
  15. 27
      kplayer/util/UIImageExtension.swift

3
Podfile

@ -5,3 +5,6 @@ use_frameworks!
# pod 'Player' # pod 'Player'
pod 'Alamofire', '~> 1.2' pod 'Alamofire', '~> 1.2'
pod 'ALMoviePlayerController', '~>0.3.0'
pod 'SwiftyJSON'
pod 'HanekeSwift'

32
kplayer.xcodeproj/project.pbxproj

@ -12,6 +12,12 @@
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 */; };
1C73641627BE29D9FA819F3C /* LayoutTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73649CEA7BDD2AC1496F76 /* LayoutTools.swift */; }; 1C73641627BE29D9FA819F3C /* LayoutTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73649CEA7BDD2AC1496F76 /* LayoutTools.swift */; };
1C736503B656C999E5E12081 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */; }; 1C736503B656C999E5E12081 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */; };
1C73664F657BE51633B69851 /* alamojson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736683E76027D72412D440 /* alamojson.swift */; };
1C73670791CDD5C9BB6B1DDC /* NetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364950C3B8C5DFA243D62 /* NetData.swift */; };
1C7367A160B25EEC5E99A517 /* ImageLoadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736E98DC8F46C7FF9CD540 /* ImageLoadOperation.swift */; };
1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */; };
1C736AD52D967F2F4000F997 /* UploadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7362F9C26405D4F3FA15A1 /* UploadOperation.swift */; };
1C736BF3C4F2D3BE570A89C7 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7368F1190278747E95C12F /* NetworkHelper.swift */; };
1C736C90DB50C4FDED266C3D /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7362C647AEBF03F5FD9FEB /* ItemCell.swift */; }; 1C736C90DB50C4FDED266C3D /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7362C647AEBF03F5FD9FEB /* 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, ); }; };
@ -38,12 +44,18 @@
/* 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; };
1C7362C647AEBF03F5FD9FEB /* ItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = "<group>"; }; 1C7362C647AEBF03F5FD9FEB /* ItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = "<group>"; };
1C7362F9C26405D4F3FA15A1 /* UploadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadOperation.swift; sourceTree = "<group>"; };
1C7364950C3B8C5DFA243D62 /* NetData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetData.swift; sourceTree = "<group>"; };
1C73649CEA7BDD2AC1496F76 /* LayoutTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutTools.swift; sourceTree = "<group>"; }; 1C73649CEA7BDD2AC1496F76 /* LayoutTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutTools.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>"; };
1C736683E76027D72412D440 /* alamojson.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = alamojson.swift; sourceTree = "<group>"; };
1C7366EF59D75216EBC0D3F0 /* VideoPlayerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoPlayerController.swift; sourceTree = "<group>"; }; 1C7366EF59D75216EBC0D3F0 /* VideoPlayerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoPlayerController.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>"; };
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>"; };
1C7368F1190278747E95C12F /* NetworkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkHelper.swift; sourceTree = "<group>"; };
1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = "<group>"; };
1C736E98DC8F46C7FF9CD540 /* ImageLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageLoadOperation.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; };
@ -80,11 +92,24 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
1C7365603CAE04E39B73D843 /* util */ = {
isa = PBXGroup;
children = (
1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */,
);
path = util;
sourceTree = "<group>";
};
1C736DC8C3AFB991541A2079 /* core */ = { 1C736DC8C3AFB991541A2079 /* core */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */, 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */,
1C73688DAB88F9360FB62A49 /* MediaItem.swift */, 1C73688DAB88F9360FB62A49 /* MediaItem.swift */,
1C7362F9C26405D4F3FA15A1 /* UploadOperation.swift */,
1C7368F1190278747E95C12F /* NetworkHelper.swift */,
1C7364950C3B8C5DFA243D62 /* NetData.swift */,
1C736683E76027D72412D440 /* alamojson.swift */,
1C736E98DC8F46C7FF9CD540 /* ImageLoadOperation.swift */,
); );
path = core; path = core;
sourceTree = "<group>"; sourceTree = "<group>";
@ -143,6 +168,7 @@
1C73649CEA7BDD2AC1496F76 /* LayoutTools.swift */, 1C73649CEA7BDD2AC1496F76 /* LayoutTools.swift */,
1C7368DC7EF11A553145E169 /* Kirschkeks-256x256.png */, 1C7368DC7EF11A553145E169 /* Kirschkeks-256x256.png */,
1C7366EF59D75216EBC0D3F0 /* VideoPlayerController.swift */, 1C7366EF59D75216EBC0D3F0 /* VideoPlayerController.swift */,
1C7365603CAE04E39B73D843 /* util */,
); );
path = kplayer; path = kplayer;
sourceTree = "<group>"; sourceTree = "<group>";
@ -333,6 +359,12 @@
1C736C90DB50C4FDED266C3D /* ItemCell.swift in Sources */, 1C736C90DB50C4FDED266C3D /* ItemCell.swift in Sources */,
1C73641627BE29D9FA819F3C /* LayoutTools.swift in Sources */, 1C73641627BE29D9FA819F3C /* LayoutTools.swift in Sources */,
1C736261CBA1D13D16DCBAFB /* VideoPlayerController.swift in Sources */, 1C736261CBA1D13D16DCBAFB /* VideoPlayerController.swift in Sources */,
1C736AD52D967F2F4000F997 /* UploadOperation.swift in Sources */,
1C736BF3C4F2D3BE570A89C7 /* NetworkHelper.swift in Sources */,
1C73670791CDD5C9BB6B1DDC /* NetData.swift in Sources */,
1C73664F657BE51633B69851 /* alamojson.swift in Sources */,
1C7367A160B25EEC5E99A517 /* ImageLoadOperation.swift in Sources */,
1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

58
kplayer/Base.lproj/Main.storyboard

@ -50,12 +50,68 @@
<navigationItem key="navigationItem" title="Detail" id="mOI-FS-AaM"/> <navigationItem key="navigationItem" title="Detail" id="mOI-FS-AaM"/>
<connections> <connections>
<outlet property="detailDescriptionLabel" destination="0XM-y9-sOw" id="deQ-Na-JPF"/> <outlet property="detailDescriptionLabel" destination="0XM-y9-sOw" id="deQ-Na-JPF"/>
<segue destination="H2f-hD-mj0" kind="presentation" identifier="showVideo" id="In3-xv-Uwk"/>
</connections> </connections>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="709" y="129"/> <point key="canvasLocation" x="709" y="129"/>
</scene> </scene>
<!--Video-->
<scene sceneID="6y1-jK-8xM">
<objects>
<viewController id="yqJ-Uz-RRd" customClass="VideoPlayerController" customModule="kplayer" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="t7F-Sd-USd"/>
<viewControllerLayoutGuide type="bottom" id="xB2-3N-aYI"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Hzn-H1-qwy">
<rect key="frame" x="0.0" y="94" width="600" height="536"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
<navigationItem key="navigationItem" title="Video" id="gsi-1J-w6z">
<barButtonItem key="backBarButtonItem" title="back" id="mQc-4U-xZS"/>
<barButtonItem key="leftBarButtonItem" style="plain" id="cd5-8s-DNN">
<button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="TxA-bq-Yuj">
<rect key="frame" x="-23" y="-15" width="133" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="zurück">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="back:" destination="yqJ-Uz-RRd" eventType="touchUpInside" id="a9M-Xh-Oid"/>
</connections>
</button>
</barButtonItem>
<connections>
<outlet property="backBarButtonItem" destination="cd5-8s-DNN" id="DKb-D2-VLe"/>
</connections>
</navigationItem>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" barStyle="black" translucent="NO" prompted="NO"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Wef-7T-g7k" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="705" y="841"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="thV-ok-QsE">
<objects>
<navigationController id="H2f-hD-mj0" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="u2K-vF-nU5">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="yqJ-Uz-RRd" kind="relationship" relationship="rootViewController" id="pGG-bu-FAP"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="yjJ-EY-Ybv" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-65" y="877"/>
</scene>
<!--Split View Controller--> <!--Split View Controller-->
<scene sceneID="Nki-YV-4Qg"> <scene sceneID="Nki-YV-4Qg">
<objects> <objects>
@ -130,6 +186,6 @@
</scene> </scene>
</scenes> </scenes>
<inferredMetricsTieBreakers> <inferredMetricsTieBreakers>
<segue reference="6S0-TO-JiA"/>
<segue reference="Tll-UG-LXB"/>
</inferredMetricsTieBreakers> </inferredMetricsTieBreakers>
</document> </document>

247
kplayer/DetailViewController.swift

@ -7,16 +7,16 @@
// //
import UIKit import UIKit
import MediaPlayer
class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
@IBOutlet weak var detailDescriptionLabel: UILabel! @IBOutlet weak var detailDescriptionLabel: UILabel!
var moviePlayer: MPMoviePlayerController?
var collectionView: UICollectionView! var collectionView: UICollectionView!
var currentItem: MediaItem?
var detailItem: MediaItem? { var detailItem: MediaItem? {
didSet { didSet {
println(detailItem!.children) println(detailItem!.children)
@ -28,8 +28,6 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
} }
} }
var currentItem: MediaItem?
func configureView() { func configureView() {
// Update the user interface for the detail item. // Update the user interface for the detail item.
println(detailItem) println(detailItem)
@ -48,92 +46,18 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
println(url) println(url)
// if moviePlayer == nil { // if moviePlayer == nil {
play(url)
// play(url)
// } // }
} }
} }
} }
func play(url: String) {
self.moviePlayer = MPMoviePlayerController()
if let player = self.moviePlayer {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("exitedFullscreen"), name: MPMoviePlayerDidExitFullscreenNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("enteredFullscreen"), name: MPMoviePlayerDidEnterFullscreenNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("showThumbnail:"), name: MPMoviePlayerThumbnailImageRequestDidFinishNotification, object: nil);
player.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
player.view.sizeToFit()
player.scalingMode = MPMovieScalingMode.AspectFit
player.controlStyle = MPMovieControlStyle.Embedded
player.movieSourceType = MPMovieSourceType.Streaming
player.repeatMode = MPMovieRepeatMode.One
player.contentURL = NSURL(string: url)
player.play()
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("update"), userInfo: nil, repeats: false)
self.view.addSubview(player.view)
}
}
func showThumbnail(note: NSNotification) {
let userInfo = note.userInfo! as NSDictionary
let thumbnail = userInfo.objectForKey(MPMoviePlayerThumbnailImageKey) as! UIImage
let time = userInfo.objectForKey(MPMoviePlayerThumbnailTimeKey) as! NSTimeInterval
let newItem = MediaItem(name: currentItem!.name, path: currentItem!.path, root: currentItem!.root, type: ItemType.SNAPSHOT)
newItem.image = thumbnail
newItem.time = time
newItem.parent = currentItem!
currentItem!.children.append(newItem)
println (newItem.time)
}
func update() {
if let player = self.moviePlayer {
if let t = currentItem!.time {
player.currentPlaybackTime = t
}
else {
println(player.duration)
player.currentPlaybackTime = player.duration / 2
}
if currentItem!.type == ItemType.SNAPSHOT {
currentItem = currentItem!.parent
}
player.fullscreen = true
}
}
func enteredFullscreen() {
let mp = UIApplication.sharedApplication().keyWindow;
if let moviePlayerContainer = recursiveSearchForViewWithName(mp!, classname: "MPVideoContainerView") {
if (moviePlayerContainer.gestureRecognizers != nil) {
return;
}
installGestures(moviePlayerContainer)
}
}
func exitedFullscreen() {
moviePlayer!.view.removeFromSuperview();
moviePlayer = nil;
NSNotificationCenter.defaultCenter().removeObserver(self);
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
}
override func loadView() { override func loadView() {
super.loadView() super.loadView()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("refreshItems:"), name: "loadedItems", object: nil)
} }
override func viewDidLoad() { override func viewDidLoad() {
@ -142,7 +66,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2) layout.sectionInset = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
layout.itemSize = CGSize(width: 14 * 16 , height: 14 * 10)
layout.itemSize = CGSize(width: 14 * 16, height: 14 * 10)
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)
@ -153,11 +77,67 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
collectionView.registerClass(ItemCell.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderView"); collectionView.registerClass(ItemCell.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderView");
view.addSubview(collectionView) view.addSubview(collectionView)
// view.autoresizesSubviews = true
// collectionView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
view.autoresizesSubviews = true
collectionView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
// Do any additional setup after loading the view, typically from a nib. // Do any additional setup after loading the view, typically from a nib.
collectionView.reloadData() collectionView.reloadData()
// attach long press gesture to collectionView
let lpgr = UILongPressGestureRecognizer(target: self, action: Selector("handleLongPress:"))
lpgr.minimumPressDuration = 3; //seconds
lpgr.delaysTouchesBegan = true
self.collectionView.addGestureRecognizer(lpgr);
}
func refreshItems(notification: NSNotification) {
let index = notification.object as! Int
if let detail: MediaItem = self.detailItem {
collectionView.performBatchUpdates( {
let path = NSIndexPath(forItem: 0, inSection: index)
self.collectionView.reloadItemsAtIndexPaths([path])
var newItems = [NSIndexPath]()
var j = 0
for i in detail.children[index].children {
if j >= 1 {
newItems.append(NSIndexPath(forItem: j, inSection: index))
}
j++
}
self.collectionView.insertItemsAtIndexPaths(newItems)
return
}, completion: nil)
}
}
func handleLongPress(gestureRecognizer: UILongPressGestureRecognizer) {
if (gestureRecognizer.state != UIGestureRecognizerState.Ended) {
return;
}
let p = gestureRecognizer.locationInView(self.collectionView);
let indexPath = self.collectionView.indexPathForItemAtPoint(p);
if (indexPath == nil) {
println("couldn't find index path");
} else {
if let detail: MediaItem = self.detailItem {
if (detail.loaded) {
let items = detail.children[indexPath!.section]
if count(items.children) == 0 {
} else {
if indexPath!.item >= count(items.children) {
} else {
items.children.removeAtIndex(indexPath!.item)
self.collectionView.reloadData()
}
}
}
}
}
} }
override func viewDidAppear(animated: Bool) { override func viewDidAppear(animated: Bool) {
@ -183,7 +163,13 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let detail: MediaItem = self.detailItem { if let detail: MediaItem = self.detailItem {
return count(detail.children[section].children) + 1
let n = count(detail.children[section].children)
if n == 0 {
return 1
}
println(n)
return n
} }
return 0 return 0
} }
@ -193,6 +179,9 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
if let detail: MediaItem = self.detailItem { if let detail: MediaItem = self.detailItem {
let items = detail.children[indexPath.section] let items = detail.children[indexPath.section]
if count(items.children) == 0 {
cell.setItem(items)
} else {
if indexPath.item >= count(items.children) { if indexPath.item >= count(items.children) {
cell.setItem(items) cell.setItem(items)
} else { } else {
@ -200,6 +189,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
cell.setItem(item) cell.setItem(item)
} }
} }
}
cell.backgroundColor = UIColor.blueColor() cell.backgroundColor = UIColor.blueColor()
return cell return cell
} }
@ -216,8 +206,6 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
as! ItemCell as! ItemCell
let items = detailItem!.children[indexPath.section] let items = detailItem!.children[indexPath.section]
println("sec \(indexPath.section) " + items.name)
headerView.label.text = items.name headerView.label.text = items.name
headerView.backgroundColor = UIColor.yellowColor() headerView.backgroundColor = UIColor.yellowColor()
return headerView return headerView
@ -228,6 +216,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if let detail: MediaItem = self.detailItem { if let detail: MediaItem = self.detailItem {
if (detail.loaded) {
var items = detail.children[indexPath.section] var items = detail.children[indexPath.section]
if indexPath.item >= count(items.children) { if indexPath.item >= count(items.children) {
println(items.name) println(items.name)
@ -236,82 +225,36 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
println(items.name) println(items.name)
} }
currentItem = items
var url = NetworkManager.sharedInstance.playerURL(items)
println(url)
play(url)
self.currentItem = items
performSegueWithIdentifier("showVideo", sender: self)
} }
} }
func installGestures(moviePlayer: UIView) {
let twoFingersTwoTaps = UITapGestureRecognizer(target: self, action: "twoFingersTwoTaps")
twoFingersTwoTaps.numberOfTapsRequired = 2
twoFingersTwoTaps.numberOfTouchesRequired = 2
moviePlayer.addGestureRecognizer(twoFingersTwoTaps)
let sR = UISwipeGestureRecognizer(target: self, action: "swipeRight")
sR.direction = UISwipeGestureRecognizerDirection.Right
sR.numberOfTouchesRequired = 1
moviePlayer.addGestureRecognizer(sR)
let sL = UISwipeGestureRecognizer(target: self, action: "swipeLeft")
sL.direction = UISwipeGestureRecognizerDirection.Left
sL.numberOfTouchesRequired = 1
moviePlayer.addGestureRecognizer(sL)
let sR2 = UISwipeGestureRecognizer(target: self, action: "swipeDown")
sR2.direction = UISwipeGestureRecognizerDirection.Down
sR2.numberOfTouchesRequired = 1
moviePlayer.addGestureRecognizer(sR2)
} }
func swipeRight() {
println("r")
if let player = self.moviePlayer {
player.currentPlaybackTime = player.currentPlaybackTime + 30.0
}
}
// MARK: - Segues
func swipeDown() {
println("r")
if let player = self.moviePlayer {
player.currentPlaybackTime = player.currentPlaybackTime + 10.0
}
}
func swipeLeft() {
println("l")
if let player = self.moviePlayer {
player.currentPlaybackTime = player.currentPlaybackTime - 30.0
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showVideo" {
let nc = segue.destinationViewController as! UINavigationController
let controller = nc.topViewController as! VideoPlayerController
controller.currentItem = self.currentItem
// controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
nc.navigationBar.barTintColor = UIColor.blackColor()
func twoFingersTwoTaps() {
println("tap")
moviePlayer!.requestThumbnailImagesAtTimes([moviePlayer!.currentPlaybackTime],
timeOption:MPMovieTimeOption.NearestKeyFrame);
}
func recursiveSearchForViewWithName(view: UIView, classname: String) -> UIView? {
for v in view.subviews {
var result = recursiveSearchForViewWithName(v as! UIView, classname: classname)
let cn = toString(v.dynamicType)
controller.completionHandler = {
() in
self.collectionView.reloadData()
self.collectionView.collectionViewLayout.invalidateLayout()
if cn == classname {
return v as! UIView
if self.currentItem!.type == ItemType.SNAPSHOT {
self.currentItem = self.currentItem!.parent
} }
if result != nil {
return result
NetworkManager.sharedInstance.saveItem(self.currentItem!)
self.dismissViewControllerAnimated(true, completion: nil);
} }
} }
return nil
} }
} }

19
kplayer/ItemCell.swift

@ -5,6 +5,7 @@
import Foundation import Foundation
import UIKit import UIKit
import Haneke
class ItemCell: UICollectionViewCell { class ItemCell: UICollectionViewCell {
var item: MediaItem? var item: MediaItem?
@ -25,7 +26,7 @@ class ItemCell: UICollectionViewCell {
label = UILabel(frame: frame) label = UILabel(frame: frame)
image = UIImageView()
image = UIImageView(frame: frame)
image.layer.borderWidth = 2.0; image.layer.borderWidth = 2.0;
autolayout(["label": label, "imag": image], autolayout(["label": label, "imag": image],
@ -38,16 +39,26 @@ class ItemCell: UICollectionViewCell {
func setItem(item: MediaItem) { func setItem(item: MediaItem) {
self.item = item self.item = item
if (item.type == ItemType.SNAPSHOT) {
label.hidden = true
}
else {
label.text = item.name label.text = item.name
label.hidden = false
}
if let url = item.thumbUrl {
image.hnk_setImageFromURL(NSURL(string: NetworkManager.sharedInstance.baseurl + "/service/download" + url)!)
}
else {
if let i = item.image { if let i = item.image {
println (i)
println(i)
image.image = i image.image = i
image.sizeToFit() image.sizeToFit()
}
else {
} else {
image.image = UIImage(named: "Kirschkeks-256x256.png") image.image = UIImage(named: "Kirschkeks-256x256.png")
} }
}
} }
} }

1
kplayer/MasterViewController.swift

@ -74,6 +74,7 @@ class MasterViewController: UITableViewController {
let object = items[indexPath.row] let object = items[indexPath.row]
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object controller.detailItem = object
NetworkManager.sharedInstance.loadItems(object)
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem() controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true controller.navigationItem.leftItemsSupplementBackButton = true
} }

231
kplayer/VideoPlayerController.swift

@ -4,6 +4,235 @@
// //
import Foundation import Foundation
import UIKit
import MediaPlayer
import ALMoviePlayerController
class VideoPlayerController {
class VideoPlayerController: UIViewController {
var moviePlayer: ALMoviePlayerController?
var currentItem: MediaItem?
var completionHandler: ((Void) -> Void)?
var buttons = Dictionary<UIButton, MediaItem>()
var index = 0
override func viewDidLoad() {
super.viewDidLoad()
var url = NetworkManager.sharedInstance.playerURL(currentItem!)
println(url)
play(url)
}
@IBAction func back(sender: AnyObject) {
if let player = self.moviePlayer {
player.stop()
}
completionHandler!()
}
func play(url: String) {
self.moviePlayer = ALMoviePlayerController(frame: CGRectMake(0, 0, 1024, 680))
if let player = self.moviePlayer {
let movieControls = ALMoviePlayerControls(moviePlayer: player, style: ALMoviePlayerControlsStyleDefault);
player.controls = movieControls
movieControls.style = ALMoviePlayerControlsStyleEmbedded
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("exitedFullscreen"), name: MPMoviePlayerDidExitFullscreenNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("enteredFullscreen"), name: MPMoviePlayerDidEnterFullscreenNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("showThumbnail:"), name: MPMoviePlayerThumbnailImageRequestDidFinishNotification, object: nil);
player.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
player.view.sizeToFit()
player.scalingMode = MPMovieScalingMode.AspectFill
// player.controlStyle = MPMovieControlStyle.Embedded
player.movieSourceType = MPMovieSourceType.Streaming
player.repeatMode = MPMovieRepeatMode.One
player.contentURL = NSURL(string: url)
player.play()
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("update"), userInfo: nil, repeats: false)
// view.autolayout(["controls": movieControls, "player": player.view],
// constraints:
// "H:|-[player]-|",
// "H:|-[controls]-|",
// "V:|-[player]-[controls(<=50)]-|" )
self.view.addSubview(player.view)
// view.addSubview(movieControls)
// player.setFrame(view.frame)
}
}
func showThumbnail(note: NSNotification) {
let userInfo = note.userInfo! as NSDictionary
let thumbnail = userInfo.objectForKey(MPMoviePlayerThumbnailImageKey) as! UIImage
let time = userInfo.objectForKey(MPMoviePlayerThumbnailTimeKey) as! NSTimeInterval
let newItem = MediaItem(name: currentItem!.name, path: currentItem!.path, root: currentItem!.root, type: ItemType.SNAPSHOT)
newItem.image = thumbnail
newItem.time = time
newItem.parent = currentItem!
currentItem!.children.append(newItem)
println(newItem.time)
addItemButton(newItem)
}
func addItemButton(newItem: MediaItem) {
let icon = newItem.image!.scaleToSize(66.0, height: 44.0)
let frame = CGRectMake(0, 0, 66.0, 44.0);
let button = UIButton(frame: frame)
button.setBackgroundImage(icon, forState: UIControlState.Normal);
button.showsTouchWhenHighlighted = true
button.addTarget(self, action: "thumbnailClicked:", forControlEvents: .TouchDown)
let barbutton = UIBarButtonItem(customView: button);
if navigationItem.rightBarButtonItems == nil {
navigationItem.rightBarButtonItems = []
}
navigationItem.rightBarButtonItems!.append(barbutton)
buttons[button] = newItem
}
func thumbnailClicked(source: UIButton) {
println(source)
moviePlayer!.currentPlaybackTime = buttons[source]!.time!
}
func update() {
if let player = self.moviePlayer {
installGestures(player.view)
if let t = currentItem!.time {
player.currentPlaybackTime = t
} else {
println(player.duration)
player.currentPlaybackTime = player.duration / 2
}
if currentItem!.type == ItemType.SNAPSHOT {
currentItem = currentItem!.parent
}
for c in currentItem!.children {
addItemButton(c)
}
// player.fullscreen = true
}
}
func enteredFullscreen() {
let mp = UIApplication.sharedApplication().keyWindow;
if let moviePlayerContainer = recursiveSearchForViewWithName(mp!, classname: "MPVideoContainerView") {
if (moviePlayerContainer.gestureRecognizers != nil) {
return;
}
installGestures(moviePlayerContainer)
}
}
func exitedFullscreen() {
moviePlayer!.view.removeFromSuperview();
moviePlayer = nil;
NSNotificationCenter.defaultCenter().removeObserver(self);
}
func installGestures(moviePlayer: UIView) {
let twoFingersTwoTaps = UITapGestureRecognizer(target: self, action: "twoFingersTwoTaps")
twoFingersTwoTaps.numberOfTapsRequired = 2
twoFingersTwoTaps.numberOfTouchesRequired = 2
moviePlayer.addGestureRecognizer(twoFingersTwoTaps)
let sR = UISwipeGestureRecognizer(target: self, action: "swipeRight")
sR.direction = UISwipeGestureRecognizerDirection.Right
sR.numberOfTouchesRequired = 1
moviePlayer.addGestureRecognizer(sR)
let sL = UISwipeGestureRecognizer(target: self, action: "swipeLeft")
sL.direction = UISwipeGestureRecognizerDirection.Left
sL.numberOfTouchesRequired = 1
moviePlayer.addGestureRecognizer(sL)
let sR2 = UISwipeGestureRecognizer(target: self, action: "swipeDown")
sR2.direction = UISwipeGestureRecognizerDirection.Down
sR2.numberOfTouchesRequired = 1
moviePlayer.addGestureRecognizer(sR2)
let sR3 = UISwipeGestureRecognizer(target: self, action: "swipeUp")
sR3.direction = UISwipeGestureRecognizerDirection.Up
sR3.numberOfTouchesRequired = 1
moviePlayer.addGestureRecognizer(sR3)
}
func swipeUp() {
println("u")
if let player = self.moviePlayer {
if index < count(currentItem!.children) - 1 {
index++;
}
else {
index = 0;
}
let child = currentItem!.children[index]
player.currentPlaybackTime = child.time!
}
}
func swipeRight() {
println("r")
if let player = self.moviePlayer {
player.currentPlaybackTime = player.currentPlaybackTime + 30.0
}
}
func swipeDown() {
println("r")
if let player = self.moviePlayer {
player.currentPlaybackTime = player.currentPlaybackTime + 10.0
}
}
func swipeLeft() {
println("l")
if let player = self.moviePlayer {
player.currentPlaybackTime = player.currentPlaybackTime - 30.0
}
}
func twoFingersTwoTaps() {
println("tap")
moviePlayer!.requestThumbnailImagesAtTimes([moviePlayer!.currentPlaybackTime],
timeOption: MPMovieTimeOption.NearestKeyFrame);
}
func recursiveSearchForViewWithName(view: UIView, classname: String) -> UIView? {
for v in view.subviews {
var result = recursiveSearchForViewWithName(v as! UIView, classname: classname)
let cn = toString(v.dynamicType)
if cn == classname {
return v as? UIView
}
if result != nil {
return result
}
}
return nil
}
} }

59
kplayer/core/ImageLoadOperation.swift

@ -0,0 +1,59 @@
//
// Created by Marco Schmickler on 21.03.15.
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
//
import Foundation
import Alamofire
import SwiftyJSON
class ImageLoadOperation: NSOperation {
let baseUrl: String
let item: MediaItem
init(baseUrl: String, item: MediaItem) {
self.baseUrl = baseUrl
self.item = item
}
override func main() {
if self.cancelled {
return
}
let path = baseUrl + "/service/download" + item.thumbUrl!
println(path)
Alamofire.request(.GET, path).validate().responseImage( {
(_, _, image, error) in
if error == nil && image != nil {
self.item.image = image
}
else {
println(error)
}
})
}
}
extension Alamofire.Request {
class func imageResponseSerializer() -> Serializer {
return { request, response, data in
if data == nil {
return (nil, nil)
}
let image = UIImage(data: data!) //, scale: UIScreen.mainScreen().scale)
return (image, 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)
})
}
}

16
kplayer/core/MediaItem.swift

@ -19,11 +19,14 @@ class MediaItem : DebugPrintable {
var image: UIImage? var image: UIImage?
var time: NSTimeInterval? var time: NSTimeInterval?
var thumbUrl: String?
var children: [MediaItem] var children: [MediaItem]
var parent: MediaItem? var parent: MediaItem?
var type: ItemType var type: ItemType
var loaded = false
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
@ -32,6 +35,19 @@ class MediaItem : DebugPrintable {
children = [MediaItem]() children = [MediaItem]()
} }
var thumbPath: String {
let len = count("/srv/samba/ren")
let tpath = "/srv/samba/ren/thumb" + (root as NSString).substringFromIndex(len) + "/" + path + "/" + name
return tpath + "/"
}
var fullPath: String {
let fpath = root + "/" + path + "/" + name
return fpath
}
var debugDescription: String { var debugDescription: String {
return root + " " + path + " " + name return root + " " + path + " " + name
} }

54
kplayer/core/NetData.swift

@ -0,0 +1,54 @@
//
// NetData.swift
// Net
//
// Created by Le Van Nghia on 8/3/14.
// Copyright (c) 2014 Le Van Nghia. All rights reserved.
//
import Foundation
import UIKit
enum MimeType: String {
case ImageJpeg = "image/jpeg"
case ImagePng = "image/png"
case ImageGif = "image/gif"
case Json = "application/json"
case Unknown = ""
func getString() -> String? {
switch self {
case .ImagePng:
fallthrough
case .ImageJpeg:
fallthrough
case .ImageGif:
fallthrough
case .Json:
return self.rawValue
case .Unknown:
fallthrough
default:
return nil
}
}
}
class NetData
{
let data: NSData
let mimeType: MimeType
let filename: String
init(data: NSData, mimeType: MimeType, filename: String) {
self.data = data
self.mimeType = mimeType
self.filename = filename
}
init(pngImage: UIImage, filename: String) {
data = UIImagePNGRepresentation(pngImage)
self.mimeType = MimeType.ImagePng
self.filename = filename
}
init(jpegImage: UIImage, compressionQuanlity: CGFloat, filename: String) {
data = UIImageJPEGRepresentation(jpegImage, compressionQuanlity)
self.mimeType = MimeType.ImageJpeg
self.filename = filename
}
}

59
kplayer/core/NetworkHelper.swift

@ -0,0 +1,59 @@
//
// Created by Marco Schmickler on 22.03.15.
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
//
import Foundation
import Alamofire
func urlRequestWithComponents(urlString: String, parameters: NSDictionary) -> (URLRequestConvertible, NSData) {
// create url request to send
var mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: urlString)!)
mutableURLRequest.HTTPMethod = Alamofire.Method.POST.rawValue
//let boundaryConstant = "myRandomBoundary12345"
let boundaryConstant = "NET-POST-boundary-\(arc4random())-\(arc4random())"
let contentType = "multipart/form-data;boundary=" + boundaryConstant
mutableURLRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")
// create upload data to send
let uploadData = NSMutableData()
// add parameters
for (key, value) in parameters {
uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
if value is NetData {
// add image
var postData = value as! NetData
//uploadData.appendData("Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(postData.filename)\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
// append content disposition
var filenameClause = " filename=\"\(postData.filename)\""
let contentDispositionString = "Content-Disposition: form-data; name=\"\(key)\";\(filenameClause)\r\n"
let contentDispositionData = contentDispositionString.dataUsingEncoding(NSUTF8StringEncoding)
uploadData.appendData(contentDispositionData!)
// append content type
//uploadData.appendData("Content-Type: image/png\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) // mark this.
let contentTypeString = "Content-Type: \(postData.mimeType.getString())\r\n\r\n"
let contentTypeData = contentTypeString.dataUsingEncoding(NSUTF8StringEncoding)
uploadData.appendData(contentTypeData!)
uploadData.appendData(postData.data)
} else {
uploadData.appendData("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n\(value)".dataUsingEncoding(NSUTF8StringEncoding)!)
}
}
uploadData.appendData("\r\n--\(boundaryConstant)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
// return URLRequestConvertible and NSData
return (Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: nil).0, uploadData)
}
class NetworkHelper {
}

146
kplayer/core/NetworkManager.swift

@ -5,12 +5,20 @@
import Foundation import Foundation
import Alamofire import Alamofire
import SwiftyJSON
class NetworkManager { class NetworkManager {
static let sharedInstance = NetworkManager() static let sharedInstance = NetworkManager()
let baseurl = "http://linkstation/tomcat/media" let baseurl = "http://linkstation/tomcat/media"
lazy var operationQueue: NSOperationQueue = {
var queue = NSOperationQueue()
queue.name = "Backup queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
func loadRoots() -> AnyObject { func loadRoots() -> AnyObject {
var itemsArray = []; var itemsArray = [];
@ -69,4 +77,142 @@ class NetworkManager {
func playerURL(item: MediaItem) -> String { func playerURL(item: MediaItem) -> String {
return baseurl + "/service/stream" + item.root + "/" + item.path + "/" + item.name return baseurl + "/service/stream" + item.root + "/" + item.path + "/" + item.name
} }
func loadItems(item: MediaItem) {
if (item.type != ItemType.FOLDER) {
return
}
if (item.loaded) {
return
}
var j = 0
for i in item.children {
loadItem(i, index: j)
j++
}
}
func loadItem(item: MediaItem, index: Int) {
if (item.type != ItemType.VIDEO) {
return
}
if item.loaded {
return
}
if !item.children.isEmpty {
return
}
let url = baseurl + "/service/listfiles" + item.thumbPath
println(url)
Alamofire.request(.GET, url).responseSwiftyJSON( {
(request, response, json, error) in
var hashes = Dictionary<String,String>()
for (a, c) in json {
// let (a,b) = j #
let b = c.object as! NSString
let p = b.lastPathComponent as NSString
if p.containsString("_thumb.jpg") {
let ts = p.substringToIndex(p.length - 10)
hashes[ts] = b as String
} else {
let ts = p.substringToIndex(p.length - 4)
if hashes[ts] == nil {
hashes[ts] = b as String
}
}
}
for (ts, p) in hashes {
println ("\(ts) \(p)")
let t = (ts as NSString).doubleValue / 1000
let snap = MediaItem(name: item.name, path: item.path, root: item.root, type:.SNAPSHOT)
snap.time = t
snap.thumbUrl = p
// let op = ImageLoadOperation(baseUrl: self.baseurl, item: snap)
// self.operationQueue.addOperation(op)
snap.parent = item
item.children.append(snap)
println ("Time: \(t)")
}
item.loaded = true
NSNotificationCenter.defaultCenter().postNotificationName("loadedItems", object: index)
// println(error)
})
}
func saveItem(item: MediaItem) {
println (item.children)
if (item.type != ItemType.VIDEO) {
return
}
let url = baseurl + "/service/listfiles" + item.thumbPath
println(url)
Alamofire.request(.GET, url).responseSwiftyJSON( {
(request, response, json, error) in
var hashes = NSMutableSet()
for (a, c) in json {
// let (a,b) = j #
let b = c.object as! String
hashes.addObject(b)
println(b)
}
for c in item.children {
if let t = c.time {
let ms = Int(t * 1000)
let p = c.thumbPath + "\(ms).jpg"
let pt = c.thumbPath + "\(ms)_thumb.jpg"
println (p)
if hashes.containsObject(pt) {
println ("contained")
}
else {
let imageData = UIImageJPEGRepresentation(c.image, 1.0);
let op = UploadOperation(baseUrl: self.baseurl, data: imageData, path: p)
self.operationQueue.addOperation(op)
let imageDataT = UIImageJPEGRepresentation(c.image!.scaleToSize(14 * 16, height: 14 * 10), 1.0);
let opT = UploadOperation(baseUrl: self.baseurl, data: imageDataT, path: pt)
self.operationQueue.addOperation(opT)
}
hashes.removeObject(p)
hashes.removeObject(pt)
}
}
for o in hashes {
println ("To delete \(o)")
Alamofire.request(.GET, self.baseurl + "/service/deletethumb\(o)")
}
println(error)
})
}
} }

38
kplayer/core/UploadOperation.swift

@ -0,0 +1,38 @@
//
// Created by Marco Schmickler on 21.03.15.
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
//
import Foundation
import Alamofire
import SwiftyJSON
class UploadOperation: NSOperation {
let baseUrl: String
let data: NSData
let path: String
init(baseUrl: String, data: NSData, path: String) {
self.baseUrl = baseUrl
self.data = data
self.path = path
}
override func main() {
if self.cancelled {
return
}
var parameters = [
"file": NetData(data: data, mimeType: MimeType.Json, filename: path),
"name": path
]
let urlRequest = urlRequestWithComponents(baseUrl + "/service/upload", parameters)
let request = Alamofire.upload(urlRequest)
// .progress {
// (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
// println("progress : \(totalBytesWritten) / \(totalBytesExpectedToWrite)")
// }
}
}

48
kplayer/core/alamojson.swift

@ -0,0 +1,48 @@
//
// AlamofireSwiftyJSON.swift
// AlamofireSwiftyJSON
//
// Created by Pinglin Tang on 14-9-22.
// Copyright (c) 2014 SwiftyJSON. All rights reserved.
//
import Foundation
import Alamofire
import SwiftyJSON
// MARK: - Request for Swift JSON
extension Request {
/**
Adds a handler to be called once the request has finished.
:param: completionHandler A closure to be executed once the request has finished. The closure takes 4 arguments: the URL request, the URL response, if one was received, the SwiftyJSON enum, if one could be created from the URL response and data, and any error produced while creating the SwiftyJSON enum.
:returns: The request.
*/
public func responseSwiftyJSON(completionHandler: (NSURLRequest, NSHTTPURLResponse?, SwiftyJSON.JSON, NSError?) -> Void) -> Self {
return responseSwiftyJSON(queue: nil, options: NSJSONReadingOptions.AllowFragments, completionHandler: completionHandler)
}
/**
Adds a handler to be called once the request has finished.
:param: queue The queue on which the completion handler is dispatched.
:param: options The JSON serialization reading options. `.AllowFragments` by default.
:param: completionHandler A closure to be executed once the request has finished. The closure takes 4 arguments: the URL request, the URL response, if one was received, the SwiftyJSON enum, if one could be created from the URL response and data, and any error produced while creating the SwiftyJSON enum.
:returns: The request.
*/
public func responseSwiftyJSON(queue: dispatch_queue_t? = nil, options: NSJSONReadingOptions = .AllowFragments, completionHandler: (NSURLRequest, NSHTTPURLResponse?, JSON, NSError?) -> Void) -> Self {
return response(queue: queue, serializer: Request.JSONResponseSerializer(options: options), completionHandler: {
(request, response, object, error) -> Void in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
var responseJSON: JSON
if error != nil || object == nil {
responseJSON = JSON.nullJSON
} else {
responseJSON = SwiftyJSON.JSON(object!)
}
dispatch_async(queue ?? dispatch_get_main_queue(), {
completionHandler(self.request, self.response, responseJSON, error)
})
})
})
}
}

27
kplayer/util/UIImageExtension.swift

@ -0,0 +1,27 @@
//
// Created by Marco Schmickler on 28.05.15.
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
//
import Foundation
import UIKit
extension UIImage {
func scaleToSize(width: CGFloat, height: CGFloat) -> UIImage {
UIGraphicsBeginImageContext(CGSizeMake(width, height));
let context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0.0, height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0.0, 0.0, width, height), self.CGImage);
let scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
}
Loading…
Cancel
Save