iOS - Download Video - iphone

I'd like to download a video from a remote URL and save it to a file in an iPhone app.
I know the video link works, since I have used it from AVPlayer, however, I am unable to download it. The response is always (null).
What is wrong with the following code?
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:someURLString]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:someFilePath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Successfully downloaded file to %#", [NSURL fileURLWithPath:someFilePath]);
NSLog(#"THE RESPONSE: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
Update
I commented out the operation.outputStream line, and this time I got a response. Does this mean that there is something wrong with the file path?

just create a link to that file, then use NSURLConnection to download.
Create a URL connection to download:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:strFileUrl]]; //strFileURL is url of your video/image
NSURLConnection *conection = [[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO] autorelease];
[conec start];
[request release];
Get path of file to save data:
strFilePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:strFileName];
Your class must adopt 3 methods of NSURLConnectionDelegate protocol: (please read about Protocol and Delegate)
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// create
[[NSFileManager defaultManager] createFileAtPath:strFilePath contents:nil attributes:nil];
file = [[NSFileHandle fileHandleForUpdatingAtPath:strFilePath] retain];// read more about file handle
if (file) {
[file seekToEndOfFile];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)receivedata
{
//write each data received
if( receivedata != nil){
if (file) {
[file seekToEndOfFile];
}
[file writeData:receivedata];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
//close file after finish getting data;
[file closeFile];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//do something when downloading failed
}
If you want to review you file, use a UIWebview to load it:
NSURL *fileURL = [NSURL fileURLWithPath:strFilePath];
[wvReview loadRequest:[NSURLRequest requestWithURL:fileURL]];

This is what was going wrong.
I was using the url of the video, and as part of the file path.
Why is this wrong? It has backslashes, so I assume iOS was getting confused.
Lesson learned: make sure that the string that you add to a directory to create a file does not have backslashes.
I hope this helps anyone else who makes this silly mistake. :P

Related

Download video from video url

I want to download the video from the url. I have the video url but don't know how to download it.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
strFileName = #"MyVideo";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://www.youtube.com/v/P9MeXRzKUuA?version=3&f=videos&app=youtube_gdata"]]; //strFileURL is url of your video/image
NSURLConnection *conection = [[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES] autorelease];
[conection start];
[request release];
strFilePath = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:strFileName] retain];
NSLog(#"file path = %#",strFilePath);
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// create
NSLog(#"file path = %#",strFilePath);
if (![[NSFileManager defaultManager] fileExistsAtPath:strFilePath]) {
[[NSFileManager defaultManager] createFileAtPath:strFilePath contents:nil attributes:nil];
}
file = [[NSFileHandle fileHandleForUpdatingAtPath:strFilePath] retain];// read more about file handle
if (file) {
[file seekToEndOfFile];
}
NSLog(#"response received");
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)receivedata
{
//write each data received
if( receivedata != nil){
if (file) {
[file seekToEndOfFile];
}
[file writeData:receivedata];
NSLog(#"data received");
}
[responseData appendData:receivedata];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
//close file after finish getting data;
NSLog(#"response = %#",[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
[file closeFile];
NSLog(#"file closed");
NSURL *fileURL = [NSURL fileURLWithPath:strFilePath];
NSLog(#"fileurl = %#",fileURL);
[webView loadRequest:[NSURLRequest requestWithURL:fileURL]];
}
In the connectiondidfinishedloading method when I print the response it is null.
Please help me with this
you forgot to initialize the responseData variable. Please do so.

how to store data in NS-Mutable-data in did-receive-data and than write to file

I am stuck from 2 days i want to display downlaod progress bar.
I am sending json in post to server and in response server send me video data.
To display progress bar i write some logic code like
In didreceivedata method of ASIhttep i am appending receive data with global NSmutabledata and in request done method i write that global Nsmutalbedata into file.
but file is blank it wont get store into file.
I know ASIHttprequest is old library but everyone suggest me to use AFnetworking but I dont want to change the code because it will take so much time and i have to read documents again.
anybody can help me how can i append data and after downlaod done write that appended data to file??
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[[NSURL alloc] initWithString:#"http://testing.io/dev.php/video/verifyReceipt"]];
[request setDidReceiveDataSelector:#selector(request:didReceiveData:)];
[request setPostValue:resultAsString forKey:#"verify"];
[request setDidFinishSelector:#selector(requestDone:)];
[request setTimeOutSeconds:120];
[request setDelegate:self];
[request setNumberOfTimesToRetryOnTimeout:2];
[request setDownloadProgressDelegate:progressBar];
request.showAccurateProgress = YES;
[request startSynchronous];
}
-(void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
{
[videoData appendData:data];
NSLog(#"data is %#",data);
}
- (void)requestDone:(ASIHTTPRequest *)request
{
//[MBProgressHUD hideHUDForView:self.view animated:YES];
// SAVED PDF PATH
// Get the Document directory
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// Add your filename to the directory to create your saved pdf location
NSString* movLocation = [documentDirectory stringByAppendingPathComponent:[fileName stringByAppendingString:#".mov"]];
if(request.responseStatusCode==200)
{
[videoData writeToFile:movLocation atomically:NO];
NSLog(#"in request done sucsessfully downlaod and store in database %d",request.responseStatusCode);
[DBHelper savePurchaseId:fileName];
[self movieReceived];
}
else
{
NSLog(#"in request downlaod and store in database failed %#",request.responseHeaders);
}
}
It's better to use asynchronous requests for the task like this. You can use the same ASIHTTPRequest class, but with block approach. Try to write the code similar to this:
-(void) verifyReceipt {
NSURL *theURL = [NSURL URLWithString:#"http://testing.io/dev.php/video/verifyReceipt"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0f];
[theRequest setHTTPMethod:#"POST"];
NSString *param1 = [self getParam1]; // getParam1 - some method to get useful data for request's body
NSNumber *param2 = [self getParam2];
NSString *postString = [NSString stringWithFormat:#"param1=%#&param2=%#", param1, param2];
[theRequest setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:theRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if ([data length] > 0 && error == nil) {
//[delegate receivedData:data]; // - if you want to notify some delegate about data arrival
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/fileArrived.ext", rootPath];
//try to access that local file for writing to it...
NSFileHandle *hFile = [NSFileHandle fileHandleForWritingAtPath:filePath];
//did we succeed in opening the existing file?
if (!hFile)
{ //nope->create that file!
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
//try to open it again...
hFile = [NSFileHandle fileHandleForWritingAtPath:filePath];
}
//did we finally get an accessable file?
if (!hFile)
{ //nope->bomb out!
NSLog(#"could not write to file %#", filePath);
return;
}
//we never know - hence we better catch possible exceptions!
#try
{
//seek to the end of the file
[hFile seekToEndOfFile];
//finally write our data to it
[hFile writeData:data];
}
#catch (NSException * e)
{
NSLog(#"exception when writing to file %#", filePath);
}
[hFile closeFile];
} else if ([data length] == 0 && error == nil) {
// [delegate emptyReply];
} else if (error != nil && error.code == NSURLErrorTimedOut) {
// [delegate timedOut];
} else if (error != nil) {
// [delegate downloadError:error];
}
[queue release];
}];
}
This will append every arrived chunk of your big data into a file as you wanted.
Customize the request POST body for your needs, and this should work. Asynchronously :)
Ok, first check your file path, I usually prefer to refer file path in this way:
you need to get the root of your application in this way:
NSString* rootPath = NSHomeDirectory();
and save the the data in one of the sub folder as specified by Apple file system guide line
NSString* fullPath = [rootPath stringByAppendingPathComponent:#"subFoldeder/file.extension"];
About append new data to old data a very quick solution could be initialize your videoData in this way:
NSMutableData *videoData = [[NSMutableData alloc] initWithContentsOfFile:#"filePath"];
After that you can procede like you are already duing appending data when you receive it, and write the complete file at the end
The correct thing to do, to don't use too much memory should be open a file seek it to the end and append data to the file

how to display progress bar while downloading file from request response in Asihttp

I am downloading video file from response.
i want to display downloading progress bar of HUD-progress.
but how can i do that.
I am sending verify json to server and server verify that send back the video file bytes. i want to display how much percentage of downloading is done by using HUD-progreasse bar.
If i call [request setDidReceiveDataSelector:#selector(request:didReceiveBytes:)]; than it display how much bytes i got but it doesn't store the bytes into cache file ( it doesn't not store file into phone)
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[[NSURL alloc] initWithString:#"http://testing.io/dev.php/video/verifyReceipt"]];
[request setPostValue:resultAsString forKey:#"verify"];// sending json in post
[request setDidReceiveDataSelector:#selector(request:didReceiveBytes:)];
[request setDidFinishSelector:#selector(requestDone:)];
[request setTimeOutSeconds:120];
[request setDelegate:self];
[request setNumberOfTimesToRetryOnTimeout:2];
[request setDownloadProgressDelegate:self];
request.showAccurateProgress = YES;
[request startSynchronous];
}
-(void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
{
[videoData appendData:data];// appending data with global NSmutabledata
NSLog(#"data is %#",data);
}
- (void)requestDone:(ASIHTTPRequest *)request{
//[MBProgressHUD hideHUDForView:self.view animated:YES];
// SAVED Video PATH
// Get the Document directory
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// Add your filename to the directory to create your saved video location
NSString* movLocation = [documentDirectory stringByAppendingPathComponent:[fileName stringByAppendingString:#".mov"]];
if(request.responseStatusCode==200)
{
[videoData writeToFile:movLocation atomically:NO];
NSLog(#"in request done sucsessfully downlaod and store in database %d",request.responseStatusCode);
[DBHelper savePurchaseId:fileName];
[self movieReceived];
}
else{
NSLog(#"in request downlaod and store in database failed %#",request.responseHeaders);
}
}
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSLog(#"%#",request.error);
}
fileUrl = string of URL to download a video.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[fileUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:destPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
// Give alert that downloading successful.
NSLog(#"Successfully downloaded file to %#", destPath);
/* To call delegate to response the result. */
[self.target parserDidDownloadItem:destPath];
HUD.detailsLabelText = [NSString stringWithFormat:#"%# %i%%",[JGlobals getLocalvalue:#"Downloading"],100];
[HUD hide:TRUE];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// Give alert that downloading failed
NSLog(#"Error: %#", error);
/* To call delegate to response the result. */
[self.target parserDidFailToDownloadItem:error];
[HUD hide:TRUE];
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite)
{
// Progress
float totalProgress = (totalBytesWritten / (totalBytesExpectedToWrite * 1.0f) * 100);
HUD.detailsLabelText = [NSString stringWithFormat:#"Downloading %i%%", MIN((int)(totalProgress), 99)];
}];
[operation start];
I'm thinking of a method which might not be the right one, but it going to save you from writing a lot of code.
First set a normal UIProgressView instance as the download progress delegate like this
[request setDownloadProgressDelegate:uiprogreeViewInstance];
Now ASIHTTPRequest framework will take care of updating that progressview when the downloading will be taking place. ProgressView has a property named progress, which ranges from 0.0 to 1.0.
Now instantiate MBProgressHUD, add it as your subview where you want. Set the progress value of the MBProgressHUD instance to that of the UIProgressView. Hide the uiprogressview instance.

How to download CSV file from server in Objective-C

I'm developing a new iPhone application, Here i have parsed a 'csv' file from local, and its working with me. When i try to download the 'csv' file from the server programmatically, it didn't workout for me. Could you please help me?
Loading data from local file (Working fine)
- (void)viewDidLoad
{
[super viewDidLoad];
NSString * file = [[NSBundle bundleForClass:[self class]] pathForResource:#"sample" ofType:#"csv"];
NSStringEncoding encoding = 0;
NSString * csv = [NSString stringWithContentsOfFile:file usedEncoding:&encoding error:nil];
NSArray *fields = [csv CSVComponents];
NSLog(#"fields: %#", fields); //getting the result content
}
Download the file from Server (failed)
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"connectionDidFinishLoading"); //nothing showing here
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fullName = [NSString stringWithFormat:#"quotes.csv"];
NSString *fullFilePath = [NSString stringWithFormat:#"%#/%#",docDir,fullName];
[receivedData writeToFile:fullFilePath atomically:YES];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"data: %#", data); //nothing showing here
if (receivedData)
[receivedData appendData:data];
else
receivedData = [[NSMutableData alloc] initWithData:data];
}
- (void)loadDatafromURL
{
NSURL *url = [NSURL URLWithString:#"http://download.finance.yahoo.com/d/quotes.csv?s=^GSPC,^IXIC,^dji,^GSPC,^BVSP,^GSPTSE,^FTSE,^GDAXI,^FCHI,^STOXX50E,^AEX,^IBEX,^SSMI,^N225,^AXJO,^HSI,^NSEI&f=sl1d1t1c1ohgv&e=.csv"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self];
}
Implement this method:
-(void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
You'll find that you're getting an error of
Error Domain=NSURLErrorDomain Code=-1000 "bad URL" UserInfo=0xf663f40 {NSUnderlyingError=0xf663de0 "bad URL", NSLocalizedDescription=bad URL}
I've looked into downloading information this way before, and I think one problem you're having is that separate symbols have to be separated with a "+". Also, when pulling an index, you can't pass the "^" symbol as part of the URL. You have to replace it with "%5E".
So, add this:
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"%#", [error description]);
}
And change your URL to this:
NSString *urlString = #"http://download.finance.yahoo.com/d/quotes.csv?s=^GSPC+^IXIC+^dji+^GSPC+^BVSP+^GSPTSE+^FTSE+^GDAXI+^FCHI+^STOXX50E+^AEX+^IBEX+^SSMI+^N225+^AXJO+^HSI+^NSEI&f=sl1d1t1c1ohgv&e=.csv";
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
Now it works for me! I even checked the output .csv file, and it looks good to go! One full quote per line.
If you plan on fetching more data over the network than this single csv, you could have a look at AFNetworking, it's a great library for doing network operations.
A working solution would then look a bit like this:
- (void)getCSVAsynch {
NSString *unescaped = #"http://download.finance.yahoo.com/d/quotes.csv?s=^GSPC,^IXIC,^dji,^GSPC,^BVSP,^GSPTSE,^FTSE,^GDAXI,^FCHI,^STOXX50E,^AEX,^IBEX,^SSMI,^N225,^AXJO,^HSI,^NSEI&f=sl1d1t1c1ohgv&e=.csv";
NSURL *url = [NSURL URLWithString:[unescaped stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"CSV: %#", [[NSString alloc] initWithBytes:[responseObject bytes] length:[responseObject length] encoding:NSUTF8StringEncoding]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Things go boom. %#", [error localizedDescription]);
}];
[operation start];
}

Resume download functionality in NSURLConnection

I am downloading some very large data from a server with the NSURLConnection class.
How can I implement a pause facility so that I can resume downloading?
You can't pause, per-se, but you can cancel a connection, and then create a new one to resume where the old left off. However, the server you're connecting to must support the Range header. Set this to "bytes=size_already_downloaded-", and it should pick up right where you cancelled it.
To resume downloading and get the rest of the file you can set the Range value in HTTP request header by doing something like this:
- (void)downloadFromUrl:(NSURL*)url toFilePath:(NSString *)filePath {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
if (!request) {
NSLog(#"Error creating request");
// Do something
}
[request setHTTPMethod:#"GET"];
// Add header to existing file
NSFileManager *fm = [NSFileManager defaultManager];
if([fm fileExistsAtPath:filePath]) {
NSError *error = nil;
NSDictionary * fileProp = [fm attributesOfItemAtPath:filePath error:&error];
if (error) {
NSLog(#"Error: %#", [error localizedDescription]);
// Do something
} else {
// Set header to resume
long long fileSize = [[fileProp objectForKey:#"NSFileSize"]longLongValue];
NSString *range = #"bytes=";
range = [[range stringByAppendingString:[[NSNumber numberWithLongLong:fileSize] stringValue]] stringByAppendingString:#"-"];
[request setValue:range forHTTPHeaderField:#"Range"];
}
}
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (!connection) {
NSLog(#"Connection failed.");
// Do something
}
}
Also you can use
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response to check if the existing file is fully downloaded by checking the expected size: [response expectedContentLength];. If sizes match you probably want to cancel the connection.