Change AVMetadataItem - iphone

I have some files, -m4a -mp4 -mp3 etc.
I want to change these details
AVMetadataItem
AVMetadataCommonKeyArtwork
AVMetadataCommonKeyArtist
I can do with AVAssetExportSession, But I need to change the directory. Is there a way I can write directly on the file please?
I found this program, but does not work :(
NSError *error;
AVAssetWriter *assetWrtr = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:self.path] fileType:AVFileTypeAppleM4A error:&error];
NSLog(#"%#",error);
NSArray *existingMetadataArray = assetWrtr.metadata;
NSMutableArray *newMetadataArray = nil;
if (existingMetadataArray)
{
newMetadataArray = [existingMetadataArray mutableCopy]; // To prevent overriding of existing metadata
}
else
{
newMetadataArray = [[NSMutableArray alloc] init];
}
AVMutableMetadataItem *item = [[AVMutableMetadataItem alloc] init];
item.keySpace = AVMetadataKeySpaceCommon;
item.key = AVMetadataCommonKeyArtwork;
item.value = UIImagePNGRepresentation([[UIImage alloc] initWithContentsOfFile:[[NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#".image"]]);
[newMetadataArray addObject:item];
assetWrtr.metadata = newMetadataArray;
[assetWrtr startWriting];
[assetWrtr startSessionAtSourceTime:kCMTimeZero];

change UIImagePNGRepresentation to UIImageJPEGRepresentation you need jpeg data not png.

Related

Change program from getting music from iTunes to local file using URL

I am currently trying to make an app stream raw data from mic over mulipeer connectivity.
I have been using this tutorial as a base https://robots.thoughtbot.com/streaming-audio-to-multiple-listeners-via-ios-multipeer-connectivity
Now however I am struggling with changing the URL from itunes library to my local file.
I am no advanced programmer and this is some kind of summer project.
When the program is getting music from itunes library it uses this code:
- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection
{
[self dismissViewControllerAnimated:YES completion:nil];
if (self.outputStreamer) return;
self.song = mediaItemCollection.items[0];
NSMutableDictionary *info = [NSMutableDictionary dictionary];
info[#"title"] = [self.song valueForProperty:MPMediaItemPropertyTitle] ? [self.song valueForProperty:MPMediaItemPropertyTitle] : #"";
info[#"artist"] = [self.song valueForProperty:MPMediaItemPropertyArtist] ? [self.song valueForProperty:MPMediaItemPropertyArtist] : #"";
MPMediaItemArtwork *artwork = [self.song valueForProperty:MPMediaItemPropertyArtwork];
UIImage *image = [artwork imageWithSize:self.albumImage.frame.size];
if (image)
info[#"artwork"] = image;
if (info[#"artwork"])
self.albumImage.image = info[#"artwork"];
else
self.albumImage.image = nil;
self.songTitle.text = info[#"title"];
self.songArtist.text = info[#"artist"];
[self.session sendData:[NSKeyedArchiver archivedDataWithRootObject:[info copy]]];
NSArray *peers = [self.session connectedPeers];
if (peers.count) {
self.outputStreamer = [[TDAudioOutputStreamer alloc] initWithOutputStream:[self.session outputStreamForPeer:peers[0]]];
[self.outputStreamer streamAudioFromURL:[self.song valueForProperty:MPMediaItemPropertyAssetURL]];
[self.outputStreamer start];
But I want it to get music from the recorder:
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
#"MyAudioMemo.m4a",
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:nil];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:recorder.url error:nil];
I have been struggling with this for a while now and would appreciate any kind of help!

Some strange error occurs when manipulating events in the calendar of iOS device

I added some events to the calendar and save their eventIdentifier to file. When i want to remove all my events i read the eventIdentifier from that file to an array and remove each event with its event id. Here is the code to add event to calendar and save their event id to file:
- (void) addEventToCalendar: (id)object
{
#autoreleasepool {
int i = 0;
NSString *string_to_file = #"";
eventStore=[[EKEventStore alloc] init];
for(Schedule *sche in scheduleArray){
EKEvent *addEvent=[EKEvent eventWithEventStore:eventStore];
addEvent.title=sche.course_Name;
addEvent.startDate = [self stringToDate:sche.from_Date];
addEvent.endDate = [self stringToDate:sche.thru_Date];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[addEvent setCalendar:[eventStore defaultCalendarForNewEvents]];
NSDate *date_alarm = [addEvent.startDate dateByAddingTimeInterval:-(10*60)];
addEvent.alarms=[NSArray arrayWithObject:[EKAlarm alarmWithAbsoluteDate:date_alarm]];
NSError *err;
// do save event to calendar
[eventStore saveEvent:addEvent span:EKSpanThisEvent error:&err];
if (err == nil) {
NSString* str = [[NSString alloc] initWithFormat:#"%#", addEvent.eventIdentifier];
string_to_file = [string_to_file stringByAppendingString:str];
string_to_file = [string_to_file stringByAppendingString:#"\n"];
NSLog(#"String %d: %#",i, str);
}
else {
NSLog(#"Error %#",err);
}
i++;
}
// create file to save
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
inFile = [NSFileHandle fileHandleForWritingAtPath: filePath];
NSData *data = [string_to_file dataUsingEncoding:NSUTF16StringEncoding];
[inFile writeData:data];
}
}
And the code below to remove all events i have added to calendar
- (void) deleteEventInCalender {
filemgr = [NSFileManager defaultManager];
NSString *filePath = [self getFilePath:#"saveeventid.txt"];
NSFileHandle *inFile;
inFile = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *dataFile;
dataFile = [inFile readDataToEndOfFile];
NSString *tmp = #"";
NSString *temp = #"";
tmp = [NSString stringWithCharacters:[dataFile bytes] length:[dataFile length]/sizeof(unichar)];
if(![tmp isEqualToString:#""]){
tmp = [tmp substringFromIndex:1];
event_idArray = [[NSMutableArray alloc] init];
int j = 0;
while (![tmp isEqualToString:#""]){
int index_find_string = [tmp rangeOfString:#"\n"].location;
temp = [tmp substringWithRange:NSMakeRange(0, index_find_string)];
[event_idArray addObject:temp];
tmp = [tmp substringFromIndex:index_find_string + 1];
}
EKEventStore* store = [[EKEventStore alloc] init];
j = 0;
for(NSString *eventid in event_idArray){
EKEvent* event2 = [store eventWithIdentifier:eventid];
if (event2 != nil) {
NSLog(#"log: %d log id: %#", j, eventid);
NSError* error = nil;
// remove event
[store removeEvent:event2 span:EKSpanThisEvent error:&error];
}
j++;
}
[filemgr removeItemAtPath:filePath error:nil];
}
}
All codes above work well when i test on the iOS simulator with calendar.sqlitedb. But it makes some strange errors when i run on iPad device 5.0. That is sometime the calendar not remove event or when all events has been remove then after some minutes all events appear again... I don't understand, i don't know why and i very confuse. Does anyone has the same issue with me? Please share your solution!
Added another question: where the calendar database stored in the iOS 5.0 device.

Cocoa Development - Having trouble loading local XML files when running from device

I have a program that runs perfectly fine when I run on the simulator, but it won't run from the device at all. Part of the initial run involves loading a few XML files into core data and it seems that these files are not being found when running on the device.
Here is the beginning of the routine that loads the file. Any help is much appreciated.
- (BOOL) checkForUpdate:(NSString *)entityName {
NSArray *thisObjectArray = nil;
NSDate *thisEntityDate = nil;
BOOL returnVal = NO;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"AppData" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *appDataArray = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
AppData *thisAppData = [appDataArray objectAtIndex:0];
if ([entityName isEqualToString:#"Features"]) {
thisEntityDate = thisAppData.FeaturesUpdated;
}
else if ([entityName isEqualToString:#"DisplayTypes"]) {
thisEntityDate = thisAppData.DisplayTypesUpdated;
}
else if ([entityName isEqualToString:#"Sections"]) {
thisEntityDate = thisAppData.SectionsUpdated;
}
NSString *filePath = [[NSBundle mainBundle] pathForResource:entityName ofType:#"xml"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (doc != nil) {
// process information - this code is not being called because doc is returning nil
}
[xmlData release];
[doc release];
return returnVal;
}
Mind the case sensitivity. The device is case sensitive, whilst the simulator is not.

Creating NSMutableArray from xml file

I have an xml file with the following information.
<?xml version="1.0"?>
-<Party>
-<Player>
<Name>Butch</Name>
<Level>1</Level>
<Class>Fighter</Class>
</Player>
-<Player>
<Name>Shadow</Name>
<Level>2</Level>
<Class>Rogue</Class>
</Player>
-<Player>
<Name>Crak</Name>
<Level>3</Level>
<Class>Wizard</Class>
</Player>
</Party>
I try to add this to an NSMutableArray by doing the following.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Party" ofType:#"xml"];
NSData *xmlData = [[NSMutableArray alloc] initWithContentsOfFile:filePAth];
When I run this, my array object has no data in it.
If I replace the line with;
NSdata *xmlData = [NSdata dataWithContentsOfFole:filePath];
it will load my data but it is not in the format I require.
I'm very new to Objective-c and iPhone development and any help will be greatly appreciated.
If anymore info is needed I'll be happy to provide it.
edit - I'm using GDataXML to parse my xml
edit - My Parser class is as follows
#implementation PartyParser
+(NSString *)dataFilePath:(BOOL)forSave{
return [[NSBundle mainBundle] pathForResource:#"Party" ofType:#"xml"];
}
+(Party *)loadParty{
NSString *filePath = [self dataFilePath:FALSE];
//NSData *xmlData = [NSData dataWithContentsOfFile:filePath];
NSData *xmlData = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if(doc ==nil){return nil;}
NSLog(#"%#", doc.rootElement);
Party *party = [[[Party alloc] init] autorelease];
NSArray *partyMembers = [doc.rootElement elementsForName:#"Player"];
for (GDataXMLElement *partyMember in partyMembers)
{
NSString *name;
int level;
RPGClass rpgClass;
//Name
NSArray *names = [partyMember elementsForName:#"name"];
if(names.count > 0)
{
GDataXMLElement *firstName = (GDataXMLElement *) [names objectAtIndex:0];
name = firstName.stringValue;
}else continue;
//Level
NSArray *levels = [partyMember elementsForName:#"level"];
if(levels.count > 0)
{
GDataXMLElement *firstLevel = (GDataXMLElement *) [levels objectAtIndex:0];
level = firstLevel.stringValue.intValue;
}else continue;
//Class
NSArray *classes = [partyMember elementsForName:#"class"];
if(classes.count > 0)
{
GDataXMLElement *firstClass = (GDataXMLElement *) [classes objectAtIndex:0];
if([firstClass.stringValue caseInsensitiveCompare:#"fighter"] == NSOrderedSame)
{
rpgClass = RPGClassFighter;
}
else if([firstClass.stringValue caseInsensitiveCompare:#"rogue"] == NSOrderedSame)
{
rpgClass = RPGClassRogue;
}
else if([firstClass.stringValue caseInsensitiveCompare:#"wizard"] == NSOrderedSame)
{
rpgClass = RPGClassWizard;
}
else
{
continue;
}
}else continue;
Player *player = [[[Player alloc] initWithName:name level:level rpgClass:rpgClass] autorelease];
[party.players addObject:player];
}
//NSLog(#"%#", doc.rootElement);
//
[doc release];
[xmlData release];
return party;
}
#end
The XML file can not be any type of XML. It needs to be in the "property list" format.
Take a look at some Apple docs or some of the .plist files that will be in your project. That will show you how to create such a file.
Alternatively, create one using the "PList Editor" application that comes with the developer tools. It has a good UI for creating these files.
Lastly, your line "NSData* xmlData = ..." is very wrong - you're assigning a mutable array object to an NSData* variable. The types are not interchangeable by a long shot.
If you want to do full-blown XML parsing, there are various options that deserve a topic of their own. The XML used for plists is limited to Cocoa collections and simple data types.
Take a look to this XML Parser. It is called "TBXML", I have used that for a while and I'm quite happy with the result.
http://www.tbxml.co.uk/TBXML/TBXML_Free.html
Just place your XML file (e.g. "myFileName.xml") anywhere in your project.
Read the xml file contents to NSData using:
NSString *myBundleString = [[NSBundle mainBundle] pathForResource:#"myFileName" ofType:#"xml"];
NSData *myData = [NSData dataWithContentsOfFile:myBundleString];
And parse your data using NSXMLParser:
NSXMLParser *myParser = [[NSXMLParser alloc] initWithData:myData];
[myParser setDelegate:self];
[myParser parse];
Happy parsing using the delegate methods!

Find out when all processes in (void) is done?

I need to know how you can find out when all processes (loaded) from a - (void) are done, if it's possible.
Why? I'm loading in data for a UITableView, and I need to know when a Loading... view can be replaced with the UITableView, and when I can start creating the cells.
This is my code:
- (void) reloadData {
NSAutoreleasePool *releasePool = [[NSAutoreleasePool alloc] init];
NSLog(#"Reloading data.");
NSURL *urlPosts = [NSURL URLWithString:[NSString stringWithFormat:#"%#", URL]];
NSError *lookupError = nil;
NSString *data = [[NSString alloc] initWithContentsOfURL:urlPosts encoding:NSUTF8StringEncoding error:&lookupError];
postsData = [data componentsSeparatedByString:#"~"];
[data release], data = nil;
urlPosts = nil;
self.numberOfPosts = [[postsData objectAtIndex:0] intValue];
self.postsArrayID = [[postsData objectAtIndex:1] componentsSeparatedByString:#"#"];
self.postsArrayDate = [[postsData objectAtIndex:2] componentsSeparatedByString:#"#"];
self.postsArrayTitle = [[postsData objectAtIndex:3] componentsSeparatedByString:#"#"];
self.postsArrayComments = [[postsData objectAtIndex:4] componentsSeparatedByString:#"#"];
self.postsArrayImgSrc = [[postsData objectAtIndex:5] componentsSeparatedByString:#"#"];
NSMutableArray *writeToPlist = [NSMutableArray array];
NSMutableArray *writeToNoImagePlist = [NSMutableArray array];
NSMutableArray *imagesStored = [NSMutableArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"]];
int loop = 0;
for (NSString *postID in postsArrayID) {
if ([imagesStored containsObject:[NSString stringWithFormat:#"%#.png", postID]]){
NSLog(#"Allready stored, jump to next. ID: %#", postID);
continue;
}
NSLog(#"%#.png", postID);
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[postsArrayImgSrc objectAtIndex:loop]]];
// If image contains anything, set cellImage to image. If image is empty, try one more time or use noImage.png, set in IB
if (imageData == nil){
NSLog(#"imageData is empty before trying .jpeg");
// If image == nil, try to replace .jpg with .jpeg, and if that worked, set cellImage to that image. If that is also nil, use noImage.png, set in IB.
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[postsArrayImgSrc objectAtIndex:loop] stringByReplacingOccurrencesOfString:#".jpg" withString:#".jpeg"]]];
}
if (imageData != nil){
NSLog(#"imageData is NOT empty when creating file");
[fileManager createFileAtPath:[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:#"images/%#.png", postID]] contents:imageData attributes:nil];
[writeToPlist addObject:[NSString stringWithFormat:#"%#.png", postID]];
} else {
[writeToNoImagePlist addObject:[NSString stringWithFormat:#"%#", postID]];
}
imageData = nil;
loop++;
NSLog(#"imagePlist: %#\nnoImagePlist: %#", writeToPlist, writeToNoImagePlist);
}
NSMutableArray *writeToAllPlist = [NSMutableArray arrayWithArray:writeToPlist];
[writeToPlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:nowPlist]];
[writeToAllPlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"]]];
[writeToNoImagePlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"noImage.plist"]]];
[writeToPlist writeToFile:nowPlist atomically:YES];
[writeToAllPlist writeToFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"] atomically:YES];
[writeToNoImagePlist writeToFile:[rootPath stringByAppendingPathComponent:#"noImage.plist"] atomically:YES];
[releasePool release];
}
It is as simple as returning a bool at the bottom of the selector being run in the background, and reaload the UITableView.
Thanks to #iWasRobbed:
I have never done this, but just speculating: have you tried returning a BOOL at the very end so that the reloadData function will return TRUE when it gets to that point? I am assuming (possibly incorrectly) that the device serially handles tasks one-at-a-time, so give it a shot.