-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:
@@ -64,4 +64,28 @@
|
||||
-Fixed a bug: Returned false results when having a "&" in the query\
|
||||
-Fixed a resource bug\
|
||||
-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}
|
||||
@@ -1,78 +1,103 @@
|
||||
/* Standards */
|
||||
/* ---------- Standards - Werden in Warnmeldungen angezeigt ---------- */
|
||||
"OK" = "OK";
|
||||
|
||||
"Yes" = "Ja";
|
||||
|
||||
"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";
|
||||
|
||||
/* Preference Items */
|
||||
"iLyrics.text.enableAutoLyrics" = "Auto-Lyrics einschalten";
|
||||
//----- Warnmeldungen
|
||||
|
||||
"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 */
|
||||
"iLyrics.text.illegalDateFormat" = "Keine Angabe";
|
||||
/* Ein Netzwerkfehler ist aufgetreten, während die Ergebnisse geladen wurden */
|
||||
"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 */
|
||||
/* Search Token Replacements */
|
||||
"iLyrics.searchToken.%name%" = "Songname";
|
||||
/* Die Suche ergab keine Ergebnisse */
|
||||
"iLyrics.messages.noResults.title" = "Ihre Suche ergab keine Ergebnisse.";
|
||||
"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 */
|
||||
"Magistrix.text.noPreview" = "Keine Vorschau verfügbar.";
|
||||
/* ---------- iLyrics - Einstellungsfenster ---------- */
|
||||
|
||||
"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.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 */
|
||||
/* By text used in the artist menu item where %@ is the artist */
|
||||
"iTunes.text.byFormat" = "von %@";
|
||||
//----- Warnmeldungen
|
||||
|
||||
/* iTunes (error) messages */
|
||||
"iTunes.messages.iTunesIdle.title" = "iTunes ist zurzeit nicht geöffnet.";
|
||||
/* Es wird kein Titel wiedergegeben */
|
||||
"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.";
|
||||
|
||||
/* Spotify Messages */
|
||||
"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 gesichert (In der detailierten Beschreibung %@ ist der Name der Datei) */
|
||||
"Growl.messages.lyricsSaved.title" = "Songtext gesichert";
|
||||
"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.detail" = "Songtext an \"%@\" gesendet.";
|
||||
@@ -1,79 +1,103 @@
|
||||
/* Standards */
|
||||
/* ---------- Standards - Used in Alert sheets and dialogs ---------- */
|
||||
"OK" = "OK";
|
||||
|
||||
"Yes" = "Yes";
|
||||
|
||||
"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 */
|
||||
"iLyrics.text.noSelection" = "No Selection";
|
||||
|
||||
/* Preference Items */
|
||||
"iLyrics.text.enableAutoLyrics" = "Enable Auto-Lyrics";
|
||||
//----- Alert Texts
|
||||
|
||||
"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 */
|
||||
"iLyrics.text.illegalDateFormat" = "No Specification";
|
||||
/* A Network error occured while loading search results */
|
||||
"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 */
|
||||
/* Search Token Replacements */
|
||||
"iLyrics.searchToken.%name%" = "Song Name";
|
||||
|
||||
"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.";
|
||||
/* The search did not return any results */
|
||||
"iLyrics.messages.noResults.title" = "Your search did not return any results.";
|
||||
"iLyrics.messages.noResults.detail" = "None of the hosters provides any songtexts matching to the entered query.";
|
||||
|
||||
/* 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.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";
|
||||
|
||||
/* %@ is the name of the song */
|
||||
"Growl.messages.lyricsSent.detail" = "Lyrics sent to \"%@\".";
|
||||
@@ -12,7 +12,6 @@
|
||||
3B20EF381584EA9A006C0CDF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF371584EA9A006C0CDF /* main.m */; };
|
||||
3B20EF3C1584EA9A006C0CDF /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF3A1584EA9A006C0CDF /* Credits.rtf */; };
|
||||
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 */; };
|
||||
3B20EF4D1584EAAD006C0CDF /* iTunes.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3B20EF4A1584EAAD006C0CDF /* iTunes.icns */; };
|
||||
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 */; };
|
||||
3B20EF551584ECD9006C0CDF /* Lyrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B20EF541584ECD9006C0CDF /* Lyrics.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 */; };
|
||||
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 */; };
|
||||
3B73010E158CDF7200D3AF26 /* AutoLyrics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B73010D158CDF7200D3AF26 /* AutoLyrics.m */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@@ -58,7 +62,6 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -70,17 +73,27 @@
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -88,7 +101,6 @@
|
||||
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>"; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -148,15 +160,17 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B2DC558158CCE8100C004A4 /* Changelog.rtf */,
|
||||
3B9A335F1590BDE700B844EF /* iLyrics.h */,
|
||||
3B9A33601590BDE700B844EF /* iLyrics.m */,
|
||||
3B73010C158CDF7200D3AF26 /* AutoLyrics.h */,
|
||||
3B73010D158CDF7200D3AF26 /* AutoLyrics.m */,
|
||||
3B20EF3D1584EA9A006C0CDF /* AppDelegate.h */,
|
||||
3B20EF3E1584EA9A006C0CDF /* AppDelegate.m */,
|
||||
3B20EF401584EA9A006C0CDF /* MainMenu.xib */,
|
||||
3B3A377E15972079002085CE /* MainMenu.xib */,
|
||||
3B2DC559158CD31E00C004A4 /* PreferencesWindow.h */,
|
||||
3B2DC55A158CD31E00C004A4 /* PreferencesWindow.m */,
|
||||
3BE95015158A291500E78FEF /* PreferencesController.h */,
|
||||
3BE95016158A291500E78FEF /* PreferencesController.m */,
|
||||
3B73010C158CDF7200D3AF26 /* AutoLyrics.h */,
|
||||
3B73010D158CDF7200D3AF26 /* AutoLyrics.m */,
|
||||
3B20EF501584EAF8006C0CDF /* MainController.h */,
|
||||
3B20EF511584EAF8006C0CDF /* MainController.m */,
|
||||
3B20EF5A1584F34E006C0CDF /* SearchResult.h */,
|
||||
@@ -186,9 +200,15 @@
|
||||
3B20EF591584F31D006C0CDF /* Lyrics Hoster */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B20EF5D1584F458006C0CDF /* LyricsHoster.h */,
|
||||
3BE9500F158A269D00E78FEF /* Magistrix.h */,
|
||||
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";
|
||||
sourceTree = "<group>";
|
||||
@@ -202,7 +222,7 @@
|
||||
3B20EF4A1584EAAD006C0CDF /* iTunes.icns */,
|
||||
3B20EF4B1584EAAD006C0CDF /* Diamond.tiff */,
|
||||
3B20EF4C1584EAAD006C0CDF /* Download-icon.icns */,
|
||||
3B20EF6315853345006C0CDF /* Localizable.strings */,
|
||||
3B3A3783159727FE002085CE /* Localizable.strings */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -261,12 +281,12 @@
|
||||
files = (
|
||||
3B20EF361584EA9A006C0CDF /* InfoPlist.strings in Resources */,
|
||||
3B20EF3C1584EA9A006C0CDF /* Credits.rtf in Resources */,
|
||||
3B20EF421584EA9A006C0CDF /* MainMenu.xib in Resources */,
|
||||
3B3A377C15972079002085CE /* MainMenu.xib in Resources */,
|
||||
3B20EF491584EAA3006C0CDF /* iLyrics.icns in Resources */,
|
||||
3B20EF4D1584EAAD006C0CDF /* iTunes.icns in Resources */,
|
||||
3B20EF4E1584EAAD006C0CDF /* Diamond.tiff 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 */,
|
||||
3B5E8ED2158E7AC40082A769 /* Spotify.icns in Resources */,
|
||||
);
|
||||
@@ -288,6 +308,10 @@
|
||||
3BE95017158A291500E78FEF /* PreferencesController.m in Sources */,
|
||||
3B2DC55B158CD31E00C004A4 /* PreferencesWindow.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;
|
||||
};
|
||||
@@ -311,20 +335,20 @@
|
||||
name = Credits.rtf;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3B20EF401584EA9A006C0CDF /* MainMenu.xib */ = {
|
||||
3B3A377E15972079002085CE /* MainMenu.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
3B20EF411584EA9A006C0CDF /* en */,
|
||||
3BFDD3FA158D420400BF32B0 /* de */,
|
||||
3B3A377D15972079002085CE /* en */,
|
||||
3B3A378015972080002085CE /* de */,
|
||||
);
|
||||
name = MainMenu.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3B20EF6315853345006C0CDF /* Localizable.strings */ = {
|
||||
3B3A3783159727FE002085CE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
3B20EF6215853345006C0CDF /* en */,
|
||||
3BBD9B72158C7F8A00A5CD2C /* de */,
|
||||
3B3A3782159727FE002085CE /* en */,
|
||||
3B3A378415972803002085CE /* de */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -7,13 +7,11 @@
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "Magistrix.h"
|
||||
|
||||
@implementation AppDelegate {
|
||||
iTunesApplication *iTunes;
|
||||
NSArray *keyTokens;
|
||||
NSMutableArray *searchFormat;
|
||||
Magistrix *magistrix;
|
||||
}
|
||||
|
||||
@synthesize window;
|
||||
@@ -24,8 +22,6 @@
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
magistrix = [[Magistrix alloc] init];
|
||||
[preferencesController addHoster:magistrix];
|
||||
keyTokens = [NSArray arrayWithObjects:@"%name%", @"%artist%", @"%album%", nil];
|
||||
[window setExcludedFromWindowsMenu:YES];
|
||||
iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
|
||||
@@ -45,6 +41,7 @@
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setBool:[quitWhenAllWindowClosedCheckBox state] == NSOnState forKey:@"Quit when all windows are closed"];
|
||||
[mainController saveToDefalts:defaults];
|
||||
[[iLyrics sharediLyrics] saveToDefaults:defaults];
|
||||
[[AutoLyrics autoLyrics] saveToDefaults:defaults];
|
||||
[defaults synchronize];
|
||||
return NSTerminateNow;
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Growl/Growl.h>
|
||||
#import "iTunes.h"
|
||||
#import "Magistrix.h"
|
||||
#import "LyricsHoster.h"
|
||||
#import "iLyrics.h"
|
||||
|
||||
@interface AutoLyrics : NSObject
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ AutoLyrics *instace;
|
||||
-(id)init {
|
||||
enabled = NO;
|
||||
replaceOldLyrics = NO;
|
||||
[self setInterval:30];
|
||||
[self setInterval:5];
|
||||
return [super init];
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ AutoLyrics *instace;
|
||||
|
||||
-(void)shouldSetLyrics: (NSTimer *) sender {
|
||||
if (enabled) {
|
||||
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
|
||||
iTunesApplication *iTunes = [[iLyrics sharediLyrics] iTunes];
|
||||
iTunesTrack *current = [iTunes currentTrack];
|
||||
if ([current name] != nil) {
|
||||
if (replaceOldLyrics || [[current lyrics] length] == 0) {
|
||||
@@ -68,13 +68,13 @@ AutoLyrics *instace;
|
||||
}
|
||||
|
||||
-(void)setLyrics {
|
||||
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
|
||||
iTunesApplication *iTunes = [[iLyrics sharediLyrics] iTunes];
|
||||
iTunesTrack *track = [iTunes currentTrack];
|
||||
Magistrix *magistrix = [[Magistrix alloc] init];
|
||||
[magistrix startNewSearchForQuery:[NSString stringWithFormat:@"%@ - %@", [track name], [track artist]]];
|
||||
NSArray *results = [magistrix nextResults];
|
||||
id<LyricsHoster> hoster = [[iLyrics sharediLyrics] preferredHoster];
|
||||
[hoster startNewSearchForQuery:[NSString stringWithFormat:@"%@ - %@", [track name], [track artist]]];
|
||||
NSArray *results = [hoster nextResults];
|
||||
if (results != nil && [results count] > 0) {
|
||||
Lyrics *lyrics = [magistrix lyricsBySearchResult:[results objectAtIndex:0]];
|
||||
Lyrics *lyrics = [hoster lyricsBySearchResult:[results objectAtIndex:0]];
|
||||
[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];
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SearchResult.h"
|
||||
#import "Lyrics.h"
|
||||
#import "LyricsHosterUtil.h"
|
||||
|
||||
@protocol LyricsHoster <NSObject>
|
||||
|
||||
@property BOOL enabled;
|
||||
|
||||
-(NSString*) name;
|
||||
|
||||
-(NSDate*) hosterVersion;
|
||||
@@ -25,7 +27,12 @@
|
||||
|
||||
-(void) resetLoadedResults;
|
||||
|
||||
-(BOOL) canShowInBrowser:(id)result;
|
||||
|
||||
-(void) showInBrowser:(id)result;
|
||||
|
||||
//Return nil for a "network error"
|
||||
-(Lyrics*) lyricsBySearchResult: (SearchResult *) result;
|
||||
//parameter should be a SearchResult instance
|
||||
-(Lyrics*) lyricsBySearchResult: (id) result;
|
||||
|
||||
@end
|
||||
|
||||
14
iLyrics/LyricsHosterUtil.h
Normal file
14
iLyrics/LyricsHosterUtil.h
Normal 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
|
||||
23
iLyrics/LyricsHosterUtil.m
Normal file
23
iLyrics/LyricsHosterUtil.m
Normal 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:@""" withString:@"\""] stringByReplacingOccurrencesOfString:@"&" withString:@"&"] stringByReplacingOccurrencesOfString:@"'" 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
14
iLyrics/MP3Lyrics.h
Normal 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
68
iLyrics/MP3Lyrics.m
Normal 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
|
||||
@@ -5,6 +5,7 @@
|
||||
// Created by Kim Wittenburg on 14.06.12.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
// Representing http://www.magistrix.de
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LyricsHoster.h"
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
//
|
||||
//TODO: Use correct Date
|
||||
|
||||
#import "Magistrix.h"
|
||||
#import "SearchResult.h"
|
||||
|
||||
typedef enum {
|
||||
LyricsPage,
|
||||
@@ -21,8 +21,11 @@ typedef enum {
|
||||
NSString *query;
|
||||
int loadedResults;
|
||||
int resultCount;
|
||||
NSString *firstPage;
|
||||
}
|
||||
|
||||
@synthesize enabled;
|
||||
|
||||
-(NSString*) name {
|
||||
return @"Magistrix";
|
||||
}
|
||||
@@ -34,6 +37,23 @@ typedef enum {
|
||||
-(void) startNewSearchForQuery: (NSString*) q {
|
||||
[self resetLoadedResults];
|
||||
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 {
|
||||
@@ -42,38 +62,33 @@ typedef enum {
|
||||
|
||||
-(NSArray*) nextResults {
|
||||
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];
|
||||
NSString *page;
|
||||
if (site == 1 && firstPage != nil) {
|
||||
page = firstPage;
|
||||
} else {
|
||||
NSError *error;
|
||||
NSString *page = [NSString stringWithContentsOfURL:searchURL encoding:NSUTF8StringEncoding error:&error];
|
||||
page = [NSString stringWithContentsOfURL:searchURL encoding:NSUTF8StringEncoding error:&error];
|
||||
if (error) {
|
||||
//Network error or invalid query
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
PageType pType = [self typeOfPage:page];
|
||||
if (pType == LyricsPage) {
|
||||
resultCount = 1;
|
||||
loadedResults = 1;
|
||||
return [NSArray arrayWithObject:[self searchResultFromLyricsPage:page atURL:searchURL]];
|
||||
} else if (pType == ResultsPage) {
|
||||
[self shouldSetResultCountFromPage:page];
|
||||
return [self searchResultsFromPage:page];
|
||||
} else if (pType == NoResultsPage) {
|
||||
resultCount = 0;
|
||||
return [[NSArray alloc] init];
|
||||
} else {
|
||||
NSRunAlertPanel(NSLocalizedString(@"Magistrix.messages.unknownPage.title", @""), NSLocalizedString(@"Magistrix.messages.unknownPage.detail", @""), NSLocalizedString(@"OK", @""), nil, nil);
|
||||
resultCount = 0;
|
||||
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 {
|
||||
if ([page rangeOfString:@"<title>Songtext-Suche</title>"].location != NSNotFound) {
|
||||
if ([page rangeOfString:@"<div class='empty_collection'>"].location != NSNotFound) {
|
||||
@@ -96,12 +111,12 @@ typedef enum {
|
||||
int artistEnd = artistEndTag.location;
|
||||
int songNameStart = NSMaxRange(artistEndTag);
|
||||
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)];
|
||||
//Remove the " Lyric" and the " – " from the Song name
|
||||
songName = [self stringByRemovingHTMLTags:[[songName substringToIndex:[songName length]-[@" Lyric" length]] substringFromIndex:[@" – " length]]];
|
||||
songName = [[[songName substringToIndex:[songName length]-[@" Lyric" length]] substringFromIndex:[@" – " length]] stringByRemovingHTMLTags];
|
||||
NSString *preview = [self lyricsFromPage:page];
|
||||
return [[SearchResult alloc]initWithName:songName fromArtist:artist preview:preview link:url];
|
||||
return [[SearchResult alloc]initWithName:songName fromArtist:artist preview:preview link:url loadedByHoster:self];
|
||||
}
|
||||
|
||||
-(NSArray*) searchResultsFromPage: (NSString *) page {
|
||||
@@ -139,8 +154,7 @@ typedef enum {
|
||||
NSRange artistStartRange = [tag rangeOfString:@">"];
|
||||
int artistEndIndex = [tag rangeOfString:@"<" options:NSCaseInsensitiveSearch range:[self restRangeFromString:tag subtractingRange:artistStartRange]].location;
|
||||
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 songNameTagStartRange = [tag rangeOfString:@"<a href=\"" options:NSCaseInsensitiveSearch range:restRange];
|
||||
int linkStart = NSMaxRange(songNameTagStartRange);
|
||||
@@ -148,12 +162,12 @@ typedef enum {
|
||||
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 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];
|
||||
NSRange previewRestRange = NSMakeRange(previewStart, [tag length]-previewStart);
|
||||
int previewEnd = [tag rangeOfString:@"</p>" options:NSCaseInsensitiveSearch range:previewRestRange].location;
|
||||
NSString *preview = [self stringByRemovingHTMLTags:[tag substringWithRange:NSMakeRange(previewStart, previewEnd-previewStart)]];
|
||||
return [[SearchResult alloc] initWithName:songName fromArtist:artist preview:preview link:link];
|
||||
NSString *preview = [[tag substringWithRange:NSMakeRange(previewStart, previewEnd-previewStart)] stringByRemovingHTMLTags];
|
||||
return [[SearchResult alloc] initWithName:songName fromArtist:artist preview:preview link:link loadedByHoster:self];
|
||||
}
|
||||
|
||||
-(NSURL*) urlFromHref: (NSString *) link {
|
||||
@@ -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:@""" withString:@"\""] stringByReplacingOccurrencesOfString:@"&" withString:@"&"];
|
||||
}
|
||||
|
||||
-(NSRange) restRangeFromString: (NSString *) page subtractingRange: (NSRange) aRange {
|
||||
int loc = NSMaxRange(aRange);
|
||||
@@ -174,7 +185,7 @@ typedef enum {
|
||||
}
|
||||
|
||||
-(void) shouldSetResultCountFromPage: (NSString *) page {
|
||||
if (resultCount == 0) {
|
||||
if (resultCount <= 0) {
|
||||
//Nothing loaded before
|
||||
NSRange resultsLabelStartRange = [page rangeOfString:@"<p>Ergebnisse 1 bis "];
|
||||
int resultsLabelEnd = [page rangeOfString:@"</p>" options:NSCaseInsensitiveSearch range:[self restRangeFromString:page subtractingRange:resultsLabelStartRange]].location;
|
||||
@@ -196,6 +207,7 @@ typedef enum {
|
||||
|
||||
-(void) resetLoadedResults {
|
||||
loadedResults = 0;
|
||||
firstPage = nil;
|
||||
}
|
||||
|
||||
-(Lyrics*) lyricsBySearchResult: (SearchResult *) result {
|
||||
@@ -208,13 +220,20 @@ typedef enum {
|
||||
return [[Lyrics alloc] initWithName:[result name] byArtist:[result artist] withLyrics:lyrics];
|
||||
}
|
||||
|
||||
|
||||
-(NSString *) lyricsFromPage: (NSString *)page {
|
||||
int lyricsStart = NSMaxRange([page rangeOfString:@"<div id='songtext'>"]) + [@"\n" length];
|
||||
NSRange restRange = NSMakeRange(lyricsStart, [page length]-lyricsStart);
|
||||
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;
|
||||
}
|
||||
|
||||
-(BOOL)canShowInBrowser:(id)result {
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)showInBrowser:(id)result {
|
||||
[[NSWorkspace sharedWorkspace] openURL:[result link]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,37 +6,24 @@
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.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>
|
||||
#import "iLyrics.h"
|
||||
|
||||
@interface MainController : NSObject <NSWindowDelegate, NSSplitViewDelegate, NSOutlineViewDataSource, NSOutlineViewDelegate>
|
||||
@property (weak) IBOutlet NSMenuItem *iLyricsMenuItem;
|
||||
@property (unsafe_unretained) IBOutlet NSWindow *window;
|
||||
@property (weak) IBOutlet NSSearchField *searchField;
|
||||
@property (weak) IBOutlet NSOutlineView *resultsOutline;
|
||||
@property (weak) IBOutlet NSButton *loadMoreResultsButton;
|
||||
@property (weak) IBOutlet NSButton *showPreviewCheckBox;
|
||||
@property (weak) IBOutlet NSPopover *previewPopover;
|
||||
@property (unsafe_unretained) IBOutlet NSTextView *previewTextArea;
|
||||
@property (weak) IBOutlet NSTextField *songLabel;
|
||||
@property (weak) IBOutlet NSTextField *artistLabel;
|
||||
@property (weak) IBOutlet NSButton *sendToiTunesButton;
|
||||
@property (weak) IBOutlet NSButton *downloadLyricsButton;
|
||||
@property (unsafe_unretained) IBOutlet NSTextView *lyricsArea;
|
||||
@property (readonly) Lyrics *currentLyrics;
|
||||
|
||||
- (IBAction)getCurrentiTunesSong:(id)sender;
|
||||
- (IBAction)getCurrentSpotifySong:(id)sender;
|
||||
- (IBAction)startNewSearch:(id)sender;
|
||||
- (IBAction)loadNextResults:(id)sender;
|
||||
- (IBAction)resetLoadedResults:(id)sender;
|
||||
- (IBAction)lyricsSelectionChanged:(NSOutlineView *)sender;
|
||||
- (IBAction)sendLyricsToiTunes:(id)sender;
|
||||
|
||||
@@ -10,46 +10,46 @@
|
||||
|
||||
@implementation MainController {
|
||||
NSMutableArray *loadedResults;
|
||||
id<LyricsHoster> currentHoster;
|
||||
BOOL lyricsSelected;
|
||||
NSInteger selectedSavePanelButton;
|
||||
NSURL *saveFile;
|
||||
iTunesApplication *iTunes;
|
||||
SpotifyApplication *spotify;
|
||||
Lyrics *currentLyrics;
|
||||
int selectedRow;
|
||||
iLyrics *ilyrics;
|
||||
}
|
||||
@synthesize iLyricsMenuItem;
|
||||
@synthesize window;
|
||||
@synthesize searchField;
|
||||
@synthesize resultsOutline;
|
||||
@synthesize loadMoreResultsButton;
|
||||
@synthesize showPreviewCheckBox;
|
||||
@synthesize previewPopover;
|
||||
@synthesize previewTextArea;
|
||||
@synthesize songLabel;
|
||||
@synthesize artistLabel;
|
||||
@synthesize sendToiTunesButton;
|
||||
@synthesize downloadLyricsButton;
|
||||
@synthesize lyricsArea;
|
||||
|
||||
|
||||
-(id)init {
|
||||
iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
|
||||
spotify = [SBApplication applicationWithBundleIdentifier:@"com.spotify.client"];
|
||||
loadedResults = [[NSMutableArray alloc] init];
|
||||
currentHoster = [[Magistrix alloc] init];
|
||||
ilyrics = [iLyrics sharediLyrics];
|
||||
return [super init];
|
||||
}
|
||||
|
||||
-(void)awakeFromNib {
|
||||
[self lyricsSelectionChanged:resultsOutline];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Outline view Data Source and Delegate
|
||||
|
||||
-(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 {
|
||||
if (index == [outlineView numberOfRows]-1) {
|
||||
return NSLocalizedString(@"iLyrics.text.loadMoreResults", @"");
|
||||
}
|
||||
return [loadedResults objectAtIndex:index];
|
||||
}
|
||||
|
||||
@@ -58,18 +58,41 @@
|
||||
}
|
||||
|
||||
-(id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
|
||||
if ([item isKindOfClass:[NSString class]]) {
|
||||
return item;
|
||||
}
|
||||
if ([[tableColumn identifier] isEqualToString:@"song"]) {
|
||||
return [item name];
|
||||
} else {
|
||||
} else if ([[tableColumn identifier] isEqualToString:@"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;
|
||||
}
|
||||
|
||||
|
||||
-(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
|
||||
if ([item isKindOfClass:[SearchResult class]]) {
|
||||
[self shouldShowPreviewForCellRect:*rect searchResult:item];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -77,11 +100,7 @@
|
||||
#pragma mark Responding to Lyrics Search
|
||||
|
||||
- (IBAction)getCurrentiTunesSong:(id)sender {
|
||||
iTunesTrack *track = [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;
|
||||
}
|
||||
iTunesTrack *track = [[ilyrics iTunes] currentTrack];
|
||||
NSString *name = [track name];
|
||||
NSString *artist = [track artist];
|
||||
if (name == nil) {
|
||||
@@ -94,7 +113,7 @@
|
||||
}
|
||||
|
||||
- (IBAction)getCurrentSpotifySong:(id)sender {
|
||||
SpotifyTrack *track = [spotify currentTrack];
|
||||
SpotifyTrack *track = [[ilyrics spotify] currentTrack];
|
||||
NSString *name = [track name];
|
||||
NSString *artist = [track artist];
|
||||
if (name == nil) {
|
||||
@@ -109,36 +128,97 @@
|
||||
- (IBAction)startNewSearch:(id)sender {
|
||||
[self resetLoadedResults:sender];
|
||||
if ([[searchField stringValue] length] > 0) {
|
||||
[currentHoster startNewSearchForQuery:[searchField stringValue]];
|
||||
[self loadNextResults:sender];
|
||||
for (id<LyricsHoster> hoster in [ilyrics lyricsHosters]) {
|
||||
[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 {
|
||||
NSArray *nextResults = [currentHoster nextResults];
|
||||
[loadMoreResultsButton setEnabled:[currentHoster hasMoreResults]];
|
||||
- (void)loadNextResults:(id)sender{
|
||||
[self loadNextResultsFromHoster:[ilyrics hosterWithName:[sender title]]];
|
||||
}
|
||||
|
||||
- (void) loadNextResultsFromHoster: (id<LyricsHoster>) hoster {
|
||||
if (hoster == nil) {
|
||||
return;
|
||||
}
|
||||
NSArray *nextResults = [hoster nextResults];
|
||||
if (nextResults == nil) {
|
||||
NSRunCriticalAlertPanel(NSLocalizedString(@"Hoster.messages.networkOrQueryError.title", @""), NSLocalizedString(@"Hoster.messages.networkOrQueryError.detail", @""), NSLocalizedString(@"OK", @""), nil, nil);
|
||||
[self presentNetworkErrorWithHoster:hoster];
|
||||
return;
|
||||
}
|
||||
if ([nextResults count] == 0) {
|
||||
NSRunAlertPanel(NSLocalizedString(@"Hoster.messages.noResults.title", @""), NSLocalizedString(@"Hoster.messages.noResults.detail", @""), NSLocalizedString(@"OK", @""), nil, nil);
|
||||
[self presentNoResultsErrorWithHoster:hoster];
|
||||
return;
|
||||
}
|
||||
[loadedResults addObjectsFromArray:nextResults];
|
||||
[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 {
|
||||
[currentHoster resetLoadedResults];
|
||||
for (id<LyricsHoster> hoster in [ilyrics lyricsHosters]) {
|
||||
[hoster resetLoadedResults];
|
||||
}
|
||||
[loadedResults removeAllObjects];
|
||||
[resultsOutline reloadData];
|
||||
[loadMoreResultsButton setEnabled:[currentHoster hasMoreResults]];
|
||||
[self lyricsSelectionChanged:resultsOutline];
|
||||
}
|
||||
|
||||
- (IBAction)lyricsSelectionChanged:(NSOutlineView *)sender {
|
||||
int index = [sender selectedRow];
|
||||
if (index == [sender numberOfRows]-1) {
|
||||
index = -1;
|
||||
}
|
||||
if (index < 0) {
|
||||
lyricsSelected = NO;
|
||||
currentLyrics = nil;
|
||||
@@ -151,10 +231,12 @@
|
||||
if (selectedRow != index) {
|
||||
lyricsSelected = YES;
|
||||
SearchResult *result = [loadedResults objectAtIndex:index];
|
||||
Lyrics *lyrics = [currentHoster lyricsBySearchResult:result];
|
||||
Lyrics *lyrics = [[result loadedByHoster] lyricsBySearchResult:result];
|
||||
currentLyrics = lyrics;
|
||||
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", @"");
|
||||
[songLabel setStringValue:noNetwork];
|
||||
[artistLabel setStringValue:noNetwork];
|
||||
@@ -176,14 +258,14 @@
|
||||
NSString *lyrics = [result preview];
|
||||
if (lyrics) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)sendLyricsToiTunes:(id)sender {
|
||||
iTunesTrack *track = [iTunes currentTrack];
|
||||
iTunesTrack *track = [[ilyrics iTunes] currentTrack];
|
||||
NSString *name = [track name];
|
||||
if (name == nil) {
|
||||
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 {
|
||||
if (returnCode == NSAlertDefaultReturn) {
|
||||
iTunesTrack *track = [iTunes currentTrack];
|
||||
iTunesTrack *track = [[ilyrics iTunes] currentTrack];
|
||||
[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];
|
||||
}
|
||||
@@ -225,8 +307,8 @@
|
||||
if (row < 0) {
|
||||
row = [resultsOutline selectedRow];
|
||||
}
|
||||
NSURL *link = [[loadedResults objectAtIndex:row] link];
|
||||
[[NSWorkspace sharedWorkspace] openURL:link];
|
||||
SearchResult *result = [loadedResults objectAtIndex:row];
|
||||
[[result loadedByHoster] showInBrowser:result];
|
||||
}
|
||||
|
||||
-(void) savePanelDidClose: (NSNotification *) notification{
|
||||
@@ -234,7 +316,7 @@
|
||||
if (selectedSavePanelButton == NSOKButton) {
|
||||
BOOL success = [[[lyricsArea string] dataUsingEncoding:NSUTF8StringEncoding] writeToURL:saveFile atomically:NO];
|
||||
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 {
|
||||
[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
|
||||
|
||||
-(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];
|
||||
}
|
||||
|
||||
@@ -280,28 +367,28 @@
|
||||
-(BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
|
||||
SEL action = [item action];
|
||||
if (action == @selector(downloadLyrics:)) {
|
||||
[downloadLyricsButton setEnabled:lyricsSelected];
|
||||
return lyricsSelected;
|
||||
}
|
||||
if (action == @selector(sendLyricsToiTunes:)) {
|
||||
BOOL enabled = lyricsSelected && [iTunes isRunning];
|
||||
[sendToiTunesButton setEnabled:enabled];
|
||||
BOOL enabled = lyricsSelected && [[ilyrics iTunes] isRunning];
|
||||
return enabled;
|
||||
}
|
||||
if (action == @selector(getCurrentiTunesSong:)) {
|
||||
return [iTunes isRunning];
|
||||
return [[ilyrics iTunes] isRunning];
|
||||
}
|
||||
if (action == @selector(getCurrentSpotifySong:)) {
|
||||
return [spotify isRunning];
|
||||
return [[ilyrics spotify] isRunning];
|
||||
}
|
||||
if (action == @selector(showPreview:)) {
|
||||
return [resultsOutline clickedRow] >= 0;
|
||||
}
|
||||
if (action == @selector(showLyricsInBrowser:)) {
|
||||
if ([resultsOutline clickedRow] >= 0) {
|
||||
return YES;
|
||||
SearchResult *result = [loadedResults objectAtIndex:[resultsOutline clickedRow]];
|
||||
return [[result loadedByHoster] canShowInBrowser:result];;
|
||||
} else if ([resultsOutline selectedRow] >= 0) {
|
||||
return YES;
|
||||
SearchResult *result = [loadedResults objectAtIndex:[resultsOutline selectedRow]];
|
||||
return [[result loadedByHoster] canShowInBrowser:result];;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -11,20 +11,16 @@
|
||||
#import "PreferencesWindow.h"
|
||||
#import "AutoLyrics.h"
|
||||
|
||||
@interface PreferencesController : NSObject <NSWindowDelegate, NSTableViewDataSource>
|
||||
@interface PreferencesController : NSObject <NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate>
|
||||
|
||||
@property (unsafe_unretained) IBOutlet PreferencesWindow *preferencesWindow;
|
||||
@property (weak) IBOutlet NSToolbarItem *generalButton;
|
||||
@property (weak) IBOutlet NSTableView *hosterTable;
|
||||
@property NSArray *hosters;
|
||||
@property (weak) IBOutlet NSView *generalView;
|
||||
@property (weak) IBOutlet NSView *autoLyricsView;
|
||||
@property (weak) IBOutlet NSButton *toggleAutoLyricsButton;
|
||||
@property (weak) IBOutlet NSButton *replaceOldCheckBox;
|
||||
|
||||
-(void) addHoster: (id<LyricsHoster>) hoster;
|
||||
-(void) removeHoster: (id<LyricsHoster>) hoster;
|
||||
|
||||
- (IBAction)showGeneralPreferences:(id)sender;
|
||||
- (IBAction)showAutoLyricsPreferences:(id)sender;
|
||||
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
//TODO: Implement Auto-Lyricds Interval
|
||||
//TODO: Set the title of the window when the toolbar button selection changed
|
||||
//TODO:
|
||||
|
||||
#import "PreferencesController.h"
|
||||
#import "iLyrics.h"
|
||||
|
||||
@implementation PreferencesController {
|
||||
NSMutableArray *hosters;
|
||||
AutoLyrics *autoLyrics;
|
||||
iLyrics *ilyrics;
|
||||
}
|
||||
@synthesize generalView;
|
||||
@synthesize autoLyricsView;
|
||||
@@ -23,14 +24,15 @@
|
||||
@synthesize hosterTable;
|
||||
|
||||
-(id)init {
|
||||
ilyrics = [iLyrics sharediLyrics];
|
||||
autoLyrics = [AutoLyrics autoLyrics];
|
||||
hosters = [[NSMutableArray alloc] init];
|
||||
return [super init];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Window Delegate Methods
|
||||
|
||||
#define HosterDataType @"HosterDataType"
|
||||
-(void)awakeFromNib {
|
||||
if ([autoLyrics enabled]) {
|
||||
[self enableAutoLyrics:toggleAutoLyricsButton];
|
||||
@@ -44,37 +46,19 @@
|
||||
}
|
||||
[[preferencesWindow toolbar] setSelectedItemIdentifier:@"general"];
|
||||
[self showGeneralPreferences:nil];
|
||||
[hosterTable registerForDraggedTypes:[NSArray arrayWithObject:HosterDataType]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Properties
|
||||
|
||||
-(NSArray *)hosters {
|
||||
return hosters;
|
||||
}
|
||||
|
||||
-(void)setHosters:(NSArray *)hstrs {
|
||||
hosters = [NSMutableArray arrayWithArray:hstrs];
|
||||
[hosterTable reloadData];
|
||||
}
|
||||
|
||||
#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 {
|
||||
[preferencesWindow setTitle:NSLocalizedString(@"iLyrics.preferences.text.general", @"")];
|
||||
[self changeContentViewTo:generalView];
|
||||
}
|
||||
|
||||
-(IBAction)showAutoLyricsPreferences:(id)sender {
|
||||
[preferencesWindow setTitle:NSLocalizedString(@"iLyrics.preferences.text.auto-lyrics", @"")];
|
||||
[self changeContentViewTo:autoLyricsView];
|
||||
}
|
||||
|
||||
@@ -88,12 +72,12 @@
|
||||
|
||||
-(void)enableAutoLyrics: (id) sender{
|
||||
[autoLyrics setEnabled:YES];
|
||||
[sender setTitle:NSLocalizedString(@"iLyrics.text.disableAutoLyrics", @"")];
|
||||
[sender setTitle:NSLocalizedString(@"iLyrics.preferences.text.disableAutoLyrics", @"")];
|
||||
}
|
||||
|
||||
-(void)disableAutoLyrics: (id) sender {
|
||||
[autoLyrics setEnabled:NO];
|
||||
[sender setTitle:NSLocalizedString(@"iLyrics.text.enableAutoLyrics", @"")];
|
||||
[sender setTitle:NSLocalizedString(@"iLyrics.preferences.text.enableAutoLyrics", @"")];
|
||||
}
|
||||
|
||||
- (IBAction)changeAutoLyricsInterval:(id)sender {
|
||||
@@ -112,18 +96,61 @@
|
||||
#pragma mark -
|
||||
#pragma mark Table Data Source
|
||||
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
|
||||
return [hosters count];
|
||||
return [[ilyrics lyricsHosters] count];
|
||||
}
|
||||
|
||||
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
||||
id<LyricsHoster> hoster = [[ilyrics lyricsHosters] objectAtIndex:row];
|
||||
if ([[tableColumn identifier] isEqualToString:@"hoster"]) {
|
||||
return [[hosters objectAtIndex:row] name];
|
||||
return [hoster name];
|
||||
} else {
|
||||
NSDate *version = [[hosters objectAtIndex:row] hosterVersion];
|
||||
NSDate *version = [hoster hosterVersion];
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setDateStyle:NSDateFormatterLongStyle];
|
||||
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
|
||||
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
|
||||
|
||||
@@ -7,14 +7,16 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LyricsHoster.h"
|
||||
|
||||
@interface SearchResult : NSObject
|
||||
@property NSString *name;
|
||||
@property NSString *artist;
|
||||
@property NSString *preview;
|
||||
@property id<LyricsHoster> loadedByHoster;
|
||||
@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
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
@synthesize name;
|
||||
@synthesize artist;
|
||||
@synthesize preview;
|
||||
@synthesize loadedByHoster;
|
||||
@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;
|
||||
artist = art;
|
||||
preview = pre;
|
||||
link = l;
|
||||
loadedByHoster = hoster;
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
14
iLyrics/Songtexte.h
Normal file
14
iLyrics/Songtexte.h
Normal 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
153
iLyrics/Songtexte.m
Normal 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
@@ -17,11 +17,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.1</string>
|
||||
<string>1.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>10</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.music</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
38
iLyrics/iLyrics.h
Normal file
38
iLyrics/iLyrics.h
Normal 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
78
iLyrics/iLyrics.m
Normal 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
|
||||
Reference in New Issue
Block a user