Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ASBPlayerSubtitling/ASBPlayerSubtitling.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
@property (nonatomic, assign) BOOL visible;

- (void)loadSubtitlesAtURL:(NSURL *)url error:(NSError **)error;
- (void)loadWebVTTSubtitlesAtURL:(NSURL *)url error:(NSError **)error;

- (void)loadSRTContent:(NSString *)string error:(NSError **)error;
- (void)removeSubtitles;

Expand Down
95 changes: 94 additions & 1 deletion ASBPlayerSubtitling/ASBPlayerSubtitling.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

#import "ASBPlayerSubtitling.h"
#import <UIKit/UIKit.h>
#import "NSString+ASBRegularExpression.h"

static CGFloat *const DefaultNbFramesPerSecond = 30;
static CGFloat const DefaultNbFramesPerSecond = 30;

@implementation ASBSubtitle
@end
Expand Down Expand Up @@ -39,6 +40,7 @@ - (instancetype)init

- (void)awakeFromNib
{
[super awakeFromNib];
[self setup];
}

Expand Down Expand Up @@ -82,6 +84,23 @@ - (void)loadSubtitlesAtURL:(NSURL *)url error:(NSError **)error
}
}

- (void)loadWebVTTSubtitlesAtURL:(NSURL *)url error:(NSError **)error
{
NSError *localError;
NSString *text;

text = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&localError];
if (localError == nil)
{
[self loadWebVTTContent:text error:&localError];
}

if(error != NULL)
{
*error = localError;
}
}

- (void)computeStyle
{
NSString *textAlign;
Expand Down Expand Up @@ -225,6 +244,11 @@ - (void)loadSRTContent:(NSString *)string error:(NSError **)error
[self setupTimeObserver];
}

- (void)loadWebVTTContent:(NSString *)string error:(NSError **)error {
NSString *srtString = [[self class] srtSubtitleFromWebVTT:string];
[self loadSRTContent:srtString error:error];
}

- (NSTimeInterval)timeFromString:(NSString *)timeString
{
NSScanner *scanner;
Expand Down Expand Up @@ -329,6 +353,75 @@ - (void)playerTimeChanged
});
}

+ (NSString *)srtSubtitleFromWebVTT:(NSString *)content {

NSArray *lines = [self split:content];
NSString *output = @"";
NSInteger i = 0;
NSError *error;
NSString *newLine;

for (NSString *line in lines) {
newLine = line;
NSCharacterSet* notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];

if([[line stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\n\r "]] rangeOfCharacterFromSet:notDigits].location == NSNotFound) {
continue;
}

NSString *pattern1 = @"(\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{3})"; // '01:52:52.554'
NSString *pattern2 = @"(\\d{2}):(\\d{2})\\.(\\d{3})"; // '00:08.301'

NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern: pattern1 options:0 error:&error];
NSArray* matches = [regex matchesInString:line options:0 range: NSMakeRange(0, line.length)];

NSString *pattern ;
NSString *template;

if (matches.count) {
pattern = pattern1;
template = @"$1:$2:$3,$4";
} else {
regex = [NSRegularExpression regularExpressionWithPattern: pattern2 options:0 error:&error];
matches = [regex matchesInString:line options:0 range: NSMakeRange(0, line.length)];
if (matches.count) {
pattern = pattern2;
template = @"00:$1:$2,$3";
}
}

if (matches.count && !error) {
i++;
output = [output stringByAppendingString:@"\r\n\r\n"];
output = [output stringByAppendingString:[@(i) stringValue]];
output = [output stringByAppendingString:@"\r\n"];

newLine = [line stringByReplacingWithPattern:pattern withTemplate:template error:&error];
}

if([newLine containsString:@"WEBVTT"]) {
continue;
}
output = [output stringByAppendingString:newLine];
output = [output stringByAppendingString:@"\r\n"];
}

return output;
}


+ (NSArray *)split:(NSString *)content {

NSArray *lines = [content componentsSeparatedByString: @"\n"];
if (lines.count == 1) {
lines = [content componentsSeparatedByString: @"\r\n"];
if (lines.count == 1) {
lines = [content componentsSeparatedByString: @"\n"];
}
}
return lines;
}

#pragma Time Observer
- (void)removeTimeObserver
{
Expand Down
15 changes: 15 additions & 0 deletions ASBPlayerSubtitling/NSString+ASBRegularExpression.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// NSString+ASBRegularExpression.h
// ASBPlayerSubtitlingExample
//
// Created by Allen and Kim on 2018/5/28.
// Copyright © 2018 AutreSphere. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSString (ASBRegularExpression)

- (NSString *)stringByReplacingWithPattern:(NSString *)pattern withTemplate:(NSString *)withTemplate error:(NSError **)error;

@end
23 changes: 23 additions & 0 deletions ASBPlayerSubtitling/NSString+ASBRegularExpression.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// NSString+ASBRegularExpression.m
// ASBPlayerSubtitlingExample
//
// Created by Allen and Kim on 2018/5/28.
// Copyright © 2018 AutreSphere. All rights reserved.
//

#import "NSString+ASBRegularExpression.h"

@implementation NSString (ASBRegularExpression)

- (NSString *)stringByReplacingWithPattern:(NSString *)pattern withTemplate:(NSString *)withTemplate error:(NSError **)error {
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive
error:error];
return [regex stringByReplacingMatchesInString:self
options:0
range:NSMakeRange(0, self.length)
withTemplate:withTemplate];
}

@end
85 changes: 39 additions & 46 deletions Example/ASBPlayerSubtitlingExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
4A0BC9321AC31714000904A2 /* play@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4A0BC92C1AC31714000904A2 /* play@2x.png */; };
4A0BC9331AC31714000904A2 /* sliderThumb.png in Resources */ = {isa = PBXBuildFile; fileRef = 4A0BC92D1AC31714000904A2 /* sliderThumb.png */; };
4A0BC9341AC31714000904A2 /* sliderThumb@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4A0BC92E1AC31714000904A2 /* sliderThumb@2x.png */; };
4A0BC93E1AC31AA4000904A2 /* ASBPlayerSubtitling.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A0BC93D1AC31AA4000904A2 /* ASBPlayerSubtitling.m */; };
4A0BC9401AC31C7B000904A2 /* welcome.srt in Resources */ = {isa = PBXBuildFile; fileRef = 4A0BC93F1AC31C7B000904A2 /* welcome.srt */; };
F654DA73C37C2F1646AEC07F /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC330590DF6F8B0B77845089 /* libPods.a */; };
AC38C51B8CBB21836A917F0F /* libPods-ASBPlayerSubtitlingExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 76EBDB8E40A605075481464B /* libPods-ASBPlayerSubtitlingExample.a */; };
FF57A34420BBFF820083DAF4 /* ASBPlayerSubtitling.m in Sources */ = {isa = PBXBuildFile; fileRef = FF57A34220BBFF810083DAF4 /* ASBPlayerSubtitling.m */; };
FF706DFC20BBF360002125A0 /* NSString+ASBRegularExpression.m in Sources */ = {isa = PBXBuildFile; fileRef = FF706DFB20BBF360002125A0 /* NSString+ASBRegularExpression.m */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
1CBAABE9F880F0FD13E247C1 /* 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>"; };
28816A0F5DC302DE300E6131 /* 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>"; };
059287F5601B90D3529D1112 /* Pods-ASBPlayerSubtitlingExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ASBPlayerSubtitlingExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ASBPlayerSubtitlingExample/Pods-ASBPlayerSubtitlingExample.debug.xcconfig"; sourceTree = "<group>"; };
4A0BC8FF1AC313F8000904A2 /* ASBPlayerSubtitlingExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ASBPlayerSubtitlingExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
4A0BC9031AC313F8000904A2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4A0BC9041AC313F8000904A2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
Expand All @@ -43,41 +43,35 @@
4A0BC92C1AC31714000904A2 /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; };
4A0BC92D1AC31714000904A2 /* sliderThumb.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sliderThumb.png; sourceTree = "<group>"; };
4A0BC92E1AC31714000904A2 /* sliderThumb@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "sliderThumb@2x.png"; sourceTree = "<group>"; };
4A0BC93C1AC31AA4000904A2 /* ASBPlayerSubtitling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBPlayerSubtitling.h; sourceTree = "<group>"; };
4A0BC93D1AC31AA4000904A2 /* ASBPlayerSubtitling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASBPlayerSubtitling.m; sourceTree = "<group>"; };
4A0BC93F1AC31C7B000904A2 /* welcome.srt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = welcome.srt; sourceTree = "<group>"; };
DC330590DF6F8B0B77845089 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
76EBDB8E40A605075481464B /* libPods-ASBPlayerSubtitlingExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ASBPlayerSubtitlingExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
E772E8E09A39AFEBDA5DEA34 /* Pods-ASBPlayerSubtitlingExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ASBPlayerSubtitlingExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-ASBPlayerSubtitlingExample/Pods-ASBPlayerSubtitlingExample.release.xcconfig"; sourceTree = "<group>"; };
FF57A34220BBFF810083DAF4 /* ASBPlayerSubtitling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASBPlayerSubtitling.m; sourceTree = "<group>"; };
FF57A34320BBFF810083DAF4 /* ASBPlayerSubtitling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBPlayerSubtitling.h; sourceTree = "<group>"; };
FF706DFA20BBF360002125A0 /* NSString+ASBRegularExpression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+ASBRegularExpression.h"; sourceTree = "<group>"; };
FF706DFB20BBF360002125A0 /* NSString+ASBRegularExpression.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+ASBRegularExpression.m"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
4A0BC8FC1AC313F8000904A2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F654DA73C37C2F1646AEC07F /* libPods.a in Frameworks */,
AC38C51B8CBB21836A917F0F /* libPods-ASBPlayerSubtitlingExample.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
057EEC1B454D549FA332F302 /* Pods */ = {
isa = PBXGroup;
children = (
28816A0F5DC302DE300E6131 /* Pods.debug.xcconfig */,
1CBAABE9F880F0FD13E247C1 /* Pods.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
4A0BC8F61AC313F8000904A2 = {
isa = PBXGroup;
children = (
4A0BC9011AC313F8000904A2 /* Example */,
4A0BC9001AC313F8000904A2 /* Products */,
057EEC1B454D549FA332F302 /* Pods */,
4A0BC9281AC31714000904A2 /* Resources */,
C7FC1F457D9FBE6CDD3CA0A1 /* Frameworks */,
4C72E807FCAF458AF437B33F /* Pods */,
B9606A0EBBEB48EF405760FC /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -131,17 +125,28 @@
4A0BC93B1AC31AA4000904A2 /* ASBPlayerSubtitling */ = {
isa = PBXGroup;
children = (
4A0BC93C1AC31AA4000904A2 /* ASBPlayerSubtitling.h */,
4A0BC93D1AC31AA4000904A2 /* ASBPlayerSubtitling.m */,
FF57A34320BBFF810083DAF4 /* ASBPlayerSubtitling.h */,
FF57A34220BBFF810083DAF4 /* ASBPlayerSubtitling.m */,
FF706DFA20BBF360002125A0 /* NSString+ASBRegularExpression.h */,
FF706DFB20BBF360002125A0 /* NSString+ASBRegularExpression.m */,
);
name = ASBPlayerSubtitling;
path = ../../ASBPlayerSubtitling;
sourceTree = "<group>";
};
C7FC1F457D9FBE6CDD3CA0A1 /* Frameworks */ = {
4C72E807FCAF458AF437B33F /* Pods */ = {
isa = PBXGroup;
children = (
059287F5601B90D3529D1112 /* Pods-ASBPlayerSubtitlingExample.debug.xcconfig */,
E772E8E09A39AFEBDA5DEA34 /* Pods-ASBPlayerSubtitlingExample.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
B9606A0EBBEB48EF405760FC /* Frameworks */ = {
isa = PBXGroup;
children = (
DC330590DF6F8B0B77845089 /* libPods.a */,
76EBDB8E40A605075481464B /* libPods-ASBPlayerSubtitlingExample.a */,
);
name = Frameworks;
sourceTree = "<group>";
Expand All @@ -153,11 +158,10 @@
isa = PBXNativeTarget;
buildConfigurationList = 4A0BC9221AC313F9000904A2 /* Build configuration list for PBXNativeTarget "ASBPlayerSubtitlingExample" */;
buildPhases = (
3943A9B80BCD8994501A37D7 /* Check Pods Manifest.lock */,
426F39AB4BE0A54BF59EF10F /* [CP] Check Pods Manifest.lock */,
4A0BC8FB1AC313F8000904A2 /* Sources */,
4A0BC8FC1AC313F8000904A2 /* Frameworks */,
4A0BC8FD1AC313F8000904A2 /* Resources */,
DAEDF1E2AF7F294F1DE6BBC6 /* Copy Pods Resources */,
);
buildRules = (
);
Expand Down Expand Up @@ -221,34 +225,22 @@
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
3943A9B80BCD8994501A37D7 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
DAEDF1E2AF7F294F1DE6BBC6 /* Copy Pods Resources */ = {
426F39AB4BE0A54BF59EF10F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "Copy Pods Resources";
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-ASBPlayerSubtitlingExample-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
Expand All @@ -258,7 +250,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4A0BC93E1AC31AA4000904A2 /* ASBPlayerSubtitling.m in Sources */,
FF57A34420BBFF820083DAF4 /* ASBPlayerSubtitling.m in Sources */,
FF706DFC20BBF360002125A0 /* NSString+ASBRegularExpression.m in Sources */,
4A0BC90B1AC313F8000904A2 /* ViewController.m in Sources */,
4A0BC9081AC313F8000904A2 /* AppDelegate.m in Sources */,
4A0BC9051AC313F8000904A2 /* main.m in Sources */,
Expand Down Expand Up @@ -367,7 +360,7 @@
};
4A0BC9231AC313F9000904A2 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 28816A0F5DC302DE300E6131 /* Pods.debug.xcconfig */;
baseConfigurationReference = 059287F5601B90D3529D1112 /* Pods-ASBPlayerSubtitlingExample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Example/Info.plist;
Expand All @@ -378,7 +371,7 @@
};
4A0BC9241AC313F9000904A2 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1CBAABE9F880F0FD13E247C1 /* Pods.release.xcconfig */;
baseConfigurationReference = E772E8E09A39AFEBDA5DEA34 /* Pods-ASBPlayerSubtitlingExample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Example/Info.plist;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Loading