2007-10-09 01:20:46 +00:00
|
|
|
//
|
|
|
|
// M3uContainer.m
|
|
|
|
// M3u
|
|
|
|
//
|
|
|
|
// Created by Zaphod Beeblebrox on 10/8/07.
|
|
|
|
// Copyright 2007 __MyCompanyName__. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "M3uContainer.h"
|
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
#import "Logging.h"
|
2007-10-09 01:20:46 +00:00
|
|
|
|
|
|
|
@implementation M3uContainer
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)fileTypes {
|
2022-01-19 02:12:57 +00:00
|
|
|
return @[@"m3u", @"m3u8"];
|
2007-10-09 01:20:46 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)mimeTypes {
|
2022-01-19 02:12:57 +00:00
|
|
|
return @[@"audio/x-mpegurl", @"audio/mpegurl"];
|
2007-10-14 18:56:23 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (float)priority {
|
|
|
|
return 1.0f;
|
2015-04-13 07:39:24 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename {
|
2007-10-15 22:19:14 +00:00
|
|
|
NSRange protocolRange = [path rangeOfString:@"://"];
|
2022-02-07 05:49:27 +00:00
|
|
|
if(protocolRange.location != NSNotFound) {
|
2007-10-09 01:20:46 +00:00
|
|
|
return [NSURL URLWithString:path];
|
|
|
|
}
|
2007-10-15 22:19:14 +00:00
|
|
|
|
2007-10-09 01:20:46 +00:00
|
|
|
NSMutableString *unixPath = [path mutableCopy];
|
2007-10-15 22:19:14 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
// Get the fragment
|
2007-10-15 22:57:30 +00:00
|
|
|
NSString *fragment = @"";
|
2007-10-19 03:06:52 +00:00
|
|
|
NSScanner *scanner = [NSScanner scannerWithString:unixPath];
|
|
|
|
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"#1234567890"];
|
2022-02-07 05:49:27 +00:00
|
|
|
while(![scanner isAtEnd]) {
|
2007-10-19 03:06:52 +00:00
|
|
|
NSString *possibleFragment;
|
|
|
|
[scanner scanUpToString:@"#" intoString:nil];
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
if([scanner scanCharactersFromSet:characterSet intoString:&possibleFragment] && [scanner isAtEnd]) {
|
2007-10-19 03:06:52 +00:00
|
|
|
fragment = possibleFragment;
|
|
|
|
[unixPath deleteCharactersInRange:NSMakeRange([scanner scanLocation] - [possibleFragment length], [possibleFragment length])];
|
|
|
|
break;
|
|
|
|
}
|
2007-10-15 22:57:30 +00:00
|
|
|
}
|
2013-10-11 12:03:55 +00:00
|
|
|
DLog(@"Fragment: %@", fragment);
|
2007-10-15 22:19:14 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
if(![unixPath hasPrefix:@"/"]) {
|
|
|
|
// Only relative paths would have windows backslashes.
|
2007-10-15 22:57:30 +00:00
|
|
|
[unixPath replaceOccurrencesOfString:@"\\" withString:@"/" options:0 range:NSMakeRange(0, [unixPath length])];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2007-10-15 22:57:30 +00:00
|
|
|
NSString *basePath = [[[baseFilename stringByStandardizingPath] stringByDeletingLastPathComponent] stringByAppendingString:@"/"];
|
2007-10-15 22:19:14 +00:00
|
|
|
|
2007-10-15 22:57:30 +00:00
|
|
|
[unixPath insertString:basePath atIndex:0];
|
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
// Append the fragment
|
|
|
|
NSURL *url = [NSURL URLWithString:[[[NSURL fileURLWithPath:unixPath] absoluteString] stringByAppendingString:fragment]];
|
2008-08-26 17:45:16 +00:00
|
|
|
return url;
|
2007-10-09 01:20:46 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)urlsForContainerURL:(NSURL *)url {
|
|
|
|
char *filecontents = nil;
|
|
|
|
|
|
|
|
{
|
|
|
|
id audioSourceClass = NSClassFromString(@"AudioSource");
|
|
|
|
id<CogSource> source = [audioSourceClass audioSourceForURL:url];
|
|
|
|
|
|
|
|
if(![source open:url])
|
|
|
|
return @[];
|
|
|
|
|
|
|
|
long size = 0;
|
|
|
|
long bytesread = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
filecontents = (char *)realloc(filecontents, size + 1024);
|
|
|
|
bytesread = [source read:(filecontents + size) amount:1024];
|
|
|
|
size += bytesread;
|
|
|
|
} while(bytesread == 1024);
|
|
|
|
|
|
|
|
filecontents = (char *)realloc(filecontents, size + 1);
|
|
|
|
|
|
|
|
filecontents[size] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle macOS Classic and Windows line endings
|
|
|
|
{
|
|
|
|
char *contentsscan = filecontents;
|
|
|
|
while(*contentsscan) {
|
|
|
|
if(*contentsscan == '\r')
|
|
|
|
*contentsscan = '\n';
|
|
|
|
++contentsscan;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DLog(@"Trying UTF8");
|
2019-11-17 22:44:47 +00:00
|
|
|
NSStringEncoding encoding = NSUTF8StringEncoding;
|
|
|
|
NSString *contents = [NSString stringWithCString:filecontents encoding:encoding];
|
2022-02-07 05:49:27 +00:00
|
|
|
if(!contents) {
|
2019-10-19 16:17:34 +00:00
|
|
|
DLog(@"Trying windows GB 18030 2000");
|
2022-02-07 05:49:27 +00:00
|
|
|
contents = [NSString stringWithCString:filecontents encoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)];
|
2019-10-19 16:17:34 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
if(!contents) {
|
2013-10-11 12:03:55 +00:00
|
|
|
DLog(@"Trying windows CP1251");
|
2022-02-07 05:49:27 +00:00
|
|
|
contents = [NSString stringWithCString:filecontents encoding:NSWindowsCP1251StringEncoding];
|
2007-10-20 15:08:06 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
if(!contents) {
|
2013-10-11 12:03:55 +00:00
|
|
|
DLog(@"Trying latin1");
|
2022-02-07 05:49:27 +00:00
|
|
|
contents = [NSString stringWithCString:filecontents encoding:NSISOLatin1StringEncoding];
|
2007-10-20 15:08:06 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
free(filecontents);
|
|
|
|
if(!contents) {
|
2019-11-17 22:44:47 +00:00
|
|
|
ALog(@"Could not open file...%@ %@", url, contents);
|
2022-01-19 02:12:57 +00:00
|
|
|
return @[];
|
2007-10-09 01:20:46 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2007-10-09 01:20:46 +00:00
|
|
|
NSMutableArray *entries = [NSMutableArray array];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
for(NSString *entry in [contents componentsSeparatedByString:@"\n"]) {
|
|
|
|
NSString *_entry = [entry stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
|
|
|
|
|
|
if([_entry hasPrefix:@"#EXT-X-MEDIA-SEQUENCE"]) // Let FFmpeg handle HLS
|
|
|
|
return @[];
|
|
|
|
|
|
|
|
if([_entry hasPrefix:@"#"] || [_entry isEqualToString:@""]) // Ignore extra info
|
2007-10-09 01:20:46 +00:00
|
|
|
continue;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
// Need to add basePath, and convert to URL
|
2019-11-17 22:44:47 +00:00
|
|
|
[entries addObject:[self urlForPath:_entry relativeTo:[url path]]];
|
2007-10-09 01:20:46 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2007-10-09 01:20:46 +00:00
|
|
|
return entries;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|