From 176df029a5859df3e911a6f9d807810f8d86eb97 Mon Sep 17 00:00:00 2001 From: Marc Hervera Date: Sat, 25 Mar 2017 14:46:42 +0100 Subject: [PATCH] Added SubRip parser without player v2.2 --- .../UserInterfaceState.xcuserstate | Bin 30920 -> 31493 bytes .../ViewController.swift | 14 + MPMoviePlayerController-Subtitles.podspec | 4 +- README.md | 25 +- Subtitles.swift | 265 +++++++++++------- 5 files changed, 195 insertions(+), 113 deletions(-) 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 index 9bacf31b88efef98ed6aded8a5976128e0fa751d..8d4742c47aec8ff38e1f026959398e33ea997fe7 100644 GIT binary patch delta 15762 zcmb_@cU;p)`2XkbGs7lfg%LI+fdFBTfQYyiB_RoW2oX^f1>7T_bJbC2+^ZtEw`kq1 z)=^ijd#_sS9<{^Py1o}8h~IDfdj0yJx+h%X#c2nD7eBbRiQ3Nv1so zLDXhPxOY~&Byt!rd=?TJClQm08N^It5wVz9LM$cfh(=;Nv4i-U*h%anb`yJuy~Ov# zG2%FJf;dT>B7PuF6F(B?h#SOB;vVssctSiSekJ}O{v=)#?}+z+0yGc+TVMz5firLe z9>5#;fKZ?SVIUkt02N3EDWDBV1?@m*(8UP4f=r+WdQb$4K?&#uN!|4p;(KgN{;BW96 z(vX2Hif$un?9(0~`#8z@cy$ z91cgok#GW>2)}@n;FoY3oCRk?6PyD#!Od_B+zPkBMz|gBfM3I%a2MPS_rY)Bckl>2 z2G78=@Ep7XZ^8TU0elF5g)iZ6@E`bwBuR>-NrvfZlA;*&w$f@L9 zavnLKTtF@%H<6pkE#y{m8`(&1CwGts$?wQRMLqBwT9Y8HB#HDJ=6i}D0PZDM_r=s zQxB+z)FbLK^~6X$rCw2gQGZjfsdvH|&CF0?D{MvG~8+Jp9_y=V#TP5aS-w3H5^ z!{}IAMW@kSXf>Tn_o7SbGTK1*rbo~t=~47(dJJu(c^c7U>Djc2oH1i{Kp1HtWVXiVanOn?b<_YtZdB(h9-ZJl)_sj>DU@4Yk z1*{co&APH~teACYgV|%BayM|rMu4C7;JK0_AZgvlQ zl>MGP#vW%cvX|J)>=pJN`wM%YeZc7PRx08{#*bT z%f)f=MlOL%FwK>Rn%5hx2-mm6gfEH@0vbULo-T-RFs$C<~-bxRnn_lNiRcXk%PiC-A8OH^O2dX z1=XfUKH{A7gn+Ojtcg;hKOtR9lo1A^H&IUXAu5QzL_eaE_u?hIH}Avy@_xKOAHWB$ zC4z`5{HMjQ8lsjMObo$72IId@_?64o@`L#?yxug(ce}fwdH8X}1VUOzjOX#&L|%rw zGwdVUOd-BBw@&5db;LA2gx67;iSxt- zyvY}dOT=a33UQUVMrch&Yqg*U-=0_V>3k>C^MJT);uaCxK-?zo5I+%j`3`&+z8l}& zys%%0`s&t>|y4sV(V0knhQ7n%)Lx3z|d#3}8*CZC%I}fHR%4 z^`d|kur@uj4W)n$p~4R#rai*sDhE8OBOrkY0DXogtXD~mArF668!Ag`D~1?&g4gjq zEd#m$S8av{Pq_lP5GqTX7`PWXh%z+Y2iKPLsx*93K|K(gm2l2%=fD%23-ID|cze^? zc#&zi$X4YGf(U5?@B{uJ00i=Rd_G^m7dC)kAO$iY=Zkm)U(Wa8_1WDFy=!$9hM_s? zit;{9PbL^Fmjfk;HIEPpqChl=;fwhaz87EGfNewz5{MvdBc1p%vnQK!gNJ5W1Zhje zE^o0}kPbRvPXO)t-gSf)Q|pTy9NSe5sHv(nbf~DTHB@)6Dl<61k0uVffebTwcfO(y z^x*sAfm4&j5kLcUD?k>|^8NUMd`&ZPHpnA{D?kp&%1039|C%S5 z3Z{R?GXu=zNAaWiH0%bLE8Wm*aCy0*DJJ@-)*NW!b-V!Pf_Y#*Hi8A%$`*mergc_b zeI{YMGV)U|fu&#>?)nNW2X(l60cZd#!7Ad3$=N!?IEkO)0C>KYAA>but;LV|FL-3} zVT)onVIKyY!4|L;Y~#oBI$uZrJ@ZH#9pO zPkg?J6L=X7#1lXgPx#4rl~Z^e5zIdDquB=*;Z@sPJm);PVA^UY$L@L2wAoHcfy>~E z$=*H)H(WK@+Dl2itEP-DE=F(z+-kAA+x&E1ZyE5eS+PHZd;AQ3_9w+Y0FOUY(i8BM zpUKbS(|Y=+j_uQ=lV*Ls1b_T5(pQ+&#HabE4p`nosW1!w5BOmAwKw1`cn99|bNPAv ze11U#Bp`qglKet`3x9w=h;8nLd~_nTf{uiA6|{yn&=%T3d+5L~;urHv_@(?Z{;O3` z2u0XUHP8jR^2_-(*i}>cb^LnFz9poSsm#sK^eV*Lln^QvLLcZy2h=HU)3PS-k^&u{wFQ3OlO9L4 zh_Y{6Q)8&D2^&^g()7?QMsJA0#41=0Bl^G!*cbMLmHbwI8{f!p=Xda5ufqFXg{@fw ztAPyf_fBlnsrXb%b<1oQI`Z02jhVa4}p0 zm%?T6E4ZBh4$F0jKg=KDkMiI1$N1y?3I61IEMYxtfGY_tT#cXCHd)FBEbA%$2mUmc z`bYeH2LGkho{UIa{`{^ z&+`{nnCEL6U2nSNmDc4vyofc>6!qaH{?bS9gI9sB9$tgj;SK&We~rJ{;(_osyxZEX z;Lq?Le}%t_Ew`5>K>P?k{jB#He9m9zZGDdC@E!cGXJB9M;2XavR}FpkIHCL-{~{{zr9eaU%%W_&xrG+JO&@KG!>gp9%1 zmJB5oWEdGvMvzJ}l8hpw`4{}J{7e2f{&)Tl{!jiD|JPbFmW;DtTQZ4Mk;!=f|3-i_ zi)I!s6oDiJR9Gi^(=UP@dCeJx>;g!#8(540g9GjB|C3H|KTap48b@NnOf!Z5r&TT? zvq&v*mDCej1StM3P9|@f0AYMq9uZql=92|vA^#2m%nDmF30Xq+!U*m?|G^CYoXoHU z1BTk_s>(`3^+yCqeoQfBxjAO^vqIntQXKRFoz z>y}VMeo4;6$e)}>PA6v|V1s}y0(SM}ENnF<1nkY4kYh95Z(mYEE;P@#2myyr6D}oJ z;sStNMt(&uC+o-+WIfq{fFlAz1VjipA>fRF3j(gV4j@;PYsj^DGuM+F_;>`|5b!}D zn17Fe6yfM(E(YdBd`<4fg#fve+(qst_aGofz#Rb(1UwtaedK;@!QUd_g@D9tu-;fS zTn`w(nYbZ3!1hA!$k^CWA7w(ca&*qf$cTujP@jm=t+jugJkhNEAOw6Z>Tik^B+k_J z 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 delta 15492 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 diff --git a/Example/MPMoviePlayerController-Subtitles/ViewController.swift b/Example/MPMoviePlayerController-Subtitles/ViewController.swift index 567a27b..4036576 100644 --- a/Example/MPMoviePlayerController-Subtitles/ViewController.swift +++ b/Example/MPMoviePlayerController-Subtitles/ViewController.swift @@ -47,5 +47,19 @@ class ViewController: UIViewController { } + func subtitleParser() { + + // Subtitle file + let subtitleFile = Bundle.main.path(forResource: "trailer_720p", ofType: "srt") + let subtitleURL = URL(fileURLWithPath: subtitleFile!) + + // Subtitle parser + let parser = Subtitles(file: subtitleURL, encoding: .utf8) + + // Do something with result + let subtitles = parser.searchSubtitles(at: 2.0) // Search subtitle at 2.0 seconds + + } + } diff --git a/MPMoviePlayerController-Subtitles.podspec b/MPMoviePlayerController-Subtitles.podspec index 65b180f..0cc990f 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.1.1' + spec.version = '2.2' spec.license = { :type => 'Apache License, Version 2.0' } 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.1.1' } + spec.source = { :git => 'https://github.com/mhergon/MPMoviePlayerController-Subtitles.git', :tag => 'v2.2' } spec.source_files = 'Subtitles.swift' spec.requires_arc = true spec.module_name = 'MPMoviePlayerControllerSubtitles' diff --git a/README.md b/README.md index 0e2e445..3d1c813 100755 --- a/README.md +++ b/README.md @@ -28,13 +28,12 @@ pod "MPMoviePlayerController-Subtitles" | Version | Language | Minimum iOS Target | |:--------------------:|:---------------------------:|:---------------------------:| -| 2.1.x | Swift 3.x | iOS 8 | +| 2.2.x | Swift 3.x | iOS 8 | | 2.0.x | Swift 2.x | iOS 8 | | 1.x | Objective-C | iOS 6 | -### Usage - +### Usage with player ```swift import MPMoviePlayerControllerSubtitles @@ -63,11 +62,27 @@ moviePlayerView?.moviePlayer.subtitleLabel?.textColor = UIColor.red moviePlayerView?.moviePlayer.play() ``` -## Screenshot +#### Screenshot

Screenshoot

+### Usage without player + +From version 2.2 you can search text in the SubRip file or text without need play any file. + +```swift +// Subtitle file +let subtitleFile = Bundle.main.path(forResource: "trailer_720p", ofType: "srt") +let subtitleURL = URL(fileURLWithPath: subtitleFile!) + +// Subtitle parser +let parser = Subtitles(file: subtitleURL, encoding: .utf8) + +// Do something with result +let subtitles = parser.searchSubtitles(at: 2.0) // Search subtitle at 2.0 seconds +``` + ## Contact - [Linkedin][2] @@ -80,4 +95,4 @@ moviePlayerView?.moviePlayer.play() Licensed under Apache License v2.0.
-Copyright 2015-2016 Marc Hervera. +Copyright 2017 Marc Hervera. diff --git a/Subtitles.swift b/Subtitles.swift index 743d1df..96d547a 100644 --- a/Subtitles.swift +++ b/Subtitles.swift @@ -19,6 +19,156 @@ private struct AssociatedKeys { static var TimerKey = "TimerKey" } +class Subtitles { + + // MARK: - Properties + fileprivate var parsedPayload: NSDictionary? + + // MARK: - Public methods + init(file filePath: URL, encoding: String.Encoding = String.Encoding.utf8) { + + // Get string + let string = try! String(contentsOf: filePath, encoding: encoding) + + // Parse string + parsedPayload = Subtitles.parseSubRip(string) + + } + + init(subtitles string: String) { + + // Parse string + parsedPayload = Subtitles.parseSubRip(string) + + } + + /// Search subtitles at time + /// + /// - Parameter time: Time + /// - Returns: String if exists + func searchSubtitles(at time: TimeInterval) -> String? { + + return Subtitles.searchSubtitles(parsedPayload, time) + + } + + // MARK: - Private methods + + /// Subtitle parser + /// + /// - Parameter payload: Input string + /// - Returns: NSDictionary + fileprivate static func parseSubRip(_ payload: String) -> NSDictionary? { + + do { + + // Prepare payload + var payload = payload.replacingOccurrences(of: "\n\r\n", with: "\n\n") + payload = payload.replacingOccurrences(of: "\n\n\n", with: "\n\n") + + // Parsed dict + let parsed = NSMutableDictionary() + + // Get groups + let regexStr = "(\\d+)\\n([\\d:,.]+)\\s+-{2}\\>\\s+([\\d:,.]+)\\n([\\s\\S]*?(?=\\n{2,}|$))" + let regex = try NSRegularExpression(pattern: regexStr, options: .caseInsensitive) + let matches = regex.matches(in: payload, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, payload.characters.count)) + for m in matches { + + let group = (payload as NSString).substring(with: m.range) + + // Get index + var regex = try NSRegularExpression(pattern: "^[0-9]+", options: .caseInsensitive) + var match = regex.matches(in: group, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, group.characters.count)) + guard let i = match.first else { + continue + } + let index = (group as NSString).substring(with: 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.matches(in: group, options: NSRegularExpression.MatchingOptions(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: TimeInterval = 0.0, m: TimeInterval = 0.0, s: TimeInterval = 0.0, c: TimeInterval = 0.0 + + let fromStr = (group as NSString).substring(with: from.range) + var scanner = Scanner(string: fromStr) + scanner.scanDouble(&h) + scanner.scanString(":", into: nil) + scanner.scanDouble(&m) + scanner.scanString(":", into: nil) + scanner.scanDouble(&s) + scanner.scanString(",", into: nil) + scanner.scanDouble(&c) + let fromTime = (h * 3600.0) + (m * 60.0) + s + (c / 1000.0) + + let toStr = (group as NSString).substring(with: to.range) + scanner = Scanner(string: toStr) + scanner.scanDouble(&h) + scanner.scanString(":", into: nil) + scanner.scanDouble(&m) + scanner.scanString(":", into: nil) + scanner.scanDouble(&s) + scanner.scanString(",", into: nil) + scanner.scanDouble(&c) + let toTime = (h * 3600.0) + (m * 60.0) + s + (c / 1000.0) + + // Get text & check if empty + let range = NSMakeRange(0, to.range.location + to.range.length + 1) + guard (group as NSString).length - range.length > 0 else { + continue + } + let text = (group as NSString).replacingCharacters(in: range, with: "") + + // Create final object + let final = NSMutableDictionary() + final["from"] = fromTime + final["to"] = toTime + final["text"] = text + parsed[index] = final + + } + + return parsed + + } catch { + + return nil + + } + + } + + /// Search subtitle on time + /// + /// - Parameters: + /// - payload: Inout payload + /// - time: Time + /// - Returns: String + fileprivate static func searchSubtitles(_ payload: NSDictionary?, _ time: TimeInterval) -> String? { + + let predicate = NSPredicate(format: "(%f >= %K) AND (%f <= %K)", time, "from", time, "to") + + guard let values = payload?.allValues, let result = (values as NSArray).filtered(using: predicate).first as? NSDictionary else { + return nil + } + + guard let text = result.value(forKey: "text") as? String else { + return nil + } + + return text.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + + } + +} + public extension MPMoviePlayerController { //MARK:- Public properties @@ -71,7 +221,7 @@ public extension MPMoviePlayerController { func show(subtitles string: String) { // Parse - parsedPayload = parseSubRip(string) + parsedPayload = Subtitles.parseSubRip(string) // Timer timer = Timer.schedule(repeatInterval: 0.5) { (timer) -> Void in self.searchSubtitles() } @@ -169,118 +319,21 @@ public extension MPMoviePlayerController { } } - - fileprivate func parseSubRip(_ payload: String) -> NSDictionary? { - - do { - - // Prepare payload - var payload = payload.replacingOccurrences(of: "\n\r\n", with: "\n\n") - payload = payload.replacingOccurrences(of: "\n\n\n", with: "\n\n") - - // Parsed dict - let parsed = NSMutableDictionary() - - // Get groups - let regexStr = "(\\d+)\\n([\\d:,.]+)\\s+-{2}\\>\\s+([\\d:,.]+)\\n([\\s\\S]*?(?=\\n{2,}|$))" - let regex = try NSRegularExpression(pattern: regexStr, options: .caseInsensitive) - let matches = regex.matches(in: payload, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, payload.characters.count)) - for m in matches { - - let group = (payload as NSString).substring(with: m.range) - - // Get index - var regex = try NSRegularExpression(pattern: "^[0-9]+", options: .caseInsensitive) - var match = regex.matches(in: group, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, group.characters.count)) - guard let i = match.first else { - continue - } - let index = (group as NSString).substring(with: 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.matches(in: group, options: NSRegularExpression.MatchingOptions(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: TimeInterval = 0.0, m: TimeInterval = 0.0, s: TimeInterval = 0.0, c: TimeInterval = 0.0 - - let fromStr = (group as NSString).substring(with: from.range) - var scanner = Scanner(string: fromStr) - scanner.scanDouble(&h) - scanner.scanString(":", into: nil) - scanner.scanDouble(&m) - scanner.scanString(":", into: nil) - scanner.scanDouble(&s) - scanner.scanString(",", into: nil) - scanner.scanDouble(&c) - let fromTime = (h * 3600.0) + (m * 60.0) + s + (c / 1000.0) - - let toStr = (group as NSString).substring(with: to.range) - scanner = Scanner(string: toStr) - scanner.scanDouble(&h) - scanner.scanString(":", into: nil) - scanner.scanDouble(&m) - scanner.scanString(":", into: nil) - scanner.scanDouble(&s) - scanner.scanString(",", into: nil) - scanner.scanDouble(&c) - let toTime = (h * 3600.0) + (m * 60.0) + s + (c / 1000.0) - - // Get text & check if empty - let range = NSMakeRange(0, to.range.location + to.range.length + 1) - guard (group as NSString).length - range.length > 0 else { - continue - } - let text = (group as NSString).replacingCharacters(in: range, with: "") - - // Create final object - let final = NSMutableDictionary() - final["from"] = fromTime - final["to"] = toTime - final["text"] = text - parsed[index] = final - - } - - return parsed - - } catch { - - return nil - - } - - } - + fileprivate 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).filtered(using: predicate).first as? NSDictionary else { - subtitleLabel?.text = "" - return - } - guard let label = subtitleLabel else { - return - } + guard let label = subtitleLabel else { return } - // Set text - label.text = (result["text"] as! String).trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + // Search && show subtitles + subtitleLabel?.text = Subtitles.searchSubtitles(parsedPayload, currentPlaybackTime) // Adjust size - let rect = (label.text! as NSString).boundingRect(with: CGSize(width: label.bounds.width, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName : label.font!], context: nil) - subtitleLabelHeightConstraint?.constant = rect.size.height + 5.0 - subtitleContainer?.layoutIfNeeded() + let baseSize = CGSize(width: label.bounds.width, height: CGFloat.greatestFiniteMagnitude) + let rect = label.sizeThatFits(baseSize) + subtitleLabelHeightConstraint?.constant = rect.height + 5.0 + subtitleLabel?.layoutIfNeeded() }