Archived
1

-Added Songtexte.com Lyrics Hoster

-Repositioned the load more results button into the outline view
-Improved the replacing of html escape characters
-Lyrics Hosters can now be dragged into a preferred order in the preference window
-Changed results outline's column ordering method
-Some code changes
-Replaced the Buttons in the lyrics pane with an action button
-Preferred order of lyrics hosters will now be saved
-Translation Improvements
This commit is contained in:
Kim Wittenburg
2012-06-24 14:22:37 +02:00
parent 98b0e70a8b
commit 41b1ef775c
27 changed files with 3611 additions and 2826 deletions

View File

@@ -64,4 +64,28 @@
-Fixed a bug: Returned false results when having a "&" in the query\ -Fixed a bug: Returned false results when having a "&" in the query\
-Fixed a resource bug\ -Fixed a resource bug\
-Fixed special characters in url bug (final)\ -Fixed special characters in url bug (final)\
} \
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc
\i \cf0 06/23/2012\
\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
\i0 \cf0 -Added Songtexte.com Lyrics Hoster\
-Repositioned the load more results button into the outline view\
-Improved the replacing of html escape characters\
-Lyrics Hosters can now be dragged into a preferred order in the preference window\
-Changed results outline's column ordering method\
-Some code changes\
-Replaced the Buttons in the lyrics pane with an action button\
\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\b \cf0 Release No. 1.2
\b0 -
\i 06/24/2012\
\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
\i0 \cf0 -Preferred order of lyrics hosters will now be saved\
-Translation Improvements}

View File

@@ -1,78 +1,103 @@
/* Standards */ /* ---------- Standards - Werden in Warnmeldungen angezeigt ---------- */
"OK" = "OK"; "OK" = "OK";
"Yes" = "Ja"; "Yes" = "Ja";
"No" = "Nein"; "No" = "Nein";
/* "No Selection" label(s) in the main window */
/* ---------- iLyrics - Hauptfenster ---------- */
//----- Angezeigte Texte
/* Wird im PopUp Button im Ergebniss-Bereich angezeigt */
"iLyrics.text.loadNextResultsFrom" = "Weitere Ergebnisse laden von...";
/* "Keine Auswahl" - Texte im Hauptfenster */
"iLyrics.text.noSelection" = "Keine Auswahl"; "iLyrics.text.noSelection" = "Keine Auswahl";
/* Preference Items */ //----- Warnmeldungen
"iLyrics.text.enableAutoLyrics" = "Auto-Lyrics einschalten";
"iLyrics.text.disableAutoLyrics" = "Auto-Lyrics ausschalten"; //Songtextsuche (Aufgerufen, wenn der Benutzer im Suchfeld die Eingabe mit ↩ (Eingabetaste) bestätigt)
/* Text displayed when a lyrics hoster does not return a valid NSDate in it's hosterVersion method */ /* Ein Netzwerkfehler ist aufgetreten, während die Ergebnisse geladen wurden */
"iLyrics.text.illegalDateFormat" = "Keine Angabe"; "iLyrics.messages.networkOrQueryError.title" = "Sie sind nicht mit demInternet verbunden.";
"iLyrics.messages.networkOrQueryError.detail" = "Überprüfen Sie Ihre WLAN oder Ethernet Verbindung und versuchen Sie es erneut. Weitere Informationen erhalten Sie mit der Netzwerkdiagnose.";
/* Preferences */ /* Die Suche ergab keine Ergebnisse */
/* Search Token Replacements */ "iLyrics.messages.noResults.title" = "Ihre Suche ergab keine Ergebnisse.";
"iLyrics.searchToken.%name%" = "Songname"; "iLyrics.messages.noResults.detail" = "Keine der Songtextseiten bietet einen Songtext an, der zu Ihrer Suche passt.";
"iLyrics.searchToken.%artist%" = "Interpret"; /* Fehler beim Speichern eines Songtextes */
"iLyrics.messages.error.saveLyrics.title" = "Der Songtext konnte nicht gesichert werden.";
"iLyrics.messages.error.saveLyrics.detail" = "Prüfen Sie, ob Sie die Schreibberechtigung am ausgewählten Ort besitzen.";
"iLyrics.searchToken.%album%" = "Album";
/* Magistrix Hoster */ /* ---------- iLyrics - Einstellungsfenster ---------- */
"Magistrix.text.noPreview" = "Keine Vorschau verfügbar.";
"Hoster.text.noNetwork" = "Keine Netzwerkverbindung."; //----- Angezeigte Texte
"Hoster.messages.networkOrQueryError.title" = "Sie sind zur Zeit nicht mit dem Internet verbunden oder haben einen ungültigen Suchtext eingegeben."; /* Fenstertitel, wenn der Allgemein-Tab aktiv ist (Dies ist nicht die Beschriftung in der Symbolleiste) */
"iLyrics.preferences.text.general" = "Allgemein";
"Hoster.messages.networkOrQueryError.detail" = "1. Prüfen Sie, ob ihre WLAN oder Ethernet-Verbndung korrekt funktioniert. Weitere Informationenen erhalten Sie mit dem Netzwerkdiagnose Programm.\n2. Entfernen Sie alle Sonderzeichen (§$&€) aus dem Suchfeld und versuchen Sie es erneut."; /* Fenstertitel, wenn der Auto-Lyrics-Tab aktiv ist (Dies ist nicht die Beschriftung in der Symbolleiste) */
"iLyrics.preferences.text.auto-lyrics" = "Auto-Lyrics";
/* Auto-Lyrics texte */
"iLyrics.preferences.text.enableAutoLyrics" = "Auto-Lyrics einschalten";
"iLyrics.preferences.text.disableAutoLyrics" = "Auto-Lyrics ausschalten";
/* ---------- Songtextseiten ---------- */
//----- Angezeigte Texte
/* Dies wird als Titel, Interpret und Songtexte angezeigt, wenn keine Internetverbindung besteht */
"Hoster.text.noNetwork" = "Keine Internetverbiindung.";
/* Die wird im Vorschaubereich angezeigt, wenn keine Vorschau erfügbar ist */
"Hoster.text.noPreviewAvailable" = "Keine Vorschau verfügbar.";
//----- Warnmeldungen (%hoster% wird mit dem Namen der Songtextseite ersetzt)
/* Es ist ein Netzwerkfehler aufgetreten, während ein Songtext geladen wurde */
"Hoster.messages.networkOrQueryError.title" = "Der Songtext konnte nicht geladen werden, da Sie nicht mit dem Internet verbunden sind.";
"Hoster.messages.networkOrQueryError.detail" = "Überprüfen Sie Ihre WLAN oder Ethernet Verbindung und versuchen Sie es erneut. Weitere Informationen erhalten Sie mit der Netzwerkdiagnose.";
/* (Veraltet - Dieser Text sollte nicht mehr verwendet werden, da er durch die hasMoreResults Methode des LyricsHoster-Protokolls hinfällig geworden ist) */
"Hoster.messages.noResults.title" = "Ihre Suche ergab keine Ergebnisse."; "Hoster.messages.noResults.title" = "Ihre Suche ergab keine Ergebnisse.";
"Hoster.messages.noResults.detail" = "%hoster% bietet leider keine Songtexte an, die zu Ihrer Suche passen.";
"Hoster.messages.noResults.detail" = "Magistrix.de hat keine Songtexte in der Datenbank, die mit der Suchanfrage übereinstimmen."; /* Sollte niemals verwendet werden - Dies bedeutet, dass ein Fehler beim verarbeiten einer Seite aufgetreten ist. (Das kann vorkommen, wenn die Seiten aktualisiert werden und z.B. neue Features eingebaut werden.) */
"Magistrix.messages.unknownPage.title" = "Es ist ein Fehler beim Verarbeiten Ihrer Anfrage aufgetreten.";
"Magistrix.messages.unknownPage.detail" = "Normalerweise kann dieses Problem behoben werden, indem Sie die neuste Version von iLyrics herunterladen.";
"Magistrix.messages.unknownPage.title" = "Ein Fehler ist beim Verarbeiten der Anfrage aufgetreten.";
"Magistrix.messages.unknownPage.detail" = "Normalerweise kann dieses Problem behoben werden, wenn Sie die neuste Version von iLyrics laden."; /* ---------- iTunes Verbindung ---------- */
/* iTunes connection */ //----- Warnmeldungen
/* By text used in the artist menu item where %@ is the artist */
"iTunes.text.byFormat" = "von %@";
/* iTunes (error) messages */ /* Es wird kein Titel wiedergegeben */
"iTunes.messages.iTunesIdle.title" = "iTunes ist zurzeit nicht geöffnet."; "iTunes.messages.noTrackPlaying.title" = "iTunes spielt zur Zeit keine Musik.";
"iTunes.messages.noTrackPlaying.detail" = "Geben Sie einen Titel mit iTunes wieder oder wählen Sie \"Wiedergabe/Pause\" aus dem iTunes Menu, um diese Funktion zu verwenden.";
"iTunes.messages.iTunesIdle.detail" = "Öffnen Sie iTunes um dieses Feature nutzen zu können."; /* Soll der gesicherte Songtext ersetzt werden */
"iTunes.messages.replaceLyrics.title" = "Der aktuelle iTunes Titel hat bereits einen Songtext. Möchten Sie diesen ersetzen?";
"iTunes.messages.replaceLyrics.detail" = "Der alte Songtext kann nicht wiederhergestellt werden.";
"iTunes.messages.noTrackPlaying.title" = "iTunes spielt zurzeit keine Musik."; /* ---------- Spotify Verbindung ---------- */
"iTunes.messages.noTrackPlaying.detail" = "Starten sie die Wiedergabe über iTunes oder über den \"Play/Pause\" Button."; /* Es wird kein Titel wiedergegeben */
"Spotify.messages.noTrackPlaying.title" = "Spotify spielt zur Zeit keine Musik.";
"Spotify.messages.noTrackPlaying.detail" = "Geben Sie einen Titel in Spotify wieder, um diese Funktion zu verwenden.";
"iTunes.messages.replaceLyrics.title" = "Der aktuelle iTunes Titel hat bereits einen Songtext. Möchten Sie ihn ersetzen?"; /* ---------- Growl Benachrichtigungen ---------- */
"iTunes.messages.replaceLyrics.detail" = "Beim Eretzen geht der alte Songtext vollständig verloren. Diese Aktion kann nicht wiederrufen werden."; /* Ein Songtext wurde erfolgreich gesichert (In der detailierten Beschreibung %@ ist der Name der Datei) */
"Growl.messages.lyricsSaved.title" = "Songtext gesichert";
/* Spotify Messages */ "Growl.messages.lyricsSaved.detail" = "nach \"%@\".";
"Spotify.messages.noTrackPlaying.title" = "Spotify spielt zut Zeit keine Musik.";
"Spotify.messages.noTrackPlaying.detail" = "Starten Sie die Wiedergabe in Spotify, um diese Funktion zu verwenden.";
/* Error while saving */
"messages.error.saveLyrics.title" = "Der Songtext konnte nicht gespeichert werden.";
"messages.error.saveLyrics.detail" = "Prüfen Sie, ob Sie Schreibberechtigung an diesem Ort haben.";
/* Growl */
"Growl.messages.lyricsSaved.title" = "Songtext gespeichert";
"Growl.messages.lyricsSaved.detail" = "nach \"%@\"";
/* Ein Songtext wurde erfolgreich an iTunes übermittelt (In der detailierten Beschreibung %@ ist der Name des iTunes Titels) */
"Growl.messages.lyricsSent.title" = "Songtext an iTunes gesendet"; "Growl.messages.lyricsSent.title" = "Songtext an iTunes gesendet";
"Growl.messages.lyricsSent.detail" = "Songtext an \"%@\" gesendet.";
"Growl.messages.lyricsSent.detail" = "Songtext an \"%@\" gesendet.";

View File

@@ -1,79 +1,103 @@
/* Standards */ /* ---------- Standards - Used in Alert sheets and dialogs ---------- */
"OK" = "OK"; "OK" = "OK";
"Yes" = "Yes"; "Yes" = "Yes";
"No" = "No"; "No" = "No";
/* ---------- iLyrics - Main Window ---------- */
//----- Displayed Texts
/* Used in the NSPopUpButton inside the results outline */
"iLyrics.text.loadNextResultsFrom" = "Load more results from...";
/* "No Selection" label(s) in the main window */ /* "No Selection" label(s) in the main window */
"iLyrics.text.noSelection" = "No Selection"; "iLyrics.text.noSelection" = "No Selection";
/* Preference Items */ //----- Alert Texts
"iLyrics.text.enableAutoLyrics" = "Enable Auto-Lyrics";
"iLyrics.text.disableAutoLyrics" = "Disable Auto-Lyrics"; //Lyrics Search (Called when the user presses ↩ (Enter) on the search field)
/* Text displayed when a lyrics hoster does not return a valid NSDate in it's hosterVersion method */ /* A Network error occured while loading search results */
"iLyrics.text.illegalDateFormat" = "No Specification"; "iLyrics.messages.networkOrQueryError.title" = "You are not connected to the internet.";
"iLyrics.messages.networkOrQueryError.detail" = "Check if you are connected through WLAN or Ethernet. Use the Network Diagnostics for more information.";
/* Preferences */ /* The search did not return any results */
/* Search Token Replacements */ "iLyrics.messages.noResults.title" = "Your search did not return any results.";
"iLyrics.searchToken.%name%" = "Song Name"; "iLyrics.messages.noResults.detail" = "None of the hosters provides any songtexts matching to the entered query.";
"iLyrics.searchToken.%artist%" = "Artist";
"iLyrics.searchToken.%album%" = "Album";
/* Magistrix Hoster */
"Magistrix.text.noPreview" = "No Preview available.";
"Hoster.text.noNetwork" = "No Network connection";
"Hoster.messages.networkOrQueryError.title" = "You are not connected to the internet or you entered an invalid query.";
"Hoster.messages.networkOrQueryError.detail" = "1. Check if you are connected through WLAN or Ethernet. Use the Network Diagnostics for more information.\n2. Try to remove any special characters (&%$§€) and try again.";
"Hoster.messages.noResults.title" = "Your search did not return any results.";
"Hoster.messages.noResults.detail" = "Magistrix.de does not provide any lyrics for this search.";
"Magistrix.messages.unknownPage.title" = "There occured an error while parsing the request.";
"Magistrix.messages.unknownPage.detail" = "Normally this can be fixed by getting the newest versin of iLyrics.";
/* iTunes connection */
/* By text used in the artist menu item where %@ is the artist */
"iTunes.text.byFormat" = "by %@";
/* iTunes (error) messages */
"iTunes.messages.iTunesIdle.title" = "iTunes is idle.";
"iTunes.messages.iTunesIdle.detail" = "Please start iTunes to use this feature.";
"iTunes.messages.noTrackPlaying.title" = "iTunes does currently not play any music.";
"iTunes.messages.noTrackPlaying.detail" = "Play a track using iTunes or select \"Play/Pause\" from the iTunes menu.";
"iTunes.messages.replaceLyrics.title" = "The current iTunes track already has lyrics. Do you want to replace them?";
"iTunes.messages.replaceLyrics.detail" = "If you replace the old lyrics they can not be restored anymore.";
/* Spotify Messages */
"Spotify.messages.noTrackPlaying.title" = "Spotify does currently not play any music.";
"Spotify.messages.noTrackPlaying.detail" = "Play a track in Spotify to use this feature.";
/* Error while saving */ /* Error while saving */
"messages.error.saveLyrics.title" = "The Lyrics could not be saved."; "iLyrics.messages.error.saveLyrics.title" = "The Lyrics could not be saved.";
"iLyrics.messages.error.saveLyrics.detail" = "Ceck if you have the rights to write to the selected location.";
"messages.error.saveLyrics.detail" = "Ceck if you have the rights to write to the selected location.";
/* Growl */ /* ---------- iLyrics - Preference Window ---------- */
//----- Displayed Texts
/* Window title when the general tab is active (This is not the label for the toolbar item) */
"iLyrics.preferences.text.general" = "General";
/* Window title when the Auto-Lyrics tab is active (This is not the label for the toolbar item) */
"iLyrics.preferences.text.auto-lyrics" = "Auto-Lyrics";
/* Auto-Lyrics texts */
"iLyrics.preferences.text.enableAutoLyrics" = "Enable Auto-Lyrics";
"iLyrics.preferences.text.disableAutoLyrics" = "Disable Auto-Lyrics";
/* ---------- Lyrics Hosters ---------- */
//----- Displayed Texts
/* Displayed as song name, artist and lyrics when network connection failed */
"Hoster.text.noNetwork" = "No Network connection.";
/* Displayed in the preview area if no preview is available */
"Hoster.text.noPreviewAvailable" = "No Preview available.";
//----- Alert Texts (%hoster% will be replaced with the name of the hoster)
/* A Network error occured while loading a lyric */
"Hoster.messages.networkOrQueryError.title" = "You are not connected to the internet.";
"Hoster.messages.networkOrQueryError.detail" = "Check if you are connected through WLAN or Ethernet. Use the Network Diagnostics for more information.";
/* (Deprecated - Should not be used because of the hasMoreResults method of the LyricsHoster protocol) */
"Hoster.messages.noResults.title" = "Your search did not return any results.";
"Hoster.messages.noResults.detail" = "%hoster% does not provide any lyrics matching to the entered query.";
/* Should never be used - This means that a parsing error occured */
"Magistrix.messages.unknownPage.title" = "There occured an error while parsing the request.";
"Magistrix.messages.unknownPage.detail" = "Normally this can be fixed by getting the newest versin of iLyrics.";
/* ---------- iTunes Connection ---------- */
//----- Alert Texts
/* No Track is currently playing */
"iTunes.messages.noTrackPlaying.title" = "iTunes does currently not play any music.";
"iTunes.messages.noTrackPlaying.detail" = "Play a track using iTunes or select \"Play/Pause\" from the iTunes menu.";
/* Ask the user wether to replace the old lyrics */
"iTunes.messages.replaceLyrics.title" = "The current iTunes track already has lyrics. Do you want to replace them?";
"iTunes.messages.replaceLyrics.detail" = "If you replace the old lyrics they can not be restored anymore.";
/* ---------- Spotify Connection ---------- */
/* No Track is currentlx playing */
"Spotify.messages.noTrackPlaying.title" = "Spotify does currently not play any music.";
"Spotify.messages.noTrackPlaying.detail" = "Play a track in Spotify to use this feature.";
/* ---------- Growl Notifications ---------- */
/* A lyric was successfully saved to a file (in the detail message %@ is the filename) */
"Growl.messages.lyricsSaved.title" = "Lyrics Saved"; "Growl.messages.lyricsSaved.title" = "Lyrics Saved";
"Growl.messages.lyricsSaved.detail" = "to \"%@\".";
"Growl.messages.lyricsSaved.detail" = "to \"%@\""; /* A lyric was successfully saved to the current iTunes song (in the detail message %@ is the name of the iTunes song) */
"Growl.messages.lyricsSent.title" = "Lyrics sent to iTunes"; "Growl.messages.lyricsSent.title" = "Lyrics sent to iTunes";
"Growl.messages.lyricsSent.detail" = "Lyrics sent to \"%@\".";
/* %@ is the name of the song */
"Growl.messages.lyricsSent.detail" = "Lyrics sent to \"%@\".";

View File

@@ -12,7 +12,6 @@
3B20EF381584EA9A006C0CDF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF371584EA9A006C0CDF /* main.m */; }; 3B20EF381584EA9A006C0CDF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF371584EA9A006C0CDF /* main.m */; };
3B20EF3C1584EA9A006C0CDF /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF3A1584EA9A006C0CDF /* Credits.rtf */; }; 3B20EF3C1584EA9A006C0CDF /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF3A1584EA9A006C0CDF /* Credits.rtf */; };
3B20EF3F1584EA9A006C0CDF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF3E1584EA9A006C0CDF /* AppDelegate.m */; }; 3B20EF3F1584EA9A006C0CDF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF3E1584EA9A006C0CDF /* AppDelegate.m */; };
3B20EF421584EA9A006C0CDF /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF401584EA9A006C0CDF /* MainMenu.xib */; };
3B20EF491584EAA3006C0CDF /* iLyrics.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF481584EAA3006C0CDF /* iLyrics.icns */; }; 3B20EF491584EAA3006C0CDF /* iLyrics.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF481584EAA3006C0CDF /* iLyrics.icns */; };
3B20EF4D1584EAAD006C0CDF /* iTunes.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF4A1584EAAD006C0CDF /* iTunes.icns */; }; 3B20EF4D1584EAAD006C0CDF /* iTunes.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF4A1584EAAD006C0CDF /* iTunes.icns */; };
3B20EF4E1584EAAD006C0CDF /* Diamond.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF4B1584EAAD006C0CDF /* Diamond.tiff */; }; 3B20EF4E1584EAAD006C0CDF /* Diamond.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF4B1584EAAD006C0CDF /* Diamond.tiff */; };
@@ -20,11 +19,16 @@
3B20EF521584EAF8006C0CDF /* MainController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF511584EAF8006C0CDF /* MainController.m */; }; 3B20EF521584EAF8006C0CDF /* MainController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF511584EAF8006C0CDF /* MainController.m */; };
3B20EF551584ECD9006C0CDF /* Lyrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF541584ECD9006C0CDF /* Lyrics.m */; }; 3B20EF551584ECD9006C0CDF /* Lyrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF541584ECD9006C0CDF /* Lyrics.m */; };
3B20EF5C1584F34E006C0CDF /* SearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF5B1584F34E006C0CDF /* SearchResult.m */; }; 3B20EF5C1584F34E006C0CDF /* SearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF5B1584F34E006C0CDF /* SearchResult.m */; };
3B20EF6115853345006C0CDF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF6315853345006C0CDF /* Localizable.strings */; };
3B2DC55B158CD31E00C004A4 /* PreferencesWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B2DC55A158CD31E00C004A4 /* PreferencesWindow.m */; }; 3B2DC55B158CD31E00C004A4 /* PreferencesWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B2DC55A158CD31E00C004A4 /* PreferencesWindow.m */; };
3B3A377C15972079002085CE /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B3A377E15972079002085CE /* MainMenu.xib */; };
3B3A3781159727FE002085CE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3B3A3783159727FE002085CE /* Localizable.strings */; };
3B3A378715973040002085CE /* MP3Lyrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A378615973040002085CE /* MP3Lyrics.m */; };
3B5E8BA2159496DA0028363E /* Songtexte.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B5E8BA1159496DA0028363E /* Songtexte.m */; };
3B5E8BA515949B380028363E /* LyricsHosterUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B5E8BA415949B380028363E /* LyricsHosterUtil.m */; };
3B5E8ED2158E7AC40082A769 /* Spotify.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3B5E8ED1158E7AC40082A769 /* Spotify.icns */; }; 3B5E8ED2158E7AC40082A769 /* Spotify.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3B5E8ED1158E7AC40082A769 /* Spotify.icns */; };
3B73010E158CDF7200D3AF26 /* AutoLyrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B73010D158CDF7200D3AF26 /* AutoLyrics.m */; }; 3B73010E158CDF7200D3AF26 /* AutoLyrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B73010D158CDF7200D3AF26 /* AutoLyrics.m */; };
3B81D4FE1586248F00916CE3 /* ScriptingBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B81D4FD1586248F00916CE3 /* ScriptingBridge.framework */; }; 3B81D4FE1586248F00916CE3 /* ScriptingBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B81D4FD1586248F00916CE3 /* ScriptingBridge.framework */; };
3B9A33611590BDE700B844EF /* iLyrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B9A33601590BDE700B844EF /* iLyrics.m */; };
3BBD9B76158C873F00A5CD2C /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBD9B75158C873F00A5CD2C /* Growl.framework */; }; 3BBD9B76158C873F00A5CD2C /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBD9B75158C873F00A5CD2C /* Growl.framework */; };
3BBD9B78158C876200A5CD2C /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3BBD9B75158C873F00A5CD2C /* Growl.framework */; }; 3BBD9B78158C876200A5CD2C /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3BBD9B75158C873F00A5CD2C /* Growl.framework */; };
3BBD9B7A158C87D000A5CD2C /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = 3BBD9B79158C87D000A5CD2C /* Growl Registration Ticket.growlRegDict */; }; 3BBD9B7A158C87D000A5CD2C /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = 3BBD9B79158C87D000A5CD2C /* Growl Registration Ticket.growlRegDict */; };
@@ -58,7 +62,6 @@
3B20EF3B1584EA9A006C0CDF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = "<group>"; }; 3B20EF3B1584EA9A006C0CDF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = "<group>"; };
3B20EF3D1584EA9A006C0CDF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; 3B20EF3D1584EA9A006C0CDF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
3B20EF3E1584EA9A006C0CDF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; 3B20EF3E1584EA9A006C0CDF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
3B20EF411584EA9A006C0CDF /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
3B20EF481584EAA3006C0CDF /* iLyrics.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = iLyrics.icns; sourceTree = "<group>"; }; 3B20EF481584EAA3006C0CDF /* iLyrics.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = iLyrics.icns; sourceTree = "<group>"; };
3B20EF4A1584EAAD006C0CDF /* iTunes.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = iTunes.icns; sourceTree = "<group>"; }; 3B20EF4A1584EAAD006C0CDF /* iTunes.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = iTunes.icns; sourceTree = "<group>"; };
3B20EF4B1584EAAD006C0CDF /* Diamond.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Diamond.tiff; sourceTree = "<group>"; }; 3B20EF4B1584EAAD006C0CDF /* Diamond.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Diamond.tiff; sourceTree = "<group>"; };
@@ -70,17 +73,27 @@
3B20EF5A1584F34E006C0CDF /* SearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchResult.h; sourceTree = "<group>"; }; 3B20EF5A1584F34E006C0CDF /* SearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchResult.h; sourceTree = "<group>"; };
3B20EF5B1584F34E006C0CDF /* SearchResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchResult.m; sourceTree = "<group>"; }; 3B20EF5B1584F34E006C0CDF /* SearchResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchResult.m; sourceTree = "<group>"; };
3B20EF5D1584F458006C0CDF /* LyricsHoster.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LyricsHoster.h; sourceTree = "<group>"; }; 3B20EF5D1584F458006C0CDF /* LyricsHoster.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LyricsHoster.h; sourceTree = "<group>"; };
3B20EF6215853345006C0CDF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
3B2DC558158CCE8100C004A4 /* Changelog.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Changelog.rtf; sourceTree = SOURCE_ROOT; }; 3B2DC558158CCE8100C004A4 /* Changelog.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Changelog.rtf; sourceTree = SOURCE_ROOT; };
3B2DC559158CD31E00C004A4 /* PreferencesWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesWindow.h; sourceTree = "<group>"; }; 3B2DC559158CD31E00C004A4 /* PreferencesWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesWindow.h; sourceTree = "<group>"; };
3B2DC55A158CD31E00C004A4 /* PreferencesWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesWindow.m; sourceTree = "<group>"; }; 3B2DC55A158CD31E00C004A4 /* PreferencesWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesWindow.m; sourceTree = "<group>"; };
3B3A377D15972079002085CE /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
3B3A378015972080002085CE /* de */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = de; path = de.lproj/MainMenu.xib; sourceTree = "<group>"; };
3B3A3782159727FE002085CE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
3B3A378415972803002085CE /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
3B3A378515973040002085CE /* MP3Lyrics.h */ = {isa = PBXFileReference; fileEncoding = 4; path = MP3Lyrics.h; sourceTree = "<group>"; };
3B3A378615973040002085CE /* MP3Lyrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MP3Lyrics.m; sourceTree = "<group>"; };
3B5E8BA0159496DA0028363E /* Songtexte.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Songtexte.h; sourceTree = "<group>"; };
3B5E8BA1159496DA0028363E /* Songtexte.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Songtexte.m; sourceTree = "<group>"; };
3B5E8BA315949B380028363E /* LyricsHosterUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LyricsHosterUtil.h; sourceTree = "<group>"; };
3B5E8BA415949B380028363E /* LyricsHosterUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LyricsHosterUtil.m; sourceTree = "<group>"; };
3B5E8ECD158E788D0082A769 /* Spotify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Spotify.h; sourceTree = "<group>"; }; 3B5E8ECD158E788D0082A769 /* Spotify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Spotify.h; sourceTree = "<group>"; };
3B5E8ED1158E7AC40082A769 /* Spotify.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Spotify.icns; sourceTree = "<group>"; }; 3B5E8ED1158E7AC40082A769 /* Spotify.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Spotify.icns; sourceTree = "<group>"; };
3B73010C158CDF7200D3AF26 /* AutoLyrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoLyrics.h; sourceTree = "<group>"; }; 3B73010C158CDF7200D3AF26 /* AutoLyrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoLyrics.h; sourceTree = "<group>"; };
3B73010D158CDF7200D3AF26 /* AutoLyrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AutoLyrics.m; sourceTree = "<group>"; }; 3B73010D158CDF7200D3AF26 /* AutoLyrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AutoLyrics.m; sourceTree = "<group>"; };
3B81D4FD1586248F00916CE3 /* ScriptingBridge.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScriptingBridge.framework; path = System/Library/Frameworks/ScriptingBridge.framework; sourceTree = SDKROOT; }; 3B81D4FD1586248F00916CE3 /* ScriptingBridge.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScriptingBridge.framework; path = System/Library/Frameworks/ScriptingBridge.framework; sourceTree = SDKROOT; };
3B81D5041586298100916CE3 /* iTunes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTunes.h; sourceTree = "<group>"; }; 3B81D5041586298100916CE3 /* iTunes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTunes.h; sourceTree = "<group>"; };
3BBD9B72158C7F8A00A5CD2C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; }; 3B9A335F1590BDE700B844EF /* iLyrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iLyrics.h; sourceTree = "<group>"; };
3B9A33601590BDE700B844EF /* iLyrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iLyrics.m; sourceTree = "<group>"; };
3BBD9B74158C86DA00A5CD2C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = de; path = de.lproj/Credits.rtf; sourceTree = "<group>"; }; 3BBD9B74158C86DA00A5CD2C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = de; path = de.lproj/Credits.rtf; sourceTree = "<group>"; };
3BBD9B75158C873F00A5CD2C /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Growl.framework; sourceTree = "<group>"; }; 3BBD9B75158C873F00A5CD2C /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Growl.framework; sourceTree = "<group>"; };
3BBD9B79158C87D000A5CD2C /* Growl Registration Ticket.growlRegDict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "Growl Registration Ticket.growlRegDict"; sourceTree = "<group>"; }; 3BBD9B79158C87D000A5CD2C /* Growl Registration Ticket.growlRegDict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "Growl Registration Ticket.growlRegDict"; sourceTree = "<group>"; };
@@ -88,7 +101,6 @@
3BE95010158A269D00E78FEF /* Magistrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Magistrix.m; sourceTree = "<group>"; }; 3BE95010158A269D00E78FEF /* Magistrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Magistrix.m; sourceTree = "<group>"; };
3BE95015158A291500E78FEF /* PreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesController.h; sourceTree = "<group>"; }; 3BE95015158A291500E78FEF /* PreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesController.h; sourceTree = "<group>"; };
3BE95016158A291500E78FEF /* PreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesController.m; sourceTree = "<group>"; }; 3BE95016158A291500E78FEF /* PreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesController.m; sourceTree = "<group>"; };
3BFDD3FA158D420400BF32B0 /* de */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = de; path = de.lproj/MainMenu.xib; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -148,15 +160,17 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3B2DC558158CCE8100C004A4 /* Changelog.rtf */, 3B2DC558158CCE8100C004A4 /* Changelog.rtf */,
3B9A335F1590BDE700B844EF /* iLyrics.h */,
3B9A33601590BDE700B844EF /* iLyrics.m */,
3B73010C158CDF7200D3AF26 /* AutoLyrics.h */,
3B73010D158CDF7200D3AF26 /* AutoLyrics.m */,
3B20EF3D1584EA9A006C0CDF /* AppDelegate.h */, 3B20EF3D1584EA9A006C0CDF /* AppDelegate.h */,
3B20EF3E1584EA9A006C0CDF /* AppDelegate.m */, 3B20EF3E1584EA9A006C0CDF /* AppDelegate.m */,
3B20EF401584EA9A006C0CDF /* MainMenu.xib */, 3B3A377E15972079002085CE /* MainMenu.xib */,
3B2DC559158CD31E00C004A4 /* PreferencesWindow.h */, 3B2DC559158CD31E00C004A4 /* PreferencesWindow.h */,
3B2DC55A158CD31E00C004A4 /* PreferencesWindow.m */, 3B2DC55A158CD31E00C004A4 /* PreferencesWindow.m */,
3BE95015158A291500E78FEF /* PreferencesController.h */, 3BE95015158A291500E78FEF /* PreferencesController.h */,
3BE95016158A291500E78FEF /* PreferencesController.m */, 3BE95016158A291500E78FEF /* PreferencesController.m */,
3B73010C158CDF7200D3AF26 /* AutoLyrics.h */,
3B73010D158CDF7200D3AF26 /* AutoLyrics.m */,
3B20EF501584EAF8006C0CDF /* MainController.h */, 3B20EF501584EAF8006C0CDF /* MainController.h */,
3B20EF511584EAF8006C0CDF /* MainController.m */, 3B20EF511584EAF8006C0CDF /* MainController.m */,
3B20EF5A1584F34E006C0CDF /* SearchResult.h */, 3B20EF5A1584F34E006C0CDF /* SearchResult.h */,
@@ -186,9 +200,15 @@
3B20EF591584F31D006C0CDF /* Lyrics Hoster */ = { 3B20EF591584F31D006C0CDF /* Lyrics Hoster */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3B20EF5D1584F458006C0CDF /* LyricsHoster.h */,
3BE9500F158A269D00E78FEF /* Magistrix.h */, 3BE9500F158A269D00E78FEF /* Magistrix.h */,
3BE95010158A269D00E78FEF /* Magistrix.m */, 3BE95010158A269D00E78FEF /* Magistrix.m */,
3B20EF5D1584F458006C0CDF /* LyricsHoster.h */, 3B5E8BA0159496DA0028363E /* Songtexte.h */,
3B5E8BA1159496DA0028363E /* Songtexte.m */,
3B3A378515973040002085CE /* MP3Lyrics.h */,
3B3A378615973040002085CE /* MP3Lyrics.m */,
3B5E8BA315949B380028363E /* LyricsHosterUtil.h */,
3B5E8BA415949B380028363E /* LyricsHosterUtil.m */,
); );
name = "Lyrics Hoster"; name = "Lyrics Hoster";
sourceTree = "<group>"; sourceTree = "<group>";
@@ -202,7 +222,7 @@
3B20EF4A1584EAAD006C0CDF /* iTunes.icns */, 3B20EF4A1584EAAD006C0CDF /* iTunes.icns */,
3B20EF4B1584EAAD006C0CDF /* Diamond.tiff */, 3B20EF4B1584EAAD006C0CDF /* Diamond.tiff */,
3B20EF4C1584EAAD006C0CDF /* Download-icon.icns */, 3B20EF4C1584EAAD006C0CDF /* Download-icon.icns */,
3B20EF6315853345006C0CDF /* Localizable.strings */, 3B3A3783159727FE002085CE /* Localizable.strings */,
); );
name = Resources; name = Resources;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -261,12 +281,12 @@
files = ( files = (
3B20EF361584EA9A006C0CDF /* InfoPlist.strings in Resources */, 3B20EF361584EA9A006C0CDF /* InfoPlist.strings in Resources */,
3B20EF3C1584EA9A006C0CDF /* Credits.rtf in Resources */, 3B20EF3C1584EA9A006C0CDF /* Credits.rtf in Resources */,
3B20EF421584EA9A006C0CDF /* MainMenu.xib in Resources */, 3B3A377C15972079002085CE /* MainMenu.xib in Resources */,
3B20EF491584EAA3006C0CDF /* iLyrics.icns in Resources */, 3B20EF491584EAA3006C0CDF /* iLyrics.icns in Resources */,
3B20EF4D1584EAAD006C0CDF /* iTunes.icns in Resources */, 3B20EF4D1584EAAD006C0CDF /* iTunes.icns in Resources */,
3B20EF4E1584EAAD006C0CDF /* Diamond.tiff in Resources */, 3B20EF4E1584EAAD006C0CDF /* Diamond.tiff in Resources */,
3B20EF4F1584EAAD006C0CDF /* Download-icon.icns in Resources */, 3B20EF4F1584EAAD006C0CDF /* Download-icon.icns in Resources */,
3B20EF6115853345006C0CDF /* Localizable.strings in Resources */, 3B3A3781159727FE002085CE /* Localizable.strings in Resources */,
3BBD9B7A158C87D000A5CD2C /* Growl Registration Ticket.growlRegDict in Resources */, 3BBD9B7A158C87D000A5CD2C /* Growl Registration Ticket.growlRegDict in Resources */,
3B5E8ED2158E7AC40082A769 /* Spotify.icns in Resources */, 3B5E8ED2158E7AC40082A769 /* Spotify.icns in Resources */,
); );
@@ -288,6 +308,10 @@
3BE95017158A291500E78FEF /* PreferencesController.m in Sources */, 3BE95017158A291500E78FEF /* PreferencesController.m in Sources */,
3B2DC55B158CD31E00C004A4 /* PreferencesWindow.m in Sources */, 3B2DC55B158CD31E00C004A4 /* PreferencesWindow.m in Sources */,
3B73010E158CDF7200D3AF26 /* AutoLyrics.m in Sources */, 3B73010E158CDF7200D3AF26 /* AutoLyrics.m in Sources */,
3B9A33611590BDE700B844EF /* iLyrics.m in Sources */,
3B5E8BA2159496DA0028363E /* Songtexte.m in Sources */,
3B5E8BA515949B380028363E /* LyricsHosterUtil.m in Sources */,
3B3A378715973040002085CE /* MP3Lyrics.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -311,20 +335,20 @@
name = Credits.rtf; name = Credits.rtf;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
3B20EF401584EA9A006C0CDF /* MainMenu.xib */ = { 3B3A377E15972079002085CE /* MainMenu.xib */ = {
isa = PBXVariantGroup; isa = PBXVariantGroup;
children = ( children = (
3B20EF411584EA9A006C0CDF /* en */, 3B3A377D15972079002085CE /* en */,
3BFDD3FA158D420400BF32B0 /* de */, 3B3A378015972080002085CE /* de */,
); );
name = MainMenu.xib; name = MainMenu.xib;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
3B20EF6315853345006C0CDF /* Localizable.strings */ = { 3B3A3783159727FE002085CE /* Localizable.strings */ = {
isa = PBXVariantGroup; isa = PBXVariantGroup;
children = ( children = (
3B20EF6215853345006C0CDF /* en */, 3B3A3782159727FE002085CE /* en */,
3BBD9B72158C7F8A00A5CD2C /* de */, 3B3A378415972803002085CE /* de */,
); );
name = Localizable.strings; name = Localizable.strings;
sourceTree = "<group>"; sourceTree = "<group>";

View File

@@ -7,13 +7,11 @@
// //
#import "AppDelegate.h" #import "AppDelegate.h"
#import "Magistrix.h"
@implementation AppDelegate { @implementation AppDelegate {
iTunesApplication *iTunes; iTunesApplication *iTunes;
NSArray *keyTokens; NSArray *keyTokens;
NSMutableArray *searchFormat; NSMutableArray *searchFormat;
Magistrix *magistrix;
} }
@synthesize window; @synthesize window;
@@ -24,8 +22,6 @@
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{ {
magistrix = [[Magistrix alloc] init];
[preferencesController addHoster:magistrix];
keyTokens = [NSArray arrayWithObjects:@"%name%", @"%artist%", @"%album%", nil]; keyTokens = [NSArray arrayWithObjects:@"%name%", @"%artist%", @"%album%", nil];
[window setExcludedFromWindowsMenu:YES]; [window setExcludedFromWindowsMenu:YES];
iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
@@ -45,6 +41,7 @@
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:[quitWhenAllWindowClosedCheckBox state] == NSOnState forKey:@"Quit when all windows are closed"]; [defaults setBool:[quitWhenAllWindowClosedCheckBox state] == NSOnState forKey:@"Quit when all windows are closed"];
[mainController saveToDefalts:defaults]; [mainController saveToDefalts:defaults];
[[iLyrics sharediLyrics] saveToDefaults:defaults];
[[AutoLyrics autoLyrics] saveToDefaults:defaults]; [[AutoLyrics autoLyrics] saveToDefaults:defaults];
[defaults synchronize]; [defaults synchronize];
return NSTerminateNow; return NSTerminateNow;

View File

@@ -9,7 +9,8 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <Growl/Growl.h> #import <Growl/Growl.h>
#import "iTunes.h" #import "iTunes.h"
#import "Magistrix.h" #import "LyricsHoster.h"
#import "iLyrics.h"
@interface AutoLyrics : NSObject @interface AutoLyrics : NSObject

View File

@@ -29,7 +29,7 @@ AutoLyrics *instace;
-(id)init { -(id)init {
enabled = NO; enabled = NO;
replaceOldLyrics = NO; replaceOldLyrics = NO;
[self setInterval:30]; [self setInterval:5];
return [super init]; return [super init];
} }
@@ -57,7 +57,7 @@ AutoLyrics *instace;
-(void)shouldSetLyrics: (NSTimer *) sender { -(void)shouldSetLyrics: (NSTimer *) sender {
if (enabled) { if (enabled) {
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; iTunesApplication *iTunes = [[iLyrics sharediLyrics] iTunes];
iTunesTrack *current = [iTunes currentTrack]; iTunesTrack *current = [iTunes currentTrack];
if ([current name] != nil) { if ([current name] != nil) {
if (replaceOldLyrics || [[current lyrics] length] == 0) { if (replaceOldLyrics || [[current lyrics] length] == 0) {
@@ -67,14 +67,14 @@ AutoLyrics *instace;
} }
} }
-(void)setLyrics { -(void)setLyrics {
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; iTunesApplication *iTunes = [[iLyrics sharediLyrics] iTunes];
iTunesTrack *track = [iTunes currentTrack]; iTunesTrack *track = [iTunes currentTrack];
Magistrix *magistrix = [[Magistrix alloc] init]; id<LyricsHoster> hoster = [[iLyrics sharediLyrics] preferredHoster];
[magistrix startNewSearchForQuery:[NSString stringWithFormat:@"%@ - %@", [track name], [track artist]]]; [hoster startNewSearchForQuery:[NSString stringWithFormat:@"%@ - %@", [track name], [track artist]]];
NSArray *results = [magistrix nextResults]; NSArray *results = [hoster nextResults];
if (results != nil && [results count] > 0) { if (results != nil && [results count] > 0) {
Lyrics *lyrics = [magistrix lyricsBySearchResult:[results objectAtIndex:0]]; Lyrics *lyrics = [hoster lyricsBySearchResult:[results objectAtIndex:0]];
[track setLyrics:[lyrics lyrics]]; [track setLyrics:[lyrics lyrics]];
[GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Growl.messages.lyricsSent.title", @"") description:[NSString stringWithFormat:NSLocalizedString(@"Growl.messages.lyricsSent.detail", @""), [track name]] notificationName:@"Lyrics sent to iTunes" iconData:nil priority:0 isSticky:NO clickContext:nil]; [GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Growl.messages.lyricsSent.title", @"") description:[NSString stringWithFormat:NSLocalizedString(@"Growl.messages.lyricsSent.detail", @""), [track name]] notificationName:@"Lyrics sent to iTunes" iconData:nil priority:0 isSticky:NO clickContext:nil];

View File

@@ -7,11 +7,13 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "SearchResult.h"
#import "Lyrics.h" #import "Lyrics.h"
#import "LyricsHosterUtil.h"
@protocol LyricsHoster <NSObject> @protocol LyricsHoster <NSObject>
@property BOOL enabled;
-(NSString*) name; -(NSString*) name;
-(NSDate*) hosterVersion; -(NSDate*) hosterVersion;
@@ -25,7 +27,12 @@
-(void) resetLoadedResults; -(void) resetLoadedResults;
-(BOOL) canShowInBrowser:(id)result;
-(void) showInBrowser:(id)result;
//Return nil for a "network error" //Return nil for a "network error"
-(Lyrics*) lyricsBySearchResult: (SearchResult *) result; //parameter should be a SearchResult instance
-(Lyrics*) lyricsBySearchResult: (id) result;
@end @end

View File

@@ -0,0 +1,14 @@
//
// LyricsHosterUtil.h
// iLyrics
//
// Created by Kim Wittenburg on 22.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString(LyricsHosterUtil)
-(NSString *) stringByRemovingHTMLTags;
-(NSString *) stringByFormattingForURL;
@end

View File

@@ -0,0 +1,23 @@
//
// LyricsHosterUtil.m
// iLyrics
//
// Created by Kim Wittenburg on 22.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "LyricsHosterUtil.h"
@implementation NSString(LyricsHosterUtil)
-(NSString*) stringByRemovingHTMLTags {
return [[[[[[[[[[[[[[[self
stringByReplacingOccurrencesOfString:@"\n" withString:@""] stringByReplacingOccurrencesOfString:@"<strong>" withString:@""] stringByReplacingOccurrencesOfString:@"</strong>" withString:@""] stringByReplacingOccurrencesOfString:@"<b>" withString:@""] stringByReplacingOccurrencesOfString:@"</b>" withString:@""] stringByReplacingOccurrencesOfString:@"<i>" withString:@""] stringByReplacingOccurrencesOfString:@"</i>" withString:@""] stringByReplacingOccurrencesOfString:@"<p>" withString:@""] stringByReplacingOccurrencesOfString:@"</p>" withString:@"\n\n"] stringByReplacingOccurrencesOfString:@"<br />" withString:@"\n"] stringByReplacingOccurrencesOfString:@"<br/>" withString:@"\n"] stringByReplacingOccurrencesOfString:@"&quot;" withString:@"\""] stringByReplacingOccurrencesOfString:@"&amp;" withString:@"&"] stringByReplacingOccurrencesOfString:@"&#039;" withString:@"'"] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
-(NSString *) stringByFormattingForURL {
//Can replace äöü with aou, no difference in results
NSCharacterSet *characters = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
return [[[self stringByReplacingOccurrencesOfString:@" " withString:@"+"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:characters];
}
@end

14
iLyrics/MP3Lyrics.h Normal file
View File

@@ -0,0 +1,14 @@
//
// Mp3Lyrics.h
// iLyrics
//
// Created by Kim Wittenburg on 24.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "LyricsHoster.h"
@interface MP3Lyrics : NSObject <LyricsHoster>
@end

68
iLyrics/MP3Lyrics.m Normal file
View File

@@ -0,0 +1,68 @@
//
// Mp3Lyrics.m
// iLyrics
//
// Created by Kim Wittenburg on 24.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "MP3Lyrics.h"
@implementation MP3Lyrics {
NSString *query;
NSString *firstPage;
int resultCount;
int loadedResults;
}
@synthesize enabled;
-(NSString *)name {
return @"MP3 Lyrics";
}
-(NSDate *)hosterVersion {
return [NSDate dateWithString:@"2012-06-24 15:00:00 +0100"];
}
-(void)startNewSearchForQuery:(NSString *)q {
query = [q stringByFormattingForURL];
int site = loadedResults;
NSString *searchPath = [NSString stringWithFormat:@"http://www.mp3lyrics.org/Search/%@%%7C%i", query, site];
NSURL *searchURL = [NSURL URLWithString:searchPath];
NSError *error;
firstPage = [NSString stringWithContentsOfURL:searchURL encoding:NSUTF8StringEncoding error:&error];
if (error || firstPage == nil) {
firstPage = nil;
return;
}
if ([firstPage rangeOfString:@"<div class=\"hit_list\">"].location == NSNotFound) {
resultCount = 0;
}
}
-(BOOL)hasMoreResults {
return loadedResults < resultCount;
}
-(NSArray *)nextResults {
}
-(BOOL)canShowInBrowser:(id)result {
}
-(void)showInBrowser:(id)result {
}
-(void)resetLoadedResults {
loadedResults = 0;
}
-(Lyrics *)lyricsBySearchResult:(id)result {
}
@end

View File

@@ -5,6 +5,7 @@
// Created by Kim Wittenburg on 14.06.12. // Created by Kim Wittenburg on 14.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved. // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
// //
// Representing http://www.magistrix.de
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "LyricsHoster.h" #import "LyricsHoster.h"

View File

@@ -6,9 +6,9 @@
// Copyright (c) 2012 __MyCompanyName__. All rights reserved. // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
// //
// //
//TODO: Use correct Date
#import "Magistrix.h" #import "Magistrix.h"
#import "SearchResult.h"
typedef enum { typedef enum {
LyricsPage, LyricsPage,
@@ -21,8 +21,11 @@ typedef enum {
NSString *query; NSString *query;
int loadedResults; int loadedResults;
int resultCount; int resultCount;
NSString *firstPage;
} }
@synthesize enabled;
-(NSString*) name { -(NSString*) name {
return @"Magistrix"; return @"Magistrix";
} }
@@ -34,6 +37,23 @@ typedef enum {
-(void) startNewSearchForQuery: (NSString*) q { -(void) startNewSearchForQuery: (NSString*) q {
[self resetLoadedResults]; [self resetLoadedResults];
query = q; query = q;
int 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 { -(BOOL) hasMoreResults {
@@ -42,38 +62,33 @@ typedef enum {
-(NSArray*) nextResults { -(NSArray*) nextResults {
int site = (loadedResults/10) + 1; int site = (loadedResults/10) + 1;
NSString *searchPath = [NSString stringWithFormat:@"http://www.magistrix.de/lyrics/search?q=%@&page=%i", [self stringByFormattingQuery:query], site]; NSString *searchPath = [NSString stringWithFormat:@"http://www.magistrix.de/lyrics/search?q=%@&page=%i", [query stringByFormattingForURL] , site];
NSURL *searchURL = [NSURL URLWithString:searchPath]; NSURL *searchURL = [NSURL URLWithString:searchPath];
NSError *error; NSString *page;
NSString *page = [NSString stringWithContentsOfURL:searchURL encoding:NSUTF8StringEncoding error:&error]; if (site == 1 && firstPage != nil) {
if (error) { page = firstPage;
//Network error or invalid query } else {
return nil; NSError *error;
page = [NSString stringWithContentsOfURL:searchURL encoding:NSUTF8StringEncoding error:&error];
if (error) {
//Network error or invalid query
return nil;
}
} }
PageType pType = [self typeOfPage:page]; PageType pType = [self typeOfPage:page];
if (pType == LyricsPage) { if (pType == LyricsPage) {
resultCount = 1;
loadedResults = 1; loadedResults = 1;
return [NSArray arrayWithObject:[self searchResultFromLyricsPage:page atURL:searchURL]]; return [NSArray arrayWithObject:[self searchResultFromLyricsPage:page atURL:searchURL]];
} else if (pType == ResultsPage) { } else if (pType == ResultsPage) {
[self shouldSetResultCountFromPage:page];
return [self searchResultsFromPage:page]; return [self searchResultsFromPage:page];
} else if (pType == NoResultsPage) { } else if (pType == NoResultsPage) {
resultCount = 0;
return [[NSArray alloc] init]; return [[NSArray alloc] init];
} else { } else {
NSRunAlertPanel(NSLocalizedString(@"Magistrix.messages.unknownPage.title", @""), NSLocalizedString(@"Magistrix.messages.unknownPage.detail", @""), NSLocalizedString(@"OK", @""), nil, nil); NSRunAlertPanel(NSLocalizedString(@"Magistrix.messages.unknownPage.title", @""), NSLocalizedString(@"Magistrix.messages.unknownPage.detail", @""), NSLocalizedString(@"OK", @""), nil, nil);
resultCount = 0;
return [[NSArray alloc] init]; return [[NSArray alloc] init];
} }
} }
-(NSString *) stringByFormattingQuery: (NSString *) q {
//Can replace äöü with aou, no difference in results
NSCharacterSet *characters = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
return [[[q stringByReplacingOccurrencesOfString:@" " withString:@"+"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:characters];
}
-(PageType) typeOfPage: (NSString *) page { -(PageType) typeOfPage: (NSString *) page {
if ([page rangeOfString:@"<title>Songtext-Suche</title>"].location != NSNotFound) { if ([page rangeOfString:@"<title>Songtext-Suche</title>"].location != NSNotFound) {
if ([page rangeOfString:@"<div class='empty_collection'>"].location != NSNotFound) { if ([page rangeOfString:@"<div class='empty_collection'>"].location != NSNotFound) {
@@ -96,12 +111,12 @@ typedef enum {
int artistEnd = artistEndTag.location; int artistEnd = artistEndTag.location;
int songNameStart = NSMaxRange(artistEndTag); int songNameStart = NSMaxRange(artistEndTag);
int songNameEnd = headingEnd; int songNameEnd = headingEnd;
NSString *artist = [self stringByRemovingHTMLTags:[page substringWithRange:NSMakeRange(artistStart, artistEnd-artistStart)]]; NSString *artist = [[page substringWithRange:NSMakeRange(artistStart, artistEnd-artistStart)] stringByRemovingHTMLTags];
NSString *songName = [page substringWithRange:NSMakeRange(songNameStart, songNameEnd-songNameStart)]; NSString *songName = [page substringWithRange:NSMakeRange(songNameStart, songNameEnd-songNameStart)];
//Remove the " Lyric" and the " &ndash; " from the Song name //Remove the " Lyric" and the " &ndash; " from the Song name
songName = [self stringByRemovingHTMLTags:[[songName substringToIndex:[songName length]-[@" Lyric" length]] substringFromIndex:[@" &ndash; " length]]]; songName = [[[songName substringToIndex:[songName length]-[@" Lyric" length]] substringFromIndex:[@" &ndash; " length]] stringByRemovingHTMLTags];
NSString *preview = [self lyricsFromPage:page]; NSString *preview = [self lyricsFromPage:page];
return [[SearchResult alloc]initWithName:songName fromArtist:artist preview:preview link:url]; return [[SearchResult alloc]initWithName:songName fromArtist:artist preview:preview link:url loadedByHoster:self];
} }
-(NSArray*) searchResultsFromPage: (NSString *) page { -(NSArray*) searchResultsFromPage: (NSString *) page {
@@ -139,8 +154,7 @@ typedef enum {
NSRange artistStartRange = [tag rangeOfString:@">"]; NSRange artistStartRange = [tag rangeOfString:@">"];
int artistEndIndex = [tag rangeOfString:@"<" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:artistStartRange]].location; int artistEndIndex = [tag rangeOfString:@"<" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:artistStartRange]].location;
int artistStartIndex = NSMaxRange(artistStartRange); int artistStartIndex = NSMaxRange(artistStartRange);
NSString *artist = [self stringByRemovingHTMLTags:[tag substringWithRange:NSMakeRange(artistStartIndex, artistEndIndex-artistStartIndex)]]; NSString *artist = [[tag substringWithRange:NSMakeRange(artistStartIndex, artistEndIndex-artistStartIndex)] stringByRemovingHTMLTags];
NSRange restRange = [self restRangeFromString:tag subtractingRange:NSMakeRange(artistEndIndex, [@"</a>" length])]; NSRange restRange = [self restRangeFromString:tag subtractingRange:NSMakeRange(artistEndIndex, [@"</a>" length])];
NSRange songNameTagStartRange = [tag rangeOfString:@"<a href=\"" options:NSCaseInsensitiveSearch range:restRange]; NSRange songNameTagStartRange = [tag rangeOfString:@"<a href=\"" options:NSCaseInsensitiveSearch range:restRange];
int linkStart = NSMaxRange(songNameTagStartRange); int linkStart = NSMaxRange(songNameTagStartRange);
@@ -148,12 +162,12 @@ typedef enum {
NSURL *link = [self urlFromHref:[tag substringWithRange:NSMakeRange(linkStart, linkEndRage.location-linkStart)]]; NSURL *link = [self urlFromHref:[tag substringWithRange:NSMakeRange(linkStart, linkEndRage.location-linkStart)]];
int songNameStart = NSMaxRange([tag rangeOfString:@">" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:songNameTagStartRange]]); int songNameStart = NSMaxRange([tag rangeOfString:@">" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:songNameTagStartRange]]);
int songNameEnd = [tag rangeOfString:@"</a>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:songNameTagStartRange]].location; int songNameEnd = [tag rangeOfString:@"</a>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:songNameTagStartRange]].location;
NSString *songName = [self stringByRemovingHTMLTags:[tag substringWithRange:NSMakeRange(songNameStart, songNameEnd-songNameStart)]]; NSString *songName = [[tag substringWithRange:NSMakeRange(songNameStart, songNameEnd-songNameStart)] stringByRemovingHTMLTags];
int previewStart = songNameEnd + [@"</a>" length] + [@"\n<p>" length]; int previewStart = songNameEnd + [@"</a>" length] + [@"\n<p>" length];
NSRange previewRestRange = NSMakeRange(previewStart, [tag length]-previewStart); NSRange previewRestRange = NSMakeRange(previewStart, [tag length]-previewStart);
int previewEnd = [tag rangeOfString:@"</p>" options:NSCaseInsensitiveSearch range:previewRestRange].location; int previewEnd = [tag rangeOfString:@"</p>" options:NSCaseInsensitiveSearch range:previewRestRange].location;
NSString *preview = [self stringByRemovingHTMLTags:[tag substringWithRange:NSMakeRange(previewStart, previewEnd-previewStart)]]; NSString *preview = [[tag substringWithRange:NSMakeRange(previewStart, previewEnd-previewStart)] stringByRemovingHTMLTags];
return [[SearchResult alloc] initWithName:songName fromArtist:artist preview:preview link:link]; return [[SearchResult alloc] initWithName:songName fromArtist:artist preview:preview link:link loadedByHoster:self];
} }
-(NSURL*) urlFromHref: (NSString *) link { -(NSURL*) urlFromHref: (NSString *) link {
@@ -164,9 +178,6 @@ typedef enum {
} }
} }
-(NSString*) stringByRemovingHTMLTags: (NSString *)string {
return [[[[[[[[[[[string stringByReplacingOccurrencesOfString:@"<strong>" withString:@""] stringByReplacingOccurrencesOfString:@"</strong>" withString:@""] stringByReplacingOccurrencesOfString:@"<b>" withString:@""] stringByReplacingOccurrencesOfString:@"</b>" withString:@""] stringByReplacingOccurrencesOfString:@"<i>" withString:@""] stringByReplacingOccurrencesOfString:@"</i>" withString:@""] stringByReplacingOccurrencesOfString:@"<p>" withString:@""] stringByReplacingOccurrencesOfString:@"</p>" withString:@""] stringByReplacingOccurrencesOfString:@"<br />" withString:@""] stringByReplacingOccurrencesOfString:@"&quot;" withString:@"\""] stringByReplacingOccurrencesOfString:@"&amp;" withString:@"&"];
}
-(NSRange) restRangeFromString: (NSString *) page subtractingRange: (NSRange) aRange { -(NSRange) restRangeFromString: (NSString *) page subtractingRange: (NSRange) aRange {
int loc = NSMaxRange(aRange); int loc = NSMaxRange(aRange);
@@ -174,7 +185,7 @@ typedef enum {
} }
-(void) shouldSetResultCountFromPage: (NSString *) page { -(void) shouldSetResultCountFromPage: (NSString *) page {
if (resultCount == 0) { if (resultCount <= 0) {
//Nothing loaded before //Nothing loaded before
NSRange resultsLabelStartRange = [page rangeOfString:@"<p>Ergebnisse 1 bis "]; NSRange resultsLabelStartRange = [page rangeOfString:@"<p>Ergebnisse 1 bis "];
int resultsLabelEnd = [page rangeOfString:@"</p>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:page subtractingRange:resultsLabelStartRange]].location; int resultsLabelEnd = [page rangeOfString:@"</p>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:page subtractingRange:resultsLabelStartRange]].location;
@@ -196,6 +207,7 @@ typedef enum {
-(void) resetLoadedResults { -(void) resetLoadedResults {
loadedResults = 0; loadedResults = 0;
firstPage = nil;
} }
-(Lyrics*) lyricsBySearchResult: (SearchResult *) result { -(Lyrics*) lyricsBySearchResult: (SearchResult *) result {
@@ -208,13 +220,20 @@ typedef enum {
return [[Lyrics alloc] initWithName:[result name] byArtist:[result artist] withLyrics:lyrics]; return [[Lyrics alloc] initWithName:[result name] byArtist:[result artist] withLyrics:lyrics];
} }
-(NSString *) lyricsFromPage: (NSString *)page { -(NSString *) lyricsFromPage: (NSString *)page {
int lyricsStart = NSMaxRange([page rangeOfString:@"<div id='songtext'>"]) + [@"\n" length]; int lyricsStart = NSMaxRange([page rangeOfString:@"<div id='songtext'>"]) + [@"\n" length];
NSRange restRange = NSMakeRange(lyricsStart, [page length]-lyricsStart); NSRange restRange = NSMakeRange(lyricsStart, [page length]-lyricsStart);
int lyricsEnd = [page rangeOfString:@"<div class='clear'></div>" options:NSCaseInsensitiveSearch range:restRange].location; int lyricsEnd = [page rangeOfString:@"<div class='clear'></div>" options:NSCaseInsensitiveSearch range:restRange].location;
NSString *lyrics = [self stringByRemovingHTMLTags:[page substringWithRange:NSMakeRange(lyricsStart, lyricsEnd-lyricsStart)]]; NSString *lyrics = [[page substringWithRange:NSMakeRange(lyricsStart, lyricsEnd-lyricsStart)] stringByRemovingHTMLTags];
return lyrics; return lyrics;
} }
-(BOOL)canShowInBrowser:(id)result {
return YES;
}
-(void)showInBrowser:(id)result {
[[NSWorkspace sharedWorkspace] openURL:[result link]];
}
@end @end

View File

@@ -6,37 +6,24 @@
// Copyright (c) 2012 __MyCompanyName__. All rights reserved. // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
// //
#import <Cocoa/Cocoa.h> #import "iLyrics.h"
#import <Scripting/Scripting.h>
#import <ScriptingBridge/ScriptingBridge.h>
#import <AppKitScripting/AppKitScripting.h>
#import "iTunes.h"
#import "Spotify.h"
#import "Magistrix.h"
#import "SearchResult.h"
#import "Lyrics.h"
#import <Growl/Growl.h>
@interface MainController : NSObject <NSWindowDelegate, NSSplitViewDelegate, NSOutlineViewDataSource, NSOutlineViewDelegate> @interface MainController : NSObject <NSWindowDelegate, NSSplitViewDelegate, NSOutlineViewDataSource, NSOutlineViewDelegate>
@property (weak) IBOutlet NSMenuItem *iLyricsMenuItem; @property (weak) IBOutlet NSMenuItem *iLyricsMenuItem;
@property (unsafe_unretained) IBOutlet NSWindow *window; @property (unsafe_unretained) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSSearchField *searchField; @property (weak) IBOutlet NSSearchField *searchField;
@property (weak) IBOutlet NSOutlineView *resultsOutline; @property (weak) IBOutlet NSOutlineView *resultsOutline;
@property (weak) IBOutlet NSButton *loadMoreResultsButton;
@property (weak) IBOutlet NSButton *showPreviewCheckBox; @property (weak) IBOutlet NSButton *showPreviewCheckBox;
@property (weak) IBOutlet NSPopover *previewPopover; @property (weak) IBOutlet NSPopover *previewPopover;
@property (unsafe_unretained) IBOutlet NSTextView *previewTextArea; @property (unsafe_unretained) IBOutlet NSTextView *previewTextArea;
@property (weak) IBOutlet NSTextField *songLabel; @property (weak) IBOutlet NSTextField *songLabel;
@property (weak) IBOutlet NSTextField *artistLabel; @property (weak) IBOutlet NSTextField *artistLabel;
@property (weak) IBOutlet NSButton *sendToiTunesButton;
@property (weak) IBOutlet NSButton *downloadLyricsButton;
@property (unsafe_unretained) IBOutlet NSTextView *lyricsArea; @property (unsafe_unretained) IBOutlet NSTextView *lyricsArea;
@property (readonly) Lyrics *currentLyrics; @property (readonly) Lyrics *currentLyrics;
- (IBAction)getCurrentiTunesSong:(id)sender; - (IBAction)getCurrentiTunesSong:(id)sender;
- (IBAction)getCurrentSpotifySong:(id)sender; - (IBAction)getCurrentSpotifySong:(id)sender;
- (IBAction)startNewSearch:(id)sender; - (IBAction)startNewSearch:(id)sender;
- (IBAction)loadNextResults:(id)sender;
- (IBAction)resetLoadedResults:(id)sender; - (IBAction)resetLoadedResults:(id)sender;
- (IBAction)lyricsSelectionChanged:(NSOutlineView *)sender; - (IBAction)lyricsSelectionChanged:(NSOutlineView *)sender;
- (IBAction)sendLyricsToiTunes:(id)sender; - (IBAction)sendLyricsToiTunes:(id)sender;

View File

@@ -10,46 +10,46 @@
@implementation MainController { @implementation MainController {
NSMutableArray *loadedResults; NSMutableArray *loadedResults;
id<LyricsHoster> currentHoster;
BOOL lyricsSelected; BOOL lyricsSelected;
NSInteger selectedSavePanelButton; NSInteger selectedSavePanelButton;
NSURL *saveFile; NSURL *saveFile;
iTunesApplication *iTunes;
SpotifyApplication *spotify;
Lyrics *currentLyrics; Lyrics *currentLyrics;
int selectedRow; int selectedRow;
iLyrics *ilyrics;
} }
@synthesize iLyricsMenuItem; @synthesize iLyricsMenuItem;
@synthesize window; @synthesize window;
@synthesize searchField; @synthesize searchField;
@synthesize resultsOutline; @synthesize resultsOutline;
@synthesize loadMoreResultsButton;
@synthesize showPreviewCheckBox; @synthesize showPreviewCheckBox;
@synthesize previewPopover; @synthesize previewPopover;
@synthesize previewTextArea; @synthesize previewTextArea;
@synthesize songLabel; @synthesize songLabel;
@synthesize artistLabel; @synthesize artistLabel;
@synthesize sendToiTunesButton;
@synthesize downloadLyricsButton;
@synthesize lyricsArea; @synthesize lyricsArea;
-(id)init { -(id)init {
iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
spotify = [SBApplication applicationWithBundleIdentifier:@"com.spotify.client"];
loadedResults = [[NSMutableArray alloc] init]; loadedResults = [[NSMutableArray alloc] init];
currentHoster = [[Magistrix alloc] init]; ilyrics = [iLyrics sharediLyrics];
return [super init]; return [super init];
} }
-(void)awakeFromNib {
[self lyricsSelectionChanged:resultsOutline];
}
#pragma mark - #pragma mark -
#pragma mark Outline view Data Source and Delegate #pragma mark Outline view Data Source and Delegate
-(NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item { -(NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
return item == nil ? [loadedResults count] : 0; return item == nil ? [loadedResults count] + 1 : 1;
} }
-(id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item { -(id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
if (index == [outlineView numberOfRows]-1) {
return NSLocalizedString(@"iLyrics.text.loadMoreResults", @"");
}
return [loadedResults objectAtIndex:index]; return [loadedResults objectAtIndex:index];
} }
@@ -58,18 +58,41 @@
} }
-(id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { -(id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
if ([item isKindOfClass:[NSString class]]) {
return item;
}
if ([[tableColumn identifier] isEqualToString:@"song"]) { if ([[tableColumn identifier] isEqualToString:@"song"]) {
return [item name]; return [item name];
} else { } else if ([[tableColumn identifier] isEqualToString:@"artist"]) {
return [item artist]; return [item artist];
} else {
return [[item loadedByHoster] name];
}
}
-(NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
if ([item isKindOfClass:[NSString class]]) {
NSPopUpButtonCell *cell = [[NSPopUpButtonCell alloc] init];
NSMenu *menu = [[NSMenu alloc] init];
NSMenuItem *titleItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"iLyrics.text.loadNextResultsFrom", @"") action:@selector(nothingResponsible:soDisable:titleItem:) keyEquivalent:@""];
[menu addItem:titleItem];
for (id<LyricsHoster> hoster in [ilyrics lyricsHosters]) {
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@" %@", [hoster name]] action:@selector(loadNextResults:) keyEquivalent:@""];
[menuItem setTarget:self];
[menu addItem:menuItem];
}
[cell setMenu:menu];
[cell setControlSize:NSMiniControlSize];
return cell;
} }
return nil; return nil;
} }
-(NSString *)outlineView:(NSOutlineView *)outlineView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tableColumn item:(id)item mouseLocation:(NSPoint)mouseLocation { -(NSString *)outlineView:(NSOutlineView *)outlineView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tableColumn item:(id)item mouseLocation:(NSPoint)mouseLocation {
//item is an instance of SearchResult //item is an instance of SearchResult
[self shouldShowPreviewForCellRect:*rect searchResult:item]; if ([item isKindOfClass:[SearchResult class]]) {
[self shouldShowPreviewForCellRect:*rect searchResult:item];
}
return nil; return nil;
} }
@@ -77,11 +100,7 @@
#pragma mark Responding to Lyrics Search #pragma mark Responding to Lyrics Search
- (IBAction)getCurrentiTunesSong:(id)sender { - (IBAction)getCurrentiTunesSong:(id)sender {
iTunesTrack *track = [iTunes currentTrack]; iTunesTrack *track = [[ilyrics iTunes] currentTrack];
if (track == nil) {
NSBeginAlertSheet(NSLocalizedString(@"iTunes.messages.iTunesIdle.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"iTunes.messages.iTunesIdle.detail", @""));
return;
}
NSString *name = [track name]; NSString *name = [track name];
NSString *artist = [track artist]; NSString *artist = [track artist];
if (name == nil) { if (name == nil) {
@@ -94,7 +113,7 @@
} }
- (IBAction)getCurrentSpotifySong:(id)sender { - (IBAction)getCurrentSpotifySong:(id)sender {
SpotifyTrack *track = [spotify currentTrack]; SpotifyTrack *track = [[ilyrics spotify] currentTrack];
NSString *name = [track name]; NSString *name = [track name];
NSString *artist = [track artist]; NSString *artist = [track artist];
if (name == nil) { if (name == nil) {
@@ -109,36 +128,97 @@
- (IBAction)startNewSearch:(id)sender { - (IBAction)startNewSearch:(id)sender {
[self resetLoadedResults:sender]; [self resetLoadedResults:sender];
if ([[searchField stringValue] length] > 0) { if ([[searchField stringValue] length] > 0) {
[currentHoster startNewSearchForQuery:[searchField stringValue]]; for (id<LyricsHoster> hoster in [ilyrics lyricsHosters]) {
[self loadNextResults:sender]; [hoster startNewSearchForQuery:[searchField stringValue]];
}
//Load first results
BOOL networkError = YES;
BOOL resultsFound = NO;
for (id<LyricsHoster> hoster in [ilyrics lyricsHosters]) {
NSArray *results = [hoster nextResults];
if (results) {
networkError = NO;
if ([results count] > 0) {
resultsFound = YES;
[loadedResults addObjectsFromArray:results];
[resultsOutline reloadData];
break;
}
} else {
networkError = networkError && YES;
}
}
if (networkError) {
[self presentNetworkErrorWithHoster:nil];
} else if (!resultsFound) {
[self presentNoResultsErrorWithHoster:nil];
}
} }
[self lyricsSelectionChanged:resultsOutline];
} }
- (IBAction)loadNextResults:(id)sender { - (void)loadNextResults:(id)sender{
NSArray *nextResults = [currentHoster nextResults]; [self loadNextResultsFromHoster:[ilyrics hosterWithName:[sender title]]];
[loadMoreResultsButton setEnabled:[currentHoster hasMoreResults]]; }
- (void) loadNextResultsFromHoster: (id<LyricsHoster>) hoster {
if (hoster == nil) {
return;
}
NSArray *nextResults = [hoster nextResults];
if (nextResults == nil) { if (nextResults == nil) {
NSRunCriticalAlertPanel(NSLocalizedString(@"Hoster.messages.networkOrQueryError.title", @""), NSLocalizedString(@"Hoster.messages.networkOrQueryError.detail", @""), NSLocalizedString(@"OK", @""), nil, nil); [self presentNetworkErrorWithHoster:hoster];
return; return;
} }
if ([nextResults count] == 0) { if ([nextResults count] == 0) {
NSRunAlertPanel(NSLocalizedString(@"Hoster.messages.noResults.title", @""), NSLocalizedString(@"Hoster.messages.noResults.detail", @""), NSLocalizedString(@"OK", @""), nil, nil); [self presentNoResultsErrorWithHoster:hoster];
return; return;
} }
[loadedResults addObjectsFromArray:nextResults]; [loadedResults addObjectsFromArray:nextResults];
[resultsOutline reloadData]; [resultsOutline reloadData];
} }
-(void)presentNetworkErrorWithHoster: (id<LyricsHoster>)hoster {
NSString *title;
NSString *detail;
if (hoster) {
title = [NSLocalizedString(@"Hoster.messages.networkOrQueryError.title", @"") stringByReplacingOccurrencesOfString:@"%hoster%" withString:[hoster name]];
detail = [NSLocalizedString(@"Hoster.messages.networkOrQueryError.detail", @"") stringByReplacingOccurrencesOfString:@"%hoster%" withString:[hoster name]];
} else {
title = NSLocalizedString(@"iLyrics.messages.networkOrQueryError.title", @"");
detail = NSLocalizedString(@"iLyrics.messages.networkOrQueryError.detail", @"");
}
NSRunCriticalAlertPanel(title, detail, NSLocalizedString(@"OK", @""), nil, nil);
}
-(void)presentNoResultsErrorWithHoster: (id<LyricsHoster>)hoster {
NSString *title;
NSString *detail;
if (hoster) {
title = [NSLocalizedString(@"Hoster.messages.noResults.title", @"") stringByReplacingOccurrencesOfString:@"%hoster%" withString:[hoster name]];
detail = [NSLocalizedString(@"Hoster.messages.noResults.detail", @"") stringByReplacingOccurrencesOfString:@"%hoster%" withString:[hoster name]];
} else {
title = NSLocalizedString(@"iLyrics.messages.noResults.title", @"") ;
detail = NSLocalizedString(@"iLyrics.messages.noResults.detail", @"");
}
NSRunAlertPanel(title, detail, NSLocalizedString(@"OK", @""), nil, nil);
}
-(IBAction)resetLoadedResults:(id)sender { -(IBAction)resetLoadedResults:(id)sender {
[currentHoster resetLoadedResults]; for (id<LyricsHoster> hoster in [ilyrics lyricsHosters]) {
[hoster resetLoadedResults];
}
[loadedResults removeAllObjects]; [loadedResults removeAllObjects];
[resultsOutline reloadData]; [resultsOutline reloadData];
[loadMoreResultsButton setEnabled:[currentHoster hasMoreResults]];
[self lyricsSelectionChanged:resultsOutline]; [self lyricsSelectionChanged:resultsOutline];
} }
- (IBAction)lyricsSelectionChanged:(NSOutlineView *)sender { - (IBAction)lyricsSelectionChanged:(NSOutlineView *)sender {
int index = [sender selectedRow]; int index = [sender selectedRow];
if (index == [sender numberOfRows]-1) {
index = -1;
}
if (index < 0) { if (index < 0) {
lyricsSelected = NO; lyricsSelected = NO;
currentLyrics = nil; currentLyrics = nil;
@@ -151,10 +231,12 @@
if (selectedRow != index) { if (selectedRow != index) {
lyricsSelected = YES; lyricsSelected = YES;
SearchResult *result = [loadedResults objectAtIndex:index]; SearchResult *result = [loadedResults objectAtIndex:index];
Lyrics *lyrics = [currentHoster lyricsBySearchResult:result]; Lyrics *lyrics = [[result loadedByHoster] lyricsBySearchResult:result];
currentLyrics = lyrics; currentLyrics = lyrics;
if (lyrics == nil) { if (lyrics == nil) {
NSRunCriticalAlertPanel(NSLocalizedString(@"Hoster.messages.networkError.title", @""), NSLocalizedString(@"Hoster.messages.networkError.detail", @""), NSLocalizedString(@"OK", @""), nil, nil); NSString *title = [NSLocalizedString(@"Hoster.messages.networkOrQueryError.title", @"") stringByReplacingOccurrencesOfString:@"%hoster%" withString:[[result loadedByHoster] name]];
NSString *detail = [NSLocalizedString(@"Hoster.messages.networkOrQueryError.detail", @"") stringByReplacingOccurrencesOfString:@"%hoster%" withString:[[result loadedByHoster] name]];
NSRunCriticalAlertPanel(title, detail, NSLocalizedString(@"OK", @""), nil, nil);
NSString *noNetwork = NSLocalizedString(@"Hoster.text.noNetwork", @""); NSString *noNetwork = NSLocalizedString(@"Hoster.text.noNetwork", @"");
[songLabel setStringValue:noNetwork]; [songLabel setStringValue:noNetwork];
[artistLabel setStringValue:noNetwork]; [artistLabel setStringValue:noNetwork];
@@ -176,14 +258,14 @@
NSString *lyrics = [result preview]; NSString *lyrics = [result preview];
if (lyrics) { if (lyrics) {
rect.size.width = [resultsOutline frame].size.width; rect.size.width = [resultsOutline frame].size.width;
[previewTextArea setString:lyrics]; [previewTextArea setString:lyrics==nil?NSLocalizedString(@"Hoster.text.noPreviewAvailable", @""):lyrics];
[previewPopover showRelativeToRect:rect ofView:resultsOutline preferredEdge:NSMaxXEdge]; [previewPopover showRelativeToRect:rect ofView:resultsOutline preferredEdge:NSMaxXEdge];
} }
} }
} }
- (IBAction)sendLyricsToiTunes:(id)sender { - (IBAction)sendLyricsToiTunes:(id)sender {
iTunesTrack *track = [iTunes currentTrack]; iTunesTrack *track = [[ilyrics iTunes] currentTrack];
NSString *name = [track name]; NSString *name = [track name];
if (name == nil) { if (name == nil) {
NSBeginAlertSheet(NSLocalizedString(@"iTunes.messages.noTrackPlaying.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"iTunes.messages.noTrackPlaying.detail", @"")); NSBeginAlertSheet(NSLocalizedString(@"iTunes.messages.noTrackPlaying.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"iTunes.messages.noTrackPlaying.detail", @""));
@@ -199,7 +281,7 @@
- (void)replaceLyricsSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - (void)replaceLyricsSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
if (returnCode == NSAlertDefaultReturn) { if (returnCode == NSAlertDefaultReturn) {
iTunesTrack *track = [iTunes currentTrack]; iTunesTrack *track = [[ilyrics iTunes] currentTrack];
[track setLyrics:[lyricsArea string]]; [track setLyrics:[lyricsArea string]];
[GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Growl.messages.lyricsSent.title", @"") description:[NSString stringWithFormat:NSLocalizedString(@"Growl.messages.lyricsSent.detail", @""), [track name]] notificationName:@"Lyrics sent to iTunes" iconData:nil priority:0 isSticky:NO clickContext:nil]; [GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Growl.messages.lyricsSent.title", @"") description:[NSString stringWithFormat:NSLocalizedString(@"Growl.messages.lyricsSent.detail", @""), [track name]] notificationName:@"Lyrics sent to iTunes" iconData:nil priority:0 isSticky:NO clickContext:nil];
} }
@@ -225,8 +307,8 @@
if (row < 0) { if (row < 0) {
row = [resultsOutline selectedRow]; row = [resultsOutline selectedRow];
} }
NSURL *link = [[loadedResults objectAtIndex:row] link]; SearchResult *result = [loadedResults objectAtIndex:row];
[[NSWorkspace sharedWorkspace] openURL:link]; [[result loadedByHoster] showInBrowser:result];
} }
-(void) savePanelDidClose: (NSNotification *) notification{ -(void) savePanelDidClose: (NSNotification *) notification{
@@ -234,7 +316,7 @@
if (selectedSavePanelButton == NSOKButton) { if (selectedSavePanelButton == NSOKButton) {
BOOL success = [[[lyricsArea string] dataUsingEncoding:NSUTF8StringEncoding] writeToURL:saveFile atomically:NO]; BOOL success = [[[lyricsArea string] dataUsingEncoding:NSUTF8StringEncoding] writeToURL:saveFile atomically:NO];
if (!success) { if (!success) {
NSBeginAlertSheet(NSLocalizedString(@"messages.error.saveLyrics.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"messages.error.saveLyrics.detail", @"")); NSBeginAlertSheet(NSLocalizedString(@"iLyrics.messages.error.saveLyrics.title", @""), NSLocalizedString(@"OK", @""), nil, nil, window, nil, nil, nil, nil, NSLocalizedString(@"iLyrics.messages.error.saveLyrics.detail", @""));
} else { } else {
[GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Growl.messages.lyricsSaved.title", @"") description:[NSString stringWithFormat:NSLocalizedString(@"Growl.messages.lyricsSaved.detail", @""), [saveFile path]] notificationName:@"Lyrics saved to File" iconData:nil priority:0 isSticky:NO clickContext:nil]; [GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Growl.messages.lyricsSaved.title", @"") description:[NSString stringWithFormat:NSLocalizedString(@"Growl.messages.lyricsSaved.detail", @""), [saveFile path]] notificationName:@"Lyrics saved to File" iconData:nil priority:0 isSticky:NO clickContext:nil];
} }
@@ -270,6 +352,11 @@
#pragma mark window delegate #pragma mark window delegate
-(BOOL)validateMenuItem:(NSMenuItem *)menuItem { -(BOOL)validateMenuItem:(NSMenuItem *)menuItem {
SEL action = [menuItem action];
if (action == @selector(loadNextResults:)) {
BOOL hasMore = [[ilyrics hosterWithName:[menuItem title]] hasMoreResults];
return hasMore;
}
return [self validateUserInterfaceItem:menuItem]; return [self validateUserInterfaceItem:menuItem];
} }
@@ -280,28 +367,28 @@
-(BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { -(BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
SEL action = [item action]; SEL action = [item action];
if (action == @selector(downloadLyrics:)) { if (action == @selector(downloadLyrics:)) {
[downloadLyricsButton setEnabled:lyricsSelected];
return lyricsSelected; return lyricsSelected;
} }
if (action == @selector(sendLyricsToiTunes:)) { if (action == @selector(sendLyricsToiTunes:)) {
BOOL enabled = lyricsSelected && [iTunes isRunning]; BOOL enabled = lyricsSelected && [[ilyrics iTunes] isRunning];
[sendToiTunesButton setEnabled:enabled];
return enabled; return enabled;
} }
if (action == @selector(getCurrentiTunesSong:)) { if (action == @selector(getCurrentiTunesSong:)) {
return [iTunes isRunning]; return [[ilyrics iTunes] isRunning];
} }
if (action == @selector(getCurrentSpotifySong:)) { if (action == @selector(getCurrentSpotifySong:)) {
return [spotify isRunning]; return [[ilyrics spotify] isRunning];
} }
if (action == @selector(showPreview:)) { if (action == @selector(showPreview:)) {
return [resultsOutline clickedRow] >= 0; return [resultsOutline clickedRow] >= 0;
} }
if (action == @selector(showLyricsInBrowser:)) { if (action == @selector(showLyricsInBrowser:)) {
if ([resultsOutline clickedRow] >= 0) { if ([resultsOutline clickedRow] >= 0) {
return YES; SearchResult *result = [loadedResults objectAtIndex:[resultsOutline clickedRow]];
} else if ([resultsOutline selectedRow] >= 0) { return [[result loadedByHoster] canShowInBrowser:result];;
return YES; } else if ([resultsOutline selectedRow] >= 0) {
SearchResult *result = [loadedResults objectAtIndex:[resultsOutline selectedRow]];
return [[result loadedByHoster] canShowInBrowser:result];;
} else { } else {
return NO; return NO;
} }

View File

@@ -11,20 +11,16 @@
#import "PreferencesWindow.h" #import "PreferencesWindow.h"
#import "AutoLyrics.h" #import "AutoLyrics.h"
@interface PreferencesController : NSObject <NSWindowDelegate, NSTableViewDataSource> @interface PreferencesController : NSObject <NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate>
@property (unsafe_unretained) IBOutlet PreferencesWindow *preferencesWindow; @property (unsafe_unretained) IBOutlet PreferencesWindow *preferencesWindow;
@property (weak) IBOutlet NSToolbarItem *generalButton; @property (weak) IBOutlet NSToolbarItem *generalButton;
@property (weak) IBOutlet NSTableView *hosterTable; @property (weak) IBOutlet NSTableView *hosterTable;
@property NSArray *hosters;
@property (weak) IBOutlet NSView *generalView; @property (weak) IBOutlet NSView *generalView;
@property (weak) IBOutlet NSView *autoLyricsView; @property (weak) IBOutlet NSView *autoLyricsView;
@property (weak) IBOutlet NSButton *toggleAutoLyricsButton; @property (weak) IBOutlet NSButton *toggleAutoLyricsButton;
@property (weak) IBOutlet NSButton *replaceOldCheckBox; @property (weak) IBOutlet NSButton *replaceOldCheckBox;
-(void) addHoster: (id<LyricsHoster>) hoster;
-(void) removeHoster: (id<LyricsHoster>) hoster;
- (IBAction)showGeneralPreferences:(id)sender; - (IBAction)showGeneralPreferences:(id)sender;
- (IBAction)showAutoLyricsPreferences:(id)sender; - (IBAction)showAutoLyricsPreferences:(id)sender;

View File

@@ -6,13 +6,14 @@
// Copyright (c) 2012 __MyCompanyName__. All rights reserved. // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
// //
//TODO: Implement Auto-Lyricds Interval //TODO: Implement Auto-Lyricds Interval
//TODO: Set the title of the window when the toolbar button selection changed //TODO:
#import "PreferencesController.h" #import "PreferencesController.h"
#import "iLyrics.h"
@implementation PreferencesController { @implementation PreferencesController {
NSMutableArray *hosters;
AutoLyrics *autoLyrics; AutoLyrics *autoLyrics;
iLyrics *ilyrics;
} }
@synthesize generalView; @synthesize generalView;
@synthesize autoLyricsView; @synthesize autoLyricsView;
@@ -23,14 +24,15 @@
@synthesize hosterTable; @synthesize hosterTable;
-(id)init { -(id)init {
ilyrics = [iLyrics sharediLyrics];
autoLyrics = [AutoLyrics autoLyrics]; autoLyrics = [AutoLyrics autoLyrics];
hosters = [[NSMutableArray alloc] init];
return [super init]; return [super init];
} }
#pragma mark - #pragma mark -
#pragma mark Window Delegate Methods #pragma mark Window Delegate Methods
#define HosterDataType @"HosterDataType"
-(void)awakeFromNib { -(void)awakeFromNib {
if ([autoLyrics enabled]) { if ([autoLyrics enabled]) {
[self enableAutoLyrics:toggleAutoLyricsButton]; [self enableAutoLyrics:toggleAutoLyricsButton];
@@ -44,37 +46,19 @@
} }
[[preferencesWindow toolbar] setSelectedItemIdentifier:@"general"]; [[preferencesWindow toolbar] setSelectedItemIdentifier:@"general"];
[self showGeneralPreferences:nil]; [self showGeneralPreferences:nil];
[hosterTable registerForDraggedTypes:[NSArray arrayWithObject:HosterDataType]];
} }
#pragma mark - #pragma mark -
#pragma mark Properties
-(NSArray *)hosters {
return hosters;
}
-(void)setHosters:(NSArray *)hstrs {
hosters = [NSMutableArray arrayWithArray:hstrs];
[hosterTable reloadData];
}
#pragma mark Modifying hosters #pragma mark Modifying hosters
-(void)addHoster:(id<LyricsHoster>)hoster {
[hosters addObject:hoster];
[hosterTable reloadData];
}
-(void)removeHoster:(id<LyricsHoster>)hoster {
[hosters removeObject:hoster];
[hosterTable reloadData];
}
- (IBAction)showGeneralPreferences:(id)sender { - (IBAction)showGeneralPreferences:(id)sender {
[preferencesWindow setTitle:NSLocalizedString(@"iLyrics.preferences.text.general", @"")];
[self changeContentViewTo:generalView]; [self changeContentViewTo:generalView];
} }
-(IBAction)showAutoLyricsPreferences:(id)sender { -(IBAction)showAutoLyricsPreferences:(id)sender {
[preferencesWindow setTitle:NSLocalizedString(@"iLyrics.preferences.text.auto-lyrics", @"")];
[self changeContentViewTo:autoLyricsView]; [self changeContentViewTo:autoLyricsView];
} }
@@ -88,12 +72,12 @@
-(void)enableAutoLyrics: (id) sender{ -(void)enableAutoLyrics: (id) sender{
[autoLyrics setEnabled:YES]; [autoLyrics setEnabled:YES];
[sender setTitle:NSLocalizedString(@"iLyrics.text.disableAutoLyrics", @"")]; [sender setTitle:NSLocalizedString(@"iLyrics.preferences.text.disableAutoLyrics", @"")];
} }
-(void)disableAutoLyrics: (id) sender { -(void)disableAutoLyrics: (id) sender {
[autoLyrics setEnabled:NO]; [autoLyrics setEnabled:NO];
[sender setTitle:NSLocalizedString(@"iLyrics.text.enableAutoLyrics", @"")]; [sender setTitle:NSLocalizedString(@"iLyrics.preferences.text.enableAutoLyrics", @"")];
} }
- (IBAction)changeAutoLyricsInterval:(id)sender { - (IBAction)changeAutoLyricsInterval:(id)sender {
@@ -112,18 +96,61 @@
#pragma mark - #pragma mark -
#pragma mark Table Data Source #pragma mark Table Data Source
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { -(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [hosters count]; return [[ilyrics lyricsHosters] count];
} }
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { -(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
id<LyricsHoster> hoster = [[ilyrics lyricsHosters] objectAtIndex:row];
if ([[tableColumn identifier] isEqualToString:@"hoster"]) { if ([[tableColumn identifier] isEqualToString:@"hoster"]) {
return [[hosters objectAtIndex:row] name]; return [hoster name];
} else { } else {
NSDate *version = [[hosters objectAtIndex:row] hosterVersion]; NSDate *version = [hoster hosterVersion];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterLongStyle]; [dateFormatter setDateStyle:NSDateFormatterLongStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle]; [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
return [dateFormatter stringFromDate:version]; return [dateFormatter stringFromDate:version];
} }
} }
#pragma mark Drag and Drop Hosters
-(BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard {
// Copy the row numbers to the pasteboard.
NSData *indexData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
[pboard declareTypes:[NSArray arrayWithObject:HosterDataType] owner:self];
[pboard setData:indexData forType:HosterDataType];
return YES;
}
- (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row
proposedDropOperation:(NSTableViewDropOperation)op {
// Add code here to validate the drop
return NSDragOperationMove;
}
- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id<NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation {
NSPasteboard* pboard = [info draggingPasteboard];
NSData* rowData = [pboard dataForType:HosterDataType];
NSIndexSet* rowIndexes =
[NSKeyedUnarchiver unarchiveObjectWithData:rowData];
NSInteger dragRow = [rowIndexes firstIndex];
if (dragRow < row) {
[[ilyrics lyricsHosters] insertObject:[[ilyrics lyricsHosters] objectAtIndex:dragRow] atIndex:row];
[[ilyrics lyricsHosters] removeObjectAtIndex:dragRow];
[hosterTable noteNumberOfRowsChanged];
[hosterTable reloadData];
return YES;
}
id<LyricsHoster> draggedHoster = [[ilyrics lyricsHosters] objectAtIndex:dragRow];
[[ilyrics lyricsHosters] removeObjectAtIndex:dragRow];
[[ilyrics lyricsHosters] insertObject:draggedHoster atIndex:row];
[hosterTable noteNumberOfRowsChanged];
[hosterTable reloadData];
return YES;
}
@end @end

View File

@@ -7,14 +7,16 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "LyricsHoster.h"
@interface SearchResult : NSObject @interface SearchResult : NSObject
@property NSString *name; @property NSString *name;
@property NSString *artist; @property NSString *artist;
@property NSString *preview; @property NSString *preview;
@property id<LyricsHoster> loadedByHoster;
@property id link; @property id link;
-(id)initWithName: (NSString*) name fromArtist: (NSString*) artist preview: (NSString*) preview link: (id) link; -(id)initWithName: (NSString*) name fromArtist: (NSString*) artist preview: (NSString*) preview link: (id) link loadedByHoster: (id<LyricsHoster>) hoster;
@end @end

View File

@@ -12,13 +12,15 @@
@synthesize name; @synthesize name;
@synthesize artist; @synthesize artist;
@synthesize preview; @synthesize preview;
@synthesize loadedByHoster;
@synthesize link; @synthesize link;
-(id)initWithName:(NSString *)sng fromArtist:(NSString *)art preview:(NSString *)pre link:(id)l { -(id)initWithName:(NSString *)sng fromArtist:(NSString *)art preview:(NSString *)pre link:(id)l loadedByHoster:(id<LyricsHoster>)hoster {
name = sng; name = sng;
artist = art; artist = art;
preview = pre; preview = pre;
link = l; link = l;
loadedByHoster = hoster;
return self; return self;
} }
@end @end

14
iLyrics/Songtexte.h Normal file
View File

@@ -0,0 +1,14 @@
//
// Songtexte.h
// iLyrics
//
// Created by Kim Wittenburg on 22.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
// Representing http://www.songtexte.com
#import <Foundation/Foundation.h>
#import "LyricsHoster.h"
@interface Songtexte : NSObject <LyricsHoster>
@end

153
iLyrics/Songtexte.m Normal file
View File

@@ -0,0 +1,153 @@
//
// Songtexte.m
// iLyrics
//
// Created by Kim Wittenburg on 22.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
// TODO: Implement parsing of multi-page results
#import "Songtexte.h"
#import "SearchResult.h"
@implementation Songtexte {
NSString *resultsPage;
BOOL hasMoreResults;
BOOL hadMoreResults;
}
@synthesize enabled;
-(NSString *) name {
return @"Songtexte.com";
}
-(NSDate *)hosterVersion {
return [NSDate dateWithString:@"2012-06-22 15:00:00 +0100"];
}
-(void) startNewSearchForQuery: (NSString *)query {
NSString *searchPath = [NSString stringWithFormat:@"http://www.songtexte.com/search?c=songs&q=%@", [query stringByFormattingForURL]];
NSURL *searchURL = [NSURL URLWithString:searchPath];
NSError *error;
NSString *page = [NSString stringWithContentsOfURL:searchURL encoding:NSUTF8StringEncoding error:&error];
if (error || page == nil) {
//Network or other error
resultsPage = nil;
hasMoreResults = hadMoreResults = NO;
}
resultsPage = page;
if ([resultsPage rangeOfString:@"</label>\n</div>\n</div>"].location == NSNotFound) {
//No Results
hasMoreResults = hadMoreResults = NO;
} else {
hasMoreResults = hadMoreResults = YES;
}
}
-(BOOL)hasMoreResults {
return hasMoreResults;
}
-(NSArray *)nextResults {
if (resultsPage == nil) {
//Network or other error
return nil;
}
NSRange tableStartRange = [resultsPage rangeOfString:@"</label>\n</div>\n</div>"];
if (tableStartRange.location == NSNotFound) {
//No Results
return [[NSArray alloc] init];
}
NSRange tableRange = [self restRangeFromString:resultsPage subtractingRange:tableStartRange];
int resultsTableStart = NSMaxRange([resultsPage rangeOfString:@"<ul>" options:NSCaseInsensitiveSearch range:tableRange]);
NSRange resultsTableEndRange = [resultsPage rangeOfString:@"<li id=\"" options:NSCaseInsensitiveSearch range:tableRange];
if (resultsTableEndRange.location == NSNotFound) {
resultsTableEndRange = [resultsPage rangeOfString:@"</ul>" options:NSCaseInsensitiveSearch range:tableRange];
}
int resultsTableEnd = resultsTableEndRange.location;
hasMoreResults = NO;
return [self resultsFromTable:[resultsPage substringWithRange:NSMakeRange(resultsTableStart, resultsTableEnd-resultsTableStart)]];
}
-(NSArray *)resultsFromTable:(NSString *)table {
NSRange restRange = NSMakeRange(0, [table length]);
NSMutableArray *tags = [[NSMutableArray alloc] init];
NSUInteger currentIndex = [table rangeOfString:@"<li>"].location;
while (currentIndex != NSNotFound) {
int startIndex = currentIndex + [@"<li>" length];
int endIndex = [table rangeOfString:@"</li>" options:NSCaseInsensitiveSearch range:restRange].location;
NSRange tagRange = NSMakeRange(startIndex, endIndex-startIndex);
SearchResult *result = [self searchResultFromTag:[table substringWithRange:tagRange]];
if (result) {
[tags addObject:result];
}
restRange = [self restRangeFromString:table subtractingRange:tagRange];
restRange.length -= [@"</li>" length];
restRange.location += [@"</li>" length];
currentIndex = [table rangeOfString:@"<li>" options:NSCaseInsensitiveSearch range:restRange].location;
}
return tags;
}
-(SearchResult *) searchResultFromTag: (NSString *)tag {
NSRange artistStartRange = [tag rangeOfString:@"Songtexte, Übersetzungen, Lyrics\"><span>"];
NSRange artistEndRange = [tag rangeOfString:@"</span>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:artistStartRange]];
int artistStart = NSMaxRange(artistStartRange);
NSString *artist = [[tag substringWithRange:NSMakeRange(artistStart, artistEndRange.location-artistStart)] stringByRemovingHTMLTags];
NSRange songLinkStartRange = [tag rangeOfString:@"<a" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:artistEndRange]];
/*if ([tag rangeOfString:@"title=\"zum Song (noch kein Songtext vorhanden)\"" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:songLinkStartRange]].location != NSNotFound) {
return nil;
}*/
//This would remove entries which does not exist anymore.
//The Problem: hasMoreResults woult also return YES if there is only one result (no matter if existing or not).
NSRange hrefStartRange = [tag rangeOfString:@"href=\"" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:songLinkStartRange]];
NSRange hrefEndRange = [tag rangeOfString:@"\"" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:hrefStartRange]];
int hrefStart = NSMaxRange(hrefStartRange);
NSString *linkHref = [tag substringWithRange:NSMakeRange(hrefStart, hrefEndRange.location-hrefStart)];
NSRange nameStartRange = [tag rangeOfString:@"<span>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:hrefEndRange]];
NSRange nameEndRange = [tag rangeOfString:@"</span>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:nameStartRange]];
int nameStart = NSMaxRange(nameStartRange);
NSString *name = [[tag substringWithRange:NSMakeRange(nameStart, nameEndRange.location-nameStart)] stringByRemovingHTMLTags];
return [[SearchResult alloc] initWithName:name fromArtist:artist preview:nil link:[self urlFromHref:linkHref] loadedByHoster:self];
}
-(NSURL*) urlFromHref: (NSString *) link {
if (![link hasPrefix:@"http://www.songtexte.com"]) {
return [NSURL URLWithString:[NSString stringWithFormat:@"http://www.songtexte.com/%@", link]];
} else {
return [NSURL URLWithString:link];
}
}
-(NSRange) restRangeFromString: (NSString *) page subtractingRange: (NSRange) aRange {
int loc = NSMaxRange(aRange);
return NSMakeRange(loc, [page length]-loc);
}
-(void)resetLoadedResults {
hasMoreResults = hadMoreResults;
}
-(Lyrics *)lyricsBySearchResult:(id)result {
NSError *error;
NSString *page = [NSString stringWithContentsOfURL:[result link] encoding:NSUTF8StringEncoding error:&error];
if (error || page == nil) {
return nil;
}
NSRange lyricsStartRange = [page rangeOfString:@"<div id=\"lyrics\">"];
NSRange lyricsEndRange = [page rangeOfString:@"</div>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:page subtractingRange:lyricsStartRange]];
int lyricsStart = NSMaxRange(lyricsStartRange);
NSString *lyrics = [[page substringWithRange:NSMakeRange(lyricsStart, lyricsEndRange.location-lyricsStart)] stringByRemovingHTMLTags];
return [[Lyrics alloc] initWithName:[result name] byArtist:[result artist] withLyrics:lyrics];
}
-(BOOL)canShowInBrowser:(id)result {
return YES;
}
-(void)showInBrowser:(id)result {
[[NSWorkspace sharedWorkspace] openURL:[result link]];
}
@end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.1.1</string> <string>1.2</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>10</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.music</string> <string>public.app-category.music</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>

38
iLyrics/iLyrics.h Normal file
View File

@@ -0,0 +1,38 @@
//
// iLyrics.h
// iLyrics
//
// Created by Kim Wittenburg on 19.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <Growl/Growl.h>
#import "LyricsHoster.h"
#import "Magistrix.h"
#import "Songtexte.h"
#import "MP3Lyrics.h"
#import "SearchResult.h"
#import "Lyrics.h"
#import "iTunes.h"
#import "Spotify.h"
@interface iLyrics : NSObject
@property NSMutableArray *lyricsHosters;
@property(readonly) id<LyricsHoster> preferredHoster;
@property(readonly) Magistrix *magistrix;
@property(readonly) Songtexte *songtexte;
@property(readonly) MP3Lyrics *mp3Lyrics;
@property(readonly) iTunesApplication *iTunes;
@property(readonly) SpotifyApplication *spotify;
+(iLyrics *)sharediLyrics;
-(id<LyricsHoster>) hosterWithName: (NSString *) name;
-(void)saveToDefaults:(NSUserDefaults *)defaults;
-(void)loadFromDefaults:(NSUserDefaults *)defaults;
@end

78
iLyrics/iLyrics.m Normal file
View File

@@ -0,0 +1,78 @@
//
// iLyrics.m
// iLyrics
//
// Created by Kim Wittenburg on 19.06.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "iLyrics.h"
@implementation iLyrics
iLyrics *ilyrics;
@synthesize lyricsHosters;
@synthesize magistrix;
@synthesize songtexte;
@synthesize mp3Lyrics;
@synthesize iTunes;
@synthesize spotify;
+(iLyrics *)sharediLyrics {
if (ilyrics == nil) {
ilyrics = [[iLyrics alloc] init];
}
return ilyrics;
}
-(id)init {
self = [super init];
if (self) {
iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
spotify = [SBApplication applicationWithBundleIdentifier:@"com.spotify.client"];
magistrix = [[Magistrix alloc] init];
songtexte = [[Songtexte alloc] init];
//mp3Lyrics = [[MP3Lyrics alloc] init];
lyricsHosters = [NSMutableArray arrayWithObjects:magistrix, songtexte, /*mp3Lyrics,*/ nil];
[self loadFromDefaults:[NSUserDefaults standardUserDefaults]];
}
return self;
}
-(void)loadFromDefaults:(NSUserDefaults *)defaults {
NSArray *hosterNames = [defaults objectForKey:@"Lyrics Hosters"];
NSMutableArray *reorderedHosters = [[NSMutableArray alloc] init];
for (NSString *name in hosterNames) {
id<LyricsHoster> hoster = [self hosterWithName:name];
if (hoster) {
[reorderedHosters addObject:hoster];
}
}
if ([reorderedHosters count] == [lyricsHosters count]) {
lyricsHosters = reorderedHosters;
}
}
-(id<LyricsHoster>)preferredHoster {
return [lyricsHosters objectAtIndex:0];
}
-(id<LyricsHoster>)hosterWithName:(NSString *)name {
for (id<LyricsHoster> hoster in lyricsHosters) {
if ([name isEqualToString:[hoster name]]) {
return hoster;
}
}
return nil;
}
-(void)saveToDefaults:(NSUserDefaults *)defaults {
NSMutableArray *hosterNames = [[NSMutableArray alloc] init];
for (id<LyricsHoster> hoster in lyricsHosters) {
[hosterNames addObject:[hoster name]];
}
[defaults setObject:hosterNames forKey:@"Lyrics Hosters"];
}
@end