// // Magistrix.m // iLyrics // // Created by Kim Wittenburg on 14.06.12. // Copyright (c) 2012 __MyCompanyName__. All rights reserved. // // #import "Magistrix.h" #import "SearchResult.h" typedef enum { LyricsPage, ResultsPage, NoResultsPage, UnknownPage } PageType; @implementation Magistrix { NSString *query; NSInteger loadedResults; NSInteger resultCount; NSString *firstPage; } @synthesize enabled; -(NSString*) name { return @"Magistrix"; } -(NSDate *)hosterVersion { return [NSDate dateWithString:@"2012-06-16 11:00:00 +0100"]; } -(void) startNewSearchForQuery: (NSString*) q { [self resetLoadedResults]; query = q; NSInteger site = (loadedResults/10) + 1; NSString *searchPath = [NSString stringWithFormat:@"http://www.magistrix.de/lyrics/search?q=%@&page=%i", [query stringByFormattingForURL], site]; NSURL *searchURL = [NSURL URLWithString:searchPath]; NSError *error; firstPage = [NSString stringWithContentsOfURL:searchURL encoding:NSUTF8StringEncoding error:&error]; if (error || firstPage == nil) { firstPage = nil; return; } PageType type = [self typeOfPage:firstPage]; if (type == ResultsPage) { [self shouldSetResultCountFromPage:firstPage]; } else if (type == LyricsPage) { resultCount = 1; } else { resultCount = 0; } } -(BOOL) hasMoreResults { return loadedResults < resultCount; } -(NSArray*) nextResults { NSInteger site = (loadedResults/10) + 1; NSString *searchPath = [NSString stringWithFormat:@"http://www.magistrix.de/lyrics/search?q=%@&page=%i", [query stringByFormattingForURL] , site]; NSURL *searchURL = [NSURL URLWithString:searchPath]; NSString *page; if (site == 1 && firstPage != nil) { page = firstPage; } else { NSError *error; page = [NSString stringWithContentsOfURL:searchURL encoding:NSUTF8StringEncoding error:&error]; if (error) { //Network error or invalid query return nil; } } PageType pType = [self typeOfPage:page]; if (pType == LyricsPage) { loadedResults = 1; return [NSArray arrayWithObject:[self searchResultFromLyricsPage:page atURL:searchURL]]; } else if (pType == ResultsPage) { return [self searchResultsFromPage:page]; } else if (pType == NoResultsPage) { return [[NSArray alloc] init]; } else { NSRunAlertPanel(NSLocalizedString(@"Magistrix.messages.unknownPage.title", @""), NSLocalizedString(@"Magistrix.messages.unknownPage.detail", @""), NSLocalizedString(@"OK", @""), nil, nil); return [[NSArray alloc] init]; } } -(PageType) typeOfPage: (NSString *) page { if ([page rangeOfString:@"Songtext-Suche"].location != NSNotFound) { if ([page rangeOfString:@"
"].location != NSNotFound) { return NoResultsPage; } else { return ResultsPage; } } if ([page rangeOfString:@"
"].location != NSNotFound) { return LyricsPage; } return UnknownPage; } -(SearchResult*) searchResultFromLyricsPage: (NSString *) page atURL: (NSURL *) url{ NSInteger headingStart = NSMaxRange([page rangeOfString:@"

"]); NSInteger headingEnd = [page rangeOfString:@"

"].location; NSInteger artistStart = NSMaxRange([page rangeOfString:@">" options:NSCaseInsensitiveSearch range:NSMakeRange(headingStart, headingEnd-headingStart)]); NSRange artistEndTag = [page rangeOfString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(artistStart, headingEnd-artistStart)]; NSInteger artistEnd = artistEndTag.location; NSInteger songNameStart = NSMaxRange(artistEndTag); NSInteger songNameEnd = headingEnd; NSString *artist = [[page substringWithRange:NSMakeRange(artistStart, artistEnd-artistStart)] stringByRemovingHTMLTags]; NSString *songName = [page substringWithRange:NSMakeRange(songNameStart, songNameEnd-songNameStart)]; //Remove the " Lyric" and the " – " from the Song name songName = [[[songName substringToIndex:[songName length]-[@" Lyric" length]] substringFromIndex:[@" – " length]] stringByRemovingHTMLTags]; NSString *preview = [self lyricsFromPage:page]; return [[SearchResult alloc]initWithName:songName fromArtist:artist preview:preview link:url loadedByHoster:self]; } -(NSArray*) searchResultsFromPage: (NSString *) page { NSInteger resultsTableStart = NSMaxRange([page rangeOfString:@""]); NSInteger resultsTableEnd = [page rangeOfString:@"
"].location; NSArray *resultTags = [self resultTagsFromTable:[page substringWithRange:NSMakeRange(resultsTableStart, resultsTableEnd-resultsTableStart)]]; NSMutableArray *searchResults = [[NSMutableArray alloc] init]; for (NSString *tag in resultTags) { [searchResults addObject:[self searchResultFromResultTag:tag]]; } //Increase loadedResults by 10 which is a full results site //Even if there are less than 10 results on a page (would not have any effect) loadedResults += 10; return searchResults; } -(NSArray*) resultTagsFromTable: (NSString *) table { NSRange restRange = NSMakeRange(0, [table length]); NSMutableArray *tags = [[NSMutableArray alloc] init]; NSUInteger currentIndex = [table rangeOfString:@""].location; while (currentIndex != NSNotFound) { NSInteger startIndex = currentIndex + [@"" length]; NSInteger endIndex = [table rangeOfString:@"" options:NSCaseInsensitiveSearch range:restRange].location; NSRange tagRange = NSMakeRange(startIndex, endIndex-startIndex); [tags addObject:[table substringWithRange:tagRange]]; restRange = [self restRangeFromString:table subtractingRange:tagRange]; restRange.length -= [@"" length]; restRange.location += [@"" length]; currentIndex = [table rangeOfString:@"" options:NSCaseInsensitiveSearch range:restRange].location; } return tags; } -(SearchResult*) searchResultFromResultTag: (NSString *) tag { NSRange artistStartRange = [tag rangeOfString:@">"]; NSInteger artistEndIndex = [tag rangeOfString:@"<" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:artistStartRange]].location; NSInteger artistStartIndex = NSMaxRange(artistStartRange); NSString *artist = [[tag substringWithRange:NSMakeRange(artistStartIndex, artistEndIndex-artistStartIndex)] stringByRemovingHTMLTags]; NSRange restRange = [self restRangeFromString:tag subtractingRange:NSMakeRange(artistEndIndex, [@"" length])]; NSRange songNameTagStartRange = [tag rangeOfString:@"" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:songNameTagStartRange]]); NSInteger songNameEnd = [tag rangeOfString:@"" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:songNameTagStartRange]].location; NSString *songName = [[tag substringWithRange:NSMakeRange(songNameStart, songNameEnd-songNameStart)] stringByRemovingHTMLTags]; NSInteger previewStart = songNameEnd + [@"" length] + [@"\n

" length]; NSRange previewRestRange = NSMakeRange(previewStart, [tag length]-previewStart); NSInteger previewEnd = [tag rangeOfString:@"

" options:NSCaseInsensitiveSearch range:previewRestRange].location; NSString *preview = [[tag substringWithRange:NSMakeRange(previewStart, previewEnd-previewStart)] stringByRemovingHTMLTags]; return [[SearchResult alloc] initWithName:songName fromArtist:artist preview:preview link:link loadedByHoster:self]; } -(NSURL*) urlFromHref: (NSString *) link { if ([link hasPrefix:@"/"]) { return [NSURL URLWithString:[NSString stringWithFormat:@"http://www.Magistrix.de%@", link]]; } else { return [NSURL URLWithString:link]; } } -(NSRange) restRangeFromString: (NSString *) page subtractingRange: (NSRange) aRange { NSInteger loc = NSMaxRange(aRange); return NSMakeRange(loc, [page length]-loc); } -(void) shouldSetResultCountFromPage: (NSString *) page { if (resultCount <= 0) { //Nothing loaded before NSRange resultsLabelStartRange = [page rangeOfString:@"

Ergebnisse 1 bis "]; NSInteger resultsLabelEnd = [page rangeOfString:@"

" options:NSCaseInsensitiveSearch range:[self restRangeFromString:page subtractingRange:resultsLabelStartRange]].location; NSString *resultsLabel = [page substringWithRange:NSMakeRange(NSMaxRange(resultsLabelStartRange), resultsLabelEnd-resultsLabelStartRange.location)]; if ([resultsLabel rangeOfString:@"ungefähr"].location != NSNotFound){ //Needs not more than 100 which means 10 sites (which is the maximum) resultCount = 100; } else { NSInteger resultsStart = NSMaxRange([resultsLabel rangeOfString:@"von "]); NSInteger resultsEnd = [resultsLabel rangeOfString:@"<"].location; NSString *results = [resultsLabel substringWithRange:NSMakeRange(resultsStart, resultsEnd-resultsStart)]; resultCount = [results intValue]; } if (resultCount > 100) { resultCount = 100; } } } -(void) resetLoadedResults { loadedResults = 0; firstPage = nil; } -(Lyrics*) lyricsBySearchResult: (SearchResult *) result { NSError *error = nil; NSString *page = [NSString stringWithContentsOfURL:[result link] encoding:NSUTF8StringEncoding error:&error]; if (error) { return nil; } NSString *lyrics = [self lyricsFromPage:page]; return [[Lyrics alloc] initWithName:[result name] byArtist:[result artist] withLyrics:lyrics]; } -(NSString *) lyricsFromPage: (NSString *)page { NSInteger lyricsStart = NSMaxRange([page rangeOfString:@"
"]) + [@"\n" length]; NSRange restRange = NSMakeRange(lyricsStart, [page length]-lyricsStart); NSInteger lyricsEnd = [page rangeOfString:@"
" options:NSCaseInsensitiveSearch range:restRange].location; NSString *lyrics = [[page substringWithRange:NSMakeRange(lyricsStart, lyricsEnd-lyricsStart)] stringByRemovingHTMLTags]; return lyrics; } -(BOOL)canShowInBrowser:(id)result { return YES; } -(void)showInBrowser:(id)result { [[NSWorkspace sharedWorkspace] openURL:[result link]]; } @end