1/* 2 Project: MPDCon 3 4 Copyright (C) 2004 5 6 Author: Daniel Luederwald 7 8 Created: 2004-05-14 11:53:40 +0200 by flip 9 10 PlaylistItem 11 12 This application is free software; you can redistribute it and/or 13 modify it under the terms of the GNU General Public 14 License as published by the Free Software Foundation; either 15 version 2 of the License, or (at your option) any later version. 16 17 This application is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Library General Public License for more details. 21 22 You should have received a copy of the GNU General Public 23 License along with this library; if not, write to the Free 24 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. 25*/ 26 27#include "PlaylistItem.h" 28 29/* ---------------------- 30 - Private Categories - 31 ----------------------*/ 32// inspired/stolen from SOPE 33@interface NSObject(StringBindings) 34- (NSString *)valueForStringBinding:(NSString *)_key; 35@end 36 37@interface NSString(misc) 38- (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings; 39@end 40 41@implementation PlaylistItem 42 43// MPD itself doesn't provide the ability to retrieve lyrics via the server 44// have to use external services to provide that ability 45static NSString *LyricsAPIURL=@"http://lyrics.wikia.com/api.php?func=getSong&artist=$ARTIST$&song=$TITLE$&fmt=xml"; 46 47/* -------------------------- 48 - Initialization Methods - 49 --------------------------*/ 50 51- (id) init 52{ 53 MPDConDB = [SQLiteAdaptor sharedSQLiteAdaptor]; 54 return self; 55} 56 57- (void) dealloc 58{ 59 [artist release]; 60 [title release]; 61 [album release]; 62 [genre release]; 63 [trackNr release]; 64 [path release]; 65 [comment release]; 66 [composer release]; 67 [date release]; 68 [performer release]; 69 [disc release]; 70 [lyricsText release]; 71 [lyricsURL release]; 72 73 [super dealloc]; 74} 75 76/* -------------------- 77 - Accessor Methods - 78 --------------------*/ 79 80- (NSString *) getArtist 81{ 82 return artist; 83} 84 85- (void) setArtist: (NSString *)newArtist 86{ 87 [artist autorelease]; 88 artist = [newArtist copy]; 89} 90 91- (NSString *) getAlbum 92{ 93 return album; 94} 95 96- (void) setAlbum: (NSString *)newAlbum 97{ 98 [album autorelease]; 99 album = [newAlbum copy]; 100} 101 102- (NSString *) getGenre 103{ 104 return genre; 105} 106 107- (void) setGenre: (NSString *)newGenre 108{ 109 [genre autorelease]; 110 genre = [newGenre copy]; 111} 112 113- (NSString *) getTitle 114{ 115 return title; 116} 117 118- (void) setTitle: (NSString *)newTitle 119{ 120 [title autorelease]; 121 title = [newTitle copy]; 122} 123 124- (NSString *) getTrackNr 125{ 126 return trackNr; 127} 128 129- (void) setTrackNr: (NSString *)newNr 130{ 131 [trackNr autorelease]; 132 trackNr = [newNr copy]; 133} 134 135- (NSString *) getComment 136{ 137 return comment; 138} 139 140- (void) setComment: (NSString *)newComment 141{ 142 [comment autorelease]; 143 comment = [newComment copy]; 144} 145 146- (NSString *) getComposer 147{ 148 return composer; 149} 150 151- (void) setComposer: (NSString *)newComposer 152{ 153 [composer autorelease]; 154 composer = [newComposer copy]; 155} 156 157- (NSString *) getDate 158{ 159 return date; 160} 161 162- (void) setDate: (NSString *)newDate 163{ 164 [date autorelease]; 165 date = [newDate copy]; 166} 167 168- (NSString *) getPerformer 169{ 170 return performer; 171} 172 173- (void) setPerformer: (NSString *)newPerformer 174{ 175 [performer autorelease]; 176 performer = [newPerformer copy]; 177} 178 179- (NSString *) getDisc 180{ 181 return disc; 182} 183 184- (void) setDisc: (NSString *)newDisc 185{ 186 [disc autorelease]; 187 disc = [newDisc copy]; 188} 189 190- (int) getElapsedTime 191{ 192 return elapsedTime; 193} 194 195- (void) setElapsedTime: (int)newTime 196{ 197 elapsedTime = newTime; 198} 199 200- (int) getTotalTime 201{ 202 return totalTime; 203} 204 205- (void) setTotalTime: (int)newTime 206{ 207 totalTime = newTime; 208} 209 210- (NSString *) getPath 211{ 212 return path; 213} 214 215- (void) setPath: (NSString *)newPath 216{ 217 [path autorelease]; 218 path = [newPath copy]; 219} 220 221- (NSInteger) getRating 222{ 223 return [MPDConDB getRatingForFile:path]; 224} 225 226- (void) setRating: (NSInteger)newRating 227{ 228 [MPDConDB setRating: newRating forFile: path]; 229} 230 231- (NSDictionary *) getLyrics 232{ 233 NSDictionary *lyricsDict; 234 NSDictionary *bindings; 235 NSString *requestURL; 236 NSData *result; 237 NSURL *url; 238 NSXMLParser *parser; 239 240 if ([[self getArtist] isEqual:@"Unknown Artist"] || [[self getTitle] isEqual:@"Unknown Title"]) 241 { 242 lyricsText = [@"No lyrics retrieved for unknown artist or song." copy]; 243 lyricsURL = [@"http://lyrics.wikia.com" copy]; 244 lyricsDict = 245 [[NSDictionary alloc] initWithObjectsAndKeys: 246 lyricsText, @"lyricsText", 247 lyricsURL, @"lyricsURL", 248 nil]; 249 return [lyricsDict autorelease]; 250 } 251 252 lyricsDict = [MPDConDB getLyricsForFile:path]; 253 if (lyricsDict) 254 return lyricsDict; 255 256 bindings = 257 [[NSDictionary alloc] initWithObjectsAndKeys: 258 [[self getArtist] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], @"ARTIST", 259 [[self getTitle] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], @"TITLE", 260 nil]; 261 requestURL = [LyricsAPIURL stringByReplacingVariablesWithBindings:bindings]; 262 RELEASE(bindings); 263 264 url = [NSURL URLWithString:requestURL]; 265 result = [NSData dataWithContentsOfURL:url]; 266 if (result) 267 { 268 parser = [[[NSXMLParser alloc] initWithData:result] autorelease]; 269 [parser setShouldProcessNamespaces:NO]; 270 [parser setShouldReportNamespacePrefixes:NO]; 271 [parser setShouldResolveExternalEntities:NO]; 272 [parser setDelegate:self]; 273 [parser parse]; 274 // if we got something from the web, we save it in the DB 275 if (![lyricsText isEqual:@"Not found"]) 276 { 277 [self setLyrics: lyricsText withURL: lyricsURL]; 278 } 279 } 280 else 281 { 282 lyricsText = [@"unable to connect to lyrics.wikia.com" copy]; 283 lyricsURL = [@"http://lyrics.wikia.com" copy]; 284 } 285 286 lyricsDict = 287 [[NSDictionary alloc] initWithObjectsAndKeys: 288 lyricsText, @"lyricsText", 289 lyricsURL, @"lyricsURL", 290 nil]; 291 292 return [lyricsDict autorelease]; 293} 294- (void) setLyrics: (NSString *) _lyricsText withURL: (NSString *) _lyricsURL 295{ 296 [MPDConDB setLyrics: _lyricsText withURL: _lyricsURL forFile: path]; 297} 298 299- (void) setID: (int) newID 300{ 301 ID = newID; 302} 303 304- (int) getID 305{ 306 return ID; 307} 308 309- (void) setPos: (int) newPos 310{ 311 pos = newPos; 312} 313 314- (int) getPos 315{ 316 return pos; 317} 318 319/* getLyrics NSXMLParser delegate methods */ 320- (void) parser:(NSXMLParser *)parser 321didStartElement:(NSString *)elementName 322 namespaceURI:(NSString *)namespaceURI 323 qualifiedName:(NSString *)qualifiedName 324 attributes:(NSDictionary *)attributeDict 325{ 326 element = [NSMutableString string]; 327} 328 329- (void) parser:(NSXMLParser *)parser 330 didEndElement:(NSString *)elementName 331 namespaceURI:(NSString *)namespaceURI 332 qualifiedName:(NSString *)qName 333{ 334 if ([elementName isEqualToString:@"lyrics"]) 335 { 336 lyricsText = [element copy]; 337 } 338 else if ([elementName isEqualToString:@"url"]) 339 { 340 lyricsURL = [element copy]; 341 } 342} 343 344- (void) parser:(NSXMLParser *)parser 345foundCharacters:(NSString *)string 346{ 347 if(element == nil) 348 { 349 element = [[NSMutableString alloc] init]; 350 } 351 352 [element appendString:string]; 353} 354@end 355 356/* ---------------------- 357 - Private Categories - 358 ---------------------*/ 359 360@implementation NSObject(StringBindings) 361- (NSString *)valueForStringBinding:(NSString *)_key { 362 if (_key == nil) return nil; 363 return [self valueForKeyPath:_key]; 364} 365@end 366 367@implementation NSString(misc) 368- (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings 369{ 370 NSUInteger len, pos = 0; 371 unichar *wbuf = NULL; 372 NSMutableString *str = nil; 373 374 str = [self mutableCopy]; 375 len = [str length]; 376 wbuf = malloc(sizeof(unichar) * (len + 4)); 377 [self getCharacters:wbuf]; 378 379 while (pos < len) 380 { 381 if (pos + 1 == len) /* last entry */ 382 { 383 if (wbuf[pos] == '$') /* found $ without end-char */ 384 { 385 [NSException raise:@"NSStringVariableBindingException" 386 format:@"did not find end of variable for string %@", self]; 387 } 388 break; 389 } 390 if (wbuf[pos] == '$') 391 { 392 if (wbuf[pos + 1] == '$')/* found $$ --> $ */ 393 { 394 [str deleteCharactersInRange:NSMakeRange(pos, 1)]; 395 396 if (wbuf != NULL) 397 { 398 free(wbuf); wbuf = NULL; 399 } 400 len = [str length]; 401 wbuf = malloc(sizeof(unichar) * (len + 4)); 402 [str getCharacters:wbuf]; 403 } 404 else 405 { 406 NSUInteger startPos = pos; 407 408 pos += 2; /* wbuf[pos + 1] != '$' */ 409 while (pos < len) 410 { 411 if (wbuf[pos] != '$') 412 pos++; 413 else 414 break; 415 } 416 if (pos == len) /* end of string was reached */ 417 { 418 [NSException raise:@"NSStringVariableBindingException" 419 format:@"did not find end of variable for string %@", 420 self]; 421 } 422 else 423 { 424 NSString *key; 425 NSString *value; 426 427 key = [[NSString alloc] 428 initWithCharacters:(wbuf + startPos + 1) 429 length:(pos - startPos - 1)]; 430 431 if ((value = [_bindings valueForStringBinding:key]) == nil) 432 { 433 value = @""; 434 } 435 [key release]; key = nil; 436 437 [str replaceCharactersInRange: 438 NSMakeRange(startPos, pos - startPos + 1) 439 withString:value]; 440 441 if (wbuf != NULL) 442 { 443 free(wbuf); wbuf = NULL; 444 } 445 len = [str length]; 446 wbuf = malloc(sizeof(unichar) * (len + 4)); 447 [str getCharacters:wbuf]; 448 449 pos = startPos - 1 + [value length]; 450 } 451 } 452 } 453 pos++; 454 } 455 if (wbuf != NULL) 456 { 457 free(wbuf); wbuf = NULL; 458 } 459 { 460 id tmp = str; 461 str = [str copy]; 462 [tmp release]; tmp = nil; 463 } 464 return [str autorelease]; 465} 466@end /* NSString(misc) */ 467