Commit b28b9b4e authored by Felix Paul Kühne's avatar Felix Paul Kühne

local network: refactor shared library code to never block the main thread

parent 9135e2e8
......@@ -74,13 +74,7 @@
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationWillResignActiveNotification
object:[UIApplication sharedApplication]];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationDidBecomeActiveNotification
object:[UIApplication sharedApplication]];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_reachability stopNotifier];
[_ftpNetServiceBrowser stop];
......@@ -124,15 +118,22 @@
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:[UIApplication sharedApplication]];
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:[UIApplication sharedApplication]];
[defaultCenter addObserver:self
selector:@selector(applicationDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:[UIApplication sharedApplication]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:[UIApplication sharedApplication]];
[defaultCenter addObserver:self
selector:@selector(sharedLibraryFound:)
name:VLCSharedLibraryParserDeterminedNetserviceAsVLCInstance
object:nil];
/* if (SYSTEM_RUNS_IOS7_OR_LATER)
_sectionHeaderTexts = @[@"Universal Plug'n'Play (UPNP)", @"Plex Media Server (via Bonjour)", @"File Transfer Protocol (FTP)", NSLocalizedString(@"SHARED_VLC_IOS_LIBRARY", nil), @"libDSM", NSLocalizedString(@"SAP_STREAMS", nil)];
......@@ -426,7 +427,10 @@
NSString *name = [_httpServicesInfo[row] objectForKey:@"name"];
NSString *hostName = [_httpServicesInfo[row] objectForKey:@"hostName"];
NSString *portNum = [_httpServicesInfo[row] objectForKey:@"port"];
VLCSharedLibraryListViewController *targetViewController = [[VLCSharedLibraryListViewController alloc] initWithHttpServer:name serverAddress:hostName portNumber:portNum];
VLCSharedLibraryListViewController *targetViewController = [[VLCSharedLibraryListViewController alloc]
initWithHttpServer:name
serverAddress:hostName
portNumber:portNum];
[[self navigationController] pushViewController:targetViewController animated:YES];
} else if (section == 4) {
NSLog(@"DSM entry selected");
......@@ -571,17 +575,7 @@
}
} else if ([aNetService.type isEqualToString:@"_http._tcp."]) {
if ([[aNetService hostName] rangeOfString:_myHostName].location == NSNotFound) {
if ([_httpParser isVLCMediaServer:[aNetService hostName] port:[NSString stringWithFormat:@":%ld", (long)[aNetService port]]]) {
if (![_httpServices containsObject:aNetService]) {
[_httpServices addObject:aNetService];
NSMutableDictionary *_dictService = [[NSMutableDictionary alloc] init];
[_dictService setObject:[aNetService name] forKey:@"name"];
[_dictService setObject:[aNetService hostName] forKey:@"hostName"];
NSString *portStr = [[NSString alloc] initWithFormat:@":%ld", (long)[aNetService port]];
[_dictService setObject:portStr forKey:@"port"];
[_httpServicesInfo addObject:_dictService];
}
}
[_httpParser checkNetserviceForVLCService:aNetService];
}
}
[_rawNetServices removeObject:aNetService];
......@@ -594,6 +588,23 @@
[_rawNetServices removeObject:aNetService];
}
#pragma mark - shared library stuff
- (void)sharedLibraryFound:(NSNotification *)aNotification
{
NSNetService *aNetService = [aNotification.userInfo objectForKey:@"aNetService"];
if (![_httpServices containsObject:aNetService]) {
[_httpServices addObject:aNetService];
NSMutableDictionary *_dictService = [[NSMutableDictionary alloc] init];
[_dictService setObject:[aNetService name] forKey:@"name"];
[_dictService setObject:[aNetService hostName] forKey:@"hostName"];
NSString *portStr = [[NSString alloc] initWithFormat:@"%ld", (long)[aNetService port]];
[_dictService setObject:portStr forKey:@"port"];
[_httpServicesInfo addObject:_dictService];
}
}
#pragma mark - UPNP details
//protocol UPnPDBObserver
- (void)UPnPDBWillUpdate:(UPnPDB*)sender
......
......@@ -21,9 +21,9 @@
#import "VLCAlertView.h"
#import "UIDevice+VLC.h"
@interface VLCSharedLibraryListViewController () <UITableViewDataSource, UITableViewDelegate, VLCLocalNetworkListCell, UISearchBarDelegate, UISearchDisplayDelegate>
@interface VLCSharedLibraryListViewController () <UITableViewDataSource, UITableViewDelegate, VLCLocalNetworkListCell, UISearchBarDelegate, UISearchDisplayDelegate, VLCSharedLibraryParserDelegate>
{
NSMutableArray *_mutableObjectList;
NSArray *_serverDataArray;
NSCache *_imageCache;
NSString *_httpServerName;
......@@ -61,32 +61,30 @@
_httpServerAddress = serverAddress;
_httpServerPort = portNumber;
_mutableObjectList = [[NSMutableArray alloc] init];
_imageCache = [[NSCache alloc] init];
[_imageCache setCountLimit:50];
_httpParser = [[VLCSharedLibraryParser alloc] init];
_httpParser.delegate = self;
}
return self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[_httpParser fetchDataFromServer:_httpServerAddress port:_httpServerPort.longLongValue];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[_mutableObjectList removeAllObjects];
_mutableObjectList = [_httpParser VLCLibraryServerParser:_httpServerAddress port:_httpServerPort];
self.tableView.separatorColor = [UIColor VLCDarkBackgroundColor];
self.view.backgroundColor = [UIColor VLCDarkBackgroundColor];
NSString *titleValue;
if (_mutableObjectList.count == 0)
titleValue = _httpServerAddress;
else
titleValue = [_mutableObjectList.firstObject objectForKey:@"libTitle"];
self.title = titleValue;
self.title = _httpServerAddress;
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
UINavigationBar *navBar = self.navigationController.navigationBar;
......@@ -139,10 +137,12 @@
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView)
return _searchData.count;
else
return _mutableObjectList.count;
@synchronized(self) {
if (tableView == self.searchDisplayController.searchResultsTableView)
return _searchData.count;
else
return _serverDataArray.count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
......@@ -154,18 +154,18 @@
if (cell == nil)
cell = [VLCLocalNetworkListCell cellWithReuseIdentifier:CellIdentifier];
NSMutableArray *ObjList = [[NSMutableArray alloc] init];
[ObjList removeAllObjects];
if (tableView == self.searchDisplayController.searchResultsTableView)
[ObjList addObjectsFromArray:_searchData];
else
[ObjList addObjectsFromArray:_mutableObjectList];
NSDictionary *cellObject;
@synchronized(self) {
if (tableView == self.searchDisplayController.searchResultsTableView)
cellObject = _searchData[indexPath.row];
else
cellObject = _serverDataArray[indexPath.row];
}
[cell setTitle:[[ObjList objectAtIndex:indexPath.row] objectForKey:@"title"]];
[cell setTitle:[cellObject objectForKey:@"title"]];
[cell setIcon:[UIImage imageNamed:@"blank"]];
NSString *thumbPath = [[ObjList objectAtIndex:indexPath.row] objectForKey:@"thumb"];
NSString *thumbPath = [cellObject objectForKey:@"thumb"];
if (thumbPath) {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_async(queue, ^{
......@@ -179,9 +179,9 @@
});
}
NSInteger size = [[[ObjList objectAtIndex:indexPath.row] objectForKey:@"size"] integerValue];
NSInteger size = [[cellObject objectForKey:@"size"] integerValue];
NSString *mediaSize = [NSByteCountFormatter stringFromByteCount:size countStyle:NSByteCountFormatterCountStyleFile];
NSString *duration = [[ObjList objectAtIndex:indexPath.row] objectForKey:@"duration"];
NSString *duration = [cellObject objectForKey:@"duration"];
[cell setIsDirectory:NO];
[cell setSubtitle:[NSString stringWithFormat:@"%@ (%@)", mediaSize, duration]];
[cell setIsDownloadable:YES];
......@@ -214,21 +214,22 @@
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *ObjList = [[NSMutableArray alloc] init];
[ObjList removeAllObjects];
NSDictionary *selectedObject;
if (tableView == self.searchDisplayController.searchResultsTableView)
[ObjList addObjectsFromArray:_searchData];
else
[ObjList addObjectsFromArray:_mutableObjectList];
@synchronized(self) {
if (tableView == self.searchDisplayController.searchResultsTableView)
selectedObject = _searchData[indexPath.row];
else
selectedObject = _serverDataArray[indexPath.row];
}
NSString *URLofSubtitle = nil;
if (![[[ObjList objectAtIndex:indexPath.row] objectForKey:@"pathSubtitle"] isEqualToString:@""]) {
NSURL *url = [NSURL URLWithString:[[[ObjList objectAtIndex:indexPath.row] objectForKey:@"pathSubtitle"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
if (![[selectedObject objectForKey:@"pathSubtitle"] isEqualToString:@""]) {
NSURL *url = [NSURL URLWithString:[[selectedObject objectForKey:@"pathSubtitle"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
URLofSubtitle = [self _getFileSubtitleFromServer:url modeStream:YES];
}
NSURL *itemURL = [NSURL URLWithString:[[ObjList objectAtIndex:indexPath.row] objectForKey:@"pathfile"]];
NSURL *itemURL = [NSURL URLWithString:[selectedObject objectForKey:@"pathfile"]];
if (itemURL) {
VLCAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate openMovieWithExternalSubtitleFromURL:itemURL externalSubURL:URLofSubtitle];
......@@ -239,8 +240,19 @@
#pragma mark - Specifics
- (void)sharedLibraryDataProcessings:(NSArray *)result
{
@synchronized(self) {
_serverDataArray = result;
self.title = [_serverDataArray.firstObject objectForKey:@"libTitle"];
}
[self.tableView reloadData];
}
- (void)_downloadFileFromMediaItem:(NSURL *)itemURL
{
NSLog(@"trying to download %@", [itemURL absoluteString]);
if (![[itemURL absoluteString] isSupportedFormat]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"FILE_NOT_SUPPORTED", nil) message:[NSString stringWithFormat:NSLocalizedString(@"FILE_NOT_SUPPORTED_LONG", nil), [itemURL absoluteString]] delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_CANCEL", nil) otherButtonTitles:nil];
[alert show];
......@@ -249,13 +261,6 @@
}
}
- (void)reloadSharedLibrary
{
[_mutableObjectList removeAllObjects];
_mutableObjectList = [_httpParser VLCLibraryServerParser:_httpServerAddress port:_httpServerPort];
[self.tableView reloadData];
}
- (NSString *)_getFileSubtitleFromServer:(NSURL *)url modeStream:(BOOL)modeStream
{
NSString *FileSubtitlePath = nil;
......@@ -290,28 +295,29 @@
- (void)triggerDownloadForCell:(VLCLocalNetworkListCell *)cell
{
NSMutableArray *ObjList = [[NSMutableArray alloc] init];
[ObjList removeAllObjects];
NSDictionary *dataItem;
if ([self.searchDisplayController isActive])
[ObjList addObject:_searchData[[self.searchDisplayController.searchResultsTableView indexPathForCell:cell].row]];
else
[ObjList addObject:_mutableObjectList[[self.tableView indexPathForCell:cell].row]];
@synchronized(self) {
if ([self.searchDisplayController isActive])
dataItem = _searchData[[self.searchDisplayController.searchResultsTableView indexPathForCell:cell].row];
else
dataItem = _serverDataArray[[self.tableView indexPathForCell:cell].row];
}
NSURL *itemURL = [NSURL URLWithString:[ObjList[0] objectForKey:@"pathfile"]];
NSURL *itemURL = [NSURL URLWithString:[dataItem objectForKey:@"pathfile"]];
NSInteger size = [[[ObjList objectAtIndex:0] objectForKey:@"size"] integerValue];
NSInteger size = [[dataItem objectForKey:@"size"] integerValue];
if (size < [[UIDevice currentDevice] freeDiskspace].longLongValue) {
NSString *URLofSubtitle = nil;
if (![[[ObjList objectAtIndex:0] objectForKey:@"pathSubtitle"] isEqualToString:@""]) {
NSURL *url = [NSURL URLWithString:[[[ObjList objectAtIndex:0] objectForKey:@"pathSubtitle"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
if (![[dataItem objectForKey:@"pathSubtitle"] isEqualToString:@""]) {
NSURL *url = [NSURL URLWithString:[[dataItem objectForKey:@"pathSubtitle"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
URLofSubtitle = [self _getFileSubtitleFromServer:url modeStream:NO];
}
[self _downloadFileFromMediaItem:itemURL];
[cell.statusLabel showStatusMessage:NSLocalizedString(@"DOWNLOADING", nil)];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"DISK_FULL", nil) message:[NSString stringWithFormat:NSLocalizedString(@"DISK_FULL_FORMAT", nil), [[ObjList objectAtIndex:0] objectForKey:@"title"], [[UIDevice currentDevice] model]] delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_OK", nil) otherButtonTitles:nil];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"DISK_FULL", nil) message:[NSString stringWithFormat:NSLocalizedString(@"DISK_FULL_FORMAT", nil), [dataItem objectForKey:@"title"], [[UIDevice currentDevice] model]] delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_OK", nil) otherButtonTitles:nil];
[alert show];
}
}
......@@ -320,13 +326,15 @@
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[_searchData removeAllObjects];
NSUInteger count = _mutableObjectList.count;
for (NSUInteger i = 0; i < count; i++) {
NSRange nameRange;
nameRange = [[[_mutableObjectList objectAtIndex:i] objectForKey:@"title"] rangeOfString:searchString options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound)
[_searchData addObject:_mutableObjectList[i]];
@synchronized (self) {
[_searchData removeAllObjects];
NSUInteger count = _serverDataArray.count;
for (NSUInteger i = 0; i < count; i++) {
NSRange nameRange;
nameRange = [[_serverDataArray[i] objectForKey:@"title"] rangeOfString:searchString options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound)
[_searchData addObject:_serverDataArray[i]];
}
}
return YES;
}
......@@ -355,7 +363,11 @@
_refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:lastupdated attributes:attrsDictionary];
//end the refreshing
[_refreshControl endRefreshing];
[self performSelector:@selector(reloadSharedLibrary) withObject:nil];
@synchronized(self) {
_serverDataArray = nil;
}
[_httpParser fetchDataFromServer:_httpServerAddress port:_httpServerPort.longLongValue];
}
#pragma mark - Gesture Action
......
......@@ -10,9 +10,22 @@
*****************************************************************************/
#import <UIKit/UIKit.h>
extern NSString *const VLCSharedLibraryParserDeterminedNetserviceAsVLCInstance;
@protocol VLCSharedLibraryParserDelegate <NSObject>
@required
- (void)sharedLibraryDataProcessings:(NSArray *)result;
@end
@interface VLCSharedLibraryParser : NSObject
- (NSMutableArray *)VLCLibraryServerParser:(NSString *)adress port:(NSString *)port;
- (BOOL)isVLCMediaServer:(NSString *)adress port:(NSString *)port;
@property (readwrite, weak) id<VLCSharedLibraryParserDelegate> delegate;
- (void)checkNetserviceForVLCService:(NSNetService *)netservice;
- (void)fetchDataFromServer:(NSString *)hostname port:(long)port;
@end
......@@ -13,74 +13,97 @@
#define kLibraryXmlFile @"libMediaVLC.xml"
NSString *const VLCSharedLibraryParserDeterminedNetserviceAsVLCInstance = @"VLCSharedLibraryParserDeterminedNetserviceAsVLCInstance";
@interface VLCSharedLibraryParser () <NSXMLParserDelegate>
{
NSMutableArray *_containerInfo;
NSMutableDictionary *_dicoInfo;
NSString *_libraryServerUrl;
}
@end
@implementation VLCSharedLibraryParser
- (NSMutableArray *)VLCLibraryServerParser:(NSString *)adress port:(NSString *)port
- (void)checkNetserviceForVLCService:(NSNetService *)aNetService
{
[self performSelectorInBackground:@selector(parseNetServiceOnBackgroundThread:) withObject:aNetService];
}
- (void)parseNetServiceOnBackgroundThread:(NSNetService *)aNetService
{
NSString *hostnamePort = [NSString stringWithFormat:@"%@:%ld", [aNetService hostName], [aNetService port]];
NSArray *parsedContents = [self downloadAndProcessDataFromServer:hostnamePort];
if (parsedContents.count > 0) {
if ([[parsedContents.firstObject objectForKey:@"identifier"] isEqualToString:@"org.videolan.vlc-ios"]) {
[[NSNotificationCenter defaultCenter] postNotificationName:VLCSharedLibraryParserDeterminedNetserviceAsVLCInstance
object:self
userInfo:@{@"aNetService" : aNetService}];
}
}
}
- (void)fetchDataFromServer:(NSString *)hostname port:(long)port
{
NSString *hostnamePort = [NSString stringWithFormat:@"%@:%ld", hostname, port];
[self performSelectorInBackground:@selector(processDataOnBackgroundThreadFromHostnameAndPort:) withObject:hostnamePort];
}
- (void)processDataOnBackgroundThreadFromHostnameAndPort:(NSString *)hostnameAndPort
{
NSArray *parsedContents = [self downloadAndProcessDataFromServer:hostnameAndPort];
if ([self.delegate respondsToSelector:@selector(sharedLibraryDataProcessings:)])
[self.delegate sharedLibraryDataProcessings:parsedContents];
}
- (NSArray *)downloadAndProcessDataFromServer:(NSString *)hostnamePort
{
_containerInfo = [[NSMutableArray alloc] init];
[_containerInfo removeAllObjects];
_dicoInfo = [[NSMutableDictionary alloc] init];
_libraryServerUrl = [NSString stringWithFormat:@"http://%@%@", adress, port];
NSString *mediaServerUrl = [NSString stringWithFormat:@"%@/%@", _libraryServerUrl, kLibraryXmlFile];
NSString *serverURL = [NSString stringWithFormat:@"http://%@/%@", hostnamePort, kLibraryXmlFile];
NSURL *url = [[NSURL alloc] initWithString:mediaServerUrl];
NSURL *url = [[NSURL alloc] initWithString:serverURL];
NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[xmlparser setDelegate:self];
if (![xmlparser parse])
if (![xmlparser parse]) {
APLog(@"VLC Library Parser url Errors : %@", url);
return _containerInfo;
}
- (BOOL)isVLCMediaServer:(NSString *)adress port:(NSString *)port
{
NSMutableArray *mutableObjectList = [self VLCLibraryServerParser:adress port:port];
if (mutableObjectList.count > 0) {
NSString *identifier = [[mutableObjectList objectAtIndex:0] objectForKey:@"identifier"];
if ([identifier isEqualToString:@"org.videolan.vlc-ios"])
return YES;
return [NSArray array];
}
return NO;
return [NSArray arrayWithArray:_containerInfo];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:@"MediaContainer"]) {
if ([elementName isEqualToString:@"MediaContainer"]) {
if ([attributeDict objectForKey:@"size"])
[_dicoInfo setObject:[attributeDict objectForKey:@"size"] forKey:@"size"];
if ([attributeDict objectForKey:@"identifier"])
[_dicoInfo setObject:[attributeDict objectForKey:@"identifier"] forKey:@"identifier"];
if ([attributeDict objectForKey:@"libraryTitle"])
[_dicoInfo setObject:[attributeDict objectForKey:@"libraryTitle"] forKey:@"libTitle"];
} else if([elementName isEqualToString:@"Media"]) {
if([attributeDict objectForKey:@"title"])
} else if ([elementName isEqualToString:@"Media"]) {
if ([attributeDict objectForKey:@"title"])
[_dicoInfo setObject:[attributeDict objectForKey:@"title"] forKey:@"title"];
if([attributeDict objectForKey:@"thumb"])
if ([attributeDict objectForKey:@"thumb"])
[_dicoInfo setObject:[attributeDict objectForKey:@"thumb"] forKey:@"thumb"];
if([attributeDict objectForKey:@"duration"])
if ([attributeDict objectForKey:@"duration"])
[_dicoInfo setObject:[attributeDict objectForKey:@"duration"] forKey:@"duration"];
if([attributeDict objectForKey:@"size"])
if ([attributeDict objectForKey:@"size"])
[_dicoInfo setObject:[attributeDict objectForKey:@"size"] forKey:@"size"];
if([attributeDict objectForKey:@"pathfile"])
if ([attributeDict objectForKey:@"pathfile"])
[_dicoInfo setObject:[attributeDict objectForKey:@"pathfile"] forKey:@"pathfile"];
if([attributeDict objectForKey:@"pathSubtitle"])
if ([attributeDict objectForKey:@"pathSubtitle"])
[_dicoInfo setObject:[attributeDict objectForKey:@"pathSubtitle"] forKey:@"pathSubtitle"];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if(([elementName isEqualToString:@"Media"] || [elementName isEqualToString:@"MediaContainer"]) && [_dicoInfo count] > 0) {
if (([elementName isEqualToString:@"Media"] || [elementName isEqualToString:@"MediaContainer"]) && [_dicoInfo count] > 0) {
[_containerInfo addObject:_dicoInfo];
_dicoInfo = [[NSMutableDictionary alloc] init];
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment