diff --git a/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.pbxproj b/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.pbxproj index df2009e..0631945 100644 --- a/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.pbxproj +++ b/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.pbxproj @@ -13,8 +13,8 @@ 4B4966481BF8F87E00CD6060 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B4966461BF8F87E00CD6060 /* Main.storyboard */; }; 4B49664A1BF8F87E00CD6060 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4B4966491BF8F87E00CD6060 /* Assets.xcassets */; }; 4B49664D1BF8F87E00CD6060 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B49664B1BF8F87E00CD6060 /* LaunchScreen.storyboard */; }; + 4B607D561BFCE0C2001090B5 /* MPMoviePlayerController-Subtitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B607D551BFCE0C2001090B5 /* MPMoviePlayerController-Subtitles.swift */; }; 4B711ABB1BF900530017C8DA /* trailer_720p.mov in Resources */ = {isa = PBXBuildFile; fileRef = 4B711ABA1BF900530017C8DA /* trailer_720p.mov */; }; - 4B711ABE1BF900D20017C8DA /* MPMoviePlayerController-Subtitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B711ABD1BF900D20017C8DA /* MPMoviePlayerController-Subtitles.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -26,8 +26,8 @@ 4B4966491BF8F87E00CD6060 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 4B49664C1BF8F87E00CD6060 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 4B49664E1BF8F87E00CD6060 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4B607D551BFCE0C2001090B5 /* MPMoviePlayerController-Subtitles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "MPMoviePlayerController-Subtitles.swift"; path = "../../MPMoviePlayerController-Subtitles.swift"; sourceTree = ""; }; 4B711ABA1BF900530017C8DA /* trailer_720p.mov */ = {isa = PBXFileReference; lastKnownFileType = video.quicktime; path = trailer_720p.mov; sourceTree = ""; }; - 4B711ABD1BF900D20017C8DA /* MPMoviePlayerController-Subtitles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MPMoviePlayerController-Subtitles.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -84,7 +84,7 @@ 4B711ABC1BF900A90017C8DA /* MPMoviePlayerController-Subtitles */ = { isa = PBXGroup; children = ( - 4B711ABD1BF900D20017C8DA /* MPMoviePlayerController-Subtitles.swift */, + 4B607D551BFCE0C2001090B5 /* MPMoviePlayerController-Subtitles.swift */, ); name = "MPMoviePlayerController-Subtitles"; sourceTree = ""; @@ -162,7 +162,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4B711ABE1BF900D20017C8DA /* MPMoviePlayerController-Subtitles.swift in Sources */, + 4B607D561BFCE0C2001090B5 /* MPMoviePlayerController-Subtitles.swift in Sources */, 4B4966451BF8F87E00CD6060 /* ViewController.swift in Sources */, 4B4966431BF8F87E00CD6060 /* AppDelegate.swift in Sources */, ); diff --git a/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.xcworkspace/xcuserdata/mhergon.xcuserdatad/UserInterfaceState.xcuserstate b/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.xcworkspace/xcuserdata/mhergon.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..9d0f870 Binary files /dev/null and b/Example/MPMoviePlayerController-Subtitles.xcodeproj/project.xcworkspace/xcuserdata/mhergon.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Example/MPMoviePlayerController-Subtitles.xcodeproj/xcuserdata/mhergon.xcuserdatad/xcschemes/MPMoviePlayerController-Subtitles.xcscheme b/Example/MPMoviePlayerController-Subtitles.xcodeproj/xcuserdata/mhergon.xcuserdatad/xcschemes/MPMoviePlayerController-Subtitles.xcscheme new file mode 100644 index 0000000..9850543 --- /dev/null +++ b/Example/MPMoviePlayerController-Subtitles.xcodeproj/xcuserdata/mhergon.xcuserdatad/xcschemes/MPMoviePlayerController-Subtitles.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/MPMoviePlayerController-Subtitles.xcodeproj/xcuserdata/mhergon.xcuserdatad/xcschemes/xcschememanagement.plist b/Example/MPMoviePlayerController-Subtitles.xcodeproj/xcuserdata/mhergon.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..5fa71e3 --- /dev/null +++ b/Example/MPMoviePlayerController-Subtitles.xcodeproj/xcuserdata/mhergon.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + MPMoviePlayerController-Subtitles.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 4B49663E1BF8F87E00CD6060 + + primary + + + + + diff --git a/Example/MPMoviePlayerController-Subtitles/MPMoviePlayerController-Subtitles.swift b/Example/MPMoviePlayerController-Subtitles/MPMoviePlayerController-Subtitles.swift deleted file mode 100644 index 810283d..0000000 --- a/Example/MPMoviePlayerController-Subtitles/MPMoviePlayerController-Subtitles.swift +++ /dev/null @@ -1,296 +0,0 @@ -// -// MPMoviePlayerController-Subtitles.swift -// MPMoviePlayerController-Subtitles -// -// Created by mhergon on 15/11/15. -// Copyright © 2015 mhergon. All rights reserved. -// - -import ObjectiveC -import MediaPlayer - -private struct AssociatedKeys { - static var FontKey = "FontKey" - static var ColorKey = "FontKey" - static var ContainerKey = "ContainerKey" - static var SubtitleKey = "SubtitleKey" - static var SubtitleHeightKey = "SubtitleHeightKey" - static var PayloadKey = "PayloadKey" - static var TimerKey = "TimerKey" -} - -extension MPMoviePlayerController { - - //MARK:- Public properties - var subtitleLabel: UILabel? { - get { return objc_getAssociatedObject(self, &AssociatedKeys.SubtitleKey) as? UILabel } - set (value) { objc_setAssociatedObject(self, &AssociatedKeys.SubtitleKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } - } - - //MARK:- Private properties - private var subtitleContainer: UIView? { - get { return objc_getAssociatedObject(self, &AssociatedKeys.ContainerKey) as? UIView } - set (value) { objc_setAssociatedObject(self, &AssociatedKeys.ContainerKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } - } - private var subtitleLabelHeightConstraint: NSLayoutConstraint? { - get { return objc_getAssociatedObject(self, &AssociatedKeys.SubtitleHeightKey) as? NSLayoutConstraint } - set (value) { objc_setAssociatedObject(self, &AssociatedKeys.SubtitleHeightKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } - } - private var parsedPayload: NSDictionary? { - get { return objc_getAssociatedObject(self, &AssociatedKeys.PayloadKey) as? NSDictionary } - set (value) { objc_setAssociatedObject(self, &AssociatedKeys.PayloadKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } - } - private var timer: NSTimer? { - get { return objc_getAssociatedObject(self, &AssociatedKeys.TimerKey) as? NSTimer } - set (value) { objc_setAssociatedObject(self, &AssociatedKeys.TimerKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } - } - - //MARK:- Public methods - func addSubtitles() -> Self { - - // Get subtitle view - getContainer() - - // Create label - addSubtitleLabel() - - // Notifications - registerNotifications() - - return self - - } - - func open(file filePath: NSURL, encoding: NSStringEncoding = NSUTF8StringEncoding) { - - let contents = try! String(contentsOfURL: filePath, encoding: encoding) - show(subtitles: contents) - - } - - func show(subtitles string: String) { - - // Parse - parsedPayload = parseSubRip(string) - - // Timer - timer = NSTimer.schedule(repeatInterval: 0.5) { (timer) -> Void in self.searchSubtitles() } - - } - - //MARK:- Private methods - private func getContainer() { - - for a in view.subviews { - for b in a.subviews { - for c in b.subviews { - if c.tag == 1006 { - subtitleContainer = c - } - } - } - } - - } - - private func addSubtitleLabel() { - - guard let _ = subtitleLabel else { - - // Label - subtitleLabel = UILabel() - subtitleLabel?.translatesAutoresizingMaskIntoConstraints = false - subtitleLabel?.backgroundColor = UIColor.clearColor() - subtitleLabel?.textAlignment = .Center - subtitleLabel?.numberOfLines = 0 - subtitleLabel?.font = UIFont.boldSystemFontOfSize(UI_USER_INTERFACE_IDIOM() == .Pad ? 40.0 : 22.0) - subtitleLabel?.textColor = UIColor.whiteColor() - subtitleLabel?.numberOfLines = 0; - subtitleLabel?.layer.shadowColor = UIColor.blackColor().CGColor - subtitleLabel?.layer.shadowOffset = CGSizeMake(1.0, 1.0); - subtitleLabel?.layer.shadowOpacity = 0.9; - subtitleLabel?.layer.shadowRadius = 1.0; - subtitleLabel?.layer.shouldRasterize = true; - subtitleLabel?.layer.rasterizationScale = UIScreen.mainScreen().scale - subtitleContainer?.addSubview(subtitleLabel!) - - // Position - var constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(20)-[l]-(20)-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["l" : subtitleLabel!]) - subtitleContainer?.addConstraints(constraints) - constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:[l]-(30)-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["l" : subtitleLabel!]) - subtitleContainer?.addConstraints(constraints) - subtitleLabelHeightConstraint = NSLayoutConstraint(item: subtitleLabel!, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 30.0) - subtitleContainer?.addConstraint(subtitleLabelHeightConstraint!) - - return - - } - - } - - private func registerNotifications() { - - // Finished - NSNotificationCenter.defaultCenter().addObserverForName( - MPMoviePlayerPlaybackDidFinishNotification, - object: self, - queue: NSOperationQueue.mainQueue()) { (notification) -> Void in - - self.subtitleLabel?.hidden = true - self.timer?.invalidate() - - } - - // Change - NSNotificationCenter.defaultCenter().addObserverForName( - MPMoviePlayerPlaybackStateDidChangeNotification, - object: self, - queue: NSOperationQueue.mainQueue()) { (notification) -> Void in - - switch self.playbackState { - - case .Playing: - - // Start timer - self.timer = NSTimer.schedule(repeatInterval: 0.5) { (timer) -> Void in self.searchSubtitles() } - - break - - default: - - // Stop timer - self.timer?.invalidate() - - break - - } - - } - - } - - private func parseSubRip(var payload: String) -> NSDictionary? { - - do { - - // Prepare payload - payload = payload.stringByReplacingOccurrencesOfString("\n\r\n", withString: "\n\n") - payload = payload.stringByReplacingOccurrencesOfString("\n\n\n", withString: "\n\n") - - // Parsed dict - let parsed = NSMutableDictionary() - - // Get groups - let regexStr = "(?m)(^[0-9]+)([\\s\\S]*?)(?=\n\n)" - let regex = try NSRegularExpression(pattern: regexStr, options: .CaseInsensitive) - let matches = regex.matchesInString(payload, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, payload.characters.count)) - for m in matches { - - let group = (payload as NSString).substringWithRange(m.range) - - // Get index - var regex = try NSRegularExpression(pattern: "^[0-9]+", options: .CaseInsensitive) - var match = regex.matchesInString(group, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, group.characters.count)) - guard let i = match.first else { - continue - } - let index = (group as NSString).substringWithRange(i.range) - - // Get "from" & "to" time - regex = try NSRegularExpression(pattern: "\\d{1,2}:\\d{1,2}:\\d{1,2},\\d{1,3}", options: .CaseInsensitive) - match = regex.matchesInString(group, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, group.characters.count)) - guard match.count == 2 else { - continue - } - guard let from = match.first, let to = match.last else { - continue - } - - var h: NSTimeInterval = 0.0, m: NSTimeInterval = 0.0, s: NSTimeInterval = 0.0, c: NSTimeInterval = 0.0 - - let fromStr = (group as NSString).substringWithRange(from.range) - var scanner = NSScanner(string: fromStr) - scanner.scanDouble(&h) - scanner.scanString(":", intoString: nil) - scanner.scanDouble(&m) - scanner.scanString(":", intoString: nil) - scanner.scanDouble(&s) - scanner.scanString(",", intoString: nil) - scanner.scanDouble(&c) - let fromTime = (h * 3600.0) + (m * 60.0) + s + (c / 1000.0) - - let toStr = (group as NSString).substringWithRange(to.range) - scanner = NSScanner(string: toStr) - scanner.scanDouble(&h) - scanner.scanString(":", intoString: nil) - scanner.scanDouble(&m) - scanner.scanString(":", intoString: nil) - scanner.scanDouble(&s) - scanner.scanString(",", intoString: nil) - scanner.scanDouble(&c) - let toTime = (h * 3600.0) + (m * 60.0) + s + (c / 1000.0) - - // Get text - let text = (group as NSString).stringByReplacingCharactersInRange(NSMakeRange(0, to.range.location + to.range.length + 1), withString: "") - - // Create final object - let final = NSMutableDictionary() - final["from"] = fromTime - final["to"] = toTime - final["text"] = text - parsed[index] = final - - } - - return parsed - - } catch { - - return nil - - } - - } - - private func searchSubtitles() { - - if playbackState == .Playing { - - let predicate = NSPredicate(format: "(%f >= %K) AND (%f <= %K)", currentPlaybackTime, "from", currentPlaybackTime, "to") - - guard let values = parsedPayload?.allValues else { - return - } - guard let result = (values as NSArray).filteredArrayUsingPredicate(predicate).first as? NSDictionary else { - subtitleLabel?.text = "" - return - } - guard let label = subtitleLabel else { - return - } - - // Set text - label.text = (result["text"] as! String).stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) - - // Adjust size - let rect = (label.text! as NSString).boundingRectWithSize(CGSize(width: CGRectGetWidth(label.bounds), height: CGFloat.max), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName : label.font!], context: nil) - subtitleLabelHeightConstraint?.constant = rect.size.height + 5.0 - subtitleContainer?.layoutIfNeeded() - - } - - } - -} - -// Others -extension NSTimer { - - class func schedule(repeatInterval interval: NSTimeInterval, handler: NSTimer! -> Void) -> NSTimer { - let fireDate = interval + CFAbsoluteTimeGetCurrent() - let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, interval, 0, 0, handler) - CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes) - return timer - } - -} \ No newline at end of file diff --git a/MPMoviePlayerController-Subtitles.podspec b/MPMoviePlayerController-Subtitles.podspec index b411fa0..2f10a63 100644 --- a/MPMoviePlayerController-Subtitles.podspec +++ b/MPMoviePlayerController-Subtitles.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = 'MPMoviePlayerController-Subtitles' spec.platform = :ios, "8.0" - spec.version = '2.0' + spec.version = '2.0.1' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/mhergon/MPMoviePlayerController-Subtitles' spec.authors = { 'Marc Hervera' => 'mhergon@gmail.com' } spec.summary = 'Subtitles made easy' - spec.source = { :git => 'https://github.com/mhergon/MPMoviePlayerController-Subtitles.git', :tag => 'v2.0' } + spec.source = { :git => 'https://github.com/mhergon/MPMoviePlayerController-Subtitles.git', :tag => 'v2.0.1' } spec.source_files = 'MPMoviePlayerController-Subtitles.swift' spec.requires_arc = true spec.module_name = 'MPMoviePlayerControllerSubtitles' diff --git a/MPMoviePlayerController-Subtitles.swift b/MPMoviePlayerController-Subtitles.swift index 810283d..79de2aa 100644 --- a/MPMoviePlayerController-Subtitles.swift +++ b/MPMoviePlayerController-Subtitles.swift @@ -19,7 +19,7 @@ private struct AssociatedKeys { static var TimerKey = "TimerKey" } -extension MPMoviePlayerController { +public extension MPMoviePlayerController { //MARK:- Public properties var subtitleLabel: UILabel? { @@ -284,7 +284,7 @@ extension MPMoviePlayerController { } // Others -extension NSTimer { +public extension NSTimer { class func schedule(repeatInterval interval: NSTimeInterval, handler: NSTimer! -> Void) -> NSTimer { let fireDate = interval + CFAbsoluteTimeGetCurrent()