Added reading saves
[maelyrica:maelyrica.git] / lyricsDownloader.cpp
1 /* File: lyricsDownloader.cpp
2  *
3  * This file is part of MaeLyrica.
4  *
5  * Copyright (C) 2012 Marcin Mielniczuk.
6  *
7  * MaeLyrica is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, version 3 of the License.
10  *
11  * MaeLyrica is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  *  along with MaeLyrica.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "lyricsDownloader.h"
21 #include <curl/curl.h>
22 #include <QDebug>
23 #include <iostream>
24 #include <QFile>
25 #include <QSettings>
26
27 using namespace std;
28
29 #define DEBUG 1
30
31 /////////////////////////////////////////////////////////////////////////////
32
33 const QString lyricsDownloader::OMPLyricsRoot("/home/user/.lyrics/");
34
35 QSettings lyricsDownloader::progSettings("Marcin Mielniczuk", "MaeLyrica");
36
37 inline void lyricsDownloader::setData(const string &a, const string &t)
38 {
39     artist = a;
40     track = t;
41 }
42
43 size_t lyricsDownloader::write_data_to_var(char *ptr, size_t size, size_t nmemb, void *userdata)
44 {
45     ostringstream * stream = (ostringstream*) userdata;
46     size_t count = size * nmemb;
47     stream->write(ptr, count);
48     return count;
49 }
50
51 QString lyricsDownloader::cleanQString(const QString qstr)
52 {
53     return qstr.toLower().replace("&", "and").remove(QRegExp("\\([^)]*\\)")).remove(QRegExp("[\\W_]"));
54 }
55
56 void lyricsDownloader::cleanTitle()
57 {
58     cleanedTitle = cleanQString( QString::fromStdString(artist));
59     cleanedTitle += "-";
60     cleanedTitle += cleanQString(QString::fromStdString(track));
61 }
62
63
64 bool lyricsDownloader::lyricsExistOMP()
65 {
66     lyricsUrlOMP = OMPLyricsRoot + cleanedTitle + ".txt";
67     return QFile(lyricsUrlOMP).exists();
68 }
69
70 bool lyricsDownloader::saveLyricsMaeLyrica()
71 {
72     QSettings("Marcin Mielniczuk", "MaeLyrica").setValue("lyrics/" + cleanedTitle, lyrics);
73     return true;
74 }
75
76 bool lyricsDownloader::saveLyricsOMP() // TODO finish
77 {
78     QFile lyricsFile(lyricsUrlOMP);
79     if (! lyricsFile.open(QIODevice::WriteOnly)) return false;
80     QTextStream lyricsFileStream(&lyricsFile);
81     lyricsFileStream << lyrics;
82     if (lyricsFileStream.status() == QTextStream::Ok) return true;
83     else return false;
84 }
85
86 ///////////////////////////////////////////////////////////////////////////////
87
88 const string AZLyricsDownloader::rooturl("http://azlyrics.com/lyrics");
89 const QRegExp AZLyricsDownloader::endcomment("<!-- end of lyrics -->");
90 const QRegExp AZLyricsDownloader::startcomment("<!-- start of lyrics -->");
91
92
93
94 short AZLyricsDownloader::perform()
95 {
96     CURLcode dlret; // return value from curl
97     dlret = download(); // it doesn't fail yet to recognize
98
99     if ( parse() != 0)
100     {
101         if ( dlret != 0 ) // Error while downloading and parsing means that the lyrics are just not there
102         {
103             qDebug() << "The lyrics are not present in AZLyrics.com database\n";
104             return 3;
105         }
106         qDebug() << "Error while parsing lyrics\n";
107         return 2;
108     }
109     if (dlret != 0) // just error while downloading
110     {
111         qDebug() << "Error while downloading lyrics\n";
112         return 1;
113     }
114
115     //qDebug() << lyrics();
116     emit lyricsChanged(lyrics);
117     return 0;
118 }
119
120 string AZLyricsDownloader::toProviderCode() const
121 {
122     string artist_www, track_www;
123     //overrides
124     if (artist == "The Offspring")
125         artist_www = "offspring";
126     else // normal case
127     {
128         int length = artist.length(); // lenght of a parameter
129         string::const_iterator cptr = artist.begin();
130         for (int i = 0; i < length; i++, cptr++)
131         {
132             if ( isalnum(*cptr) == false ) continue; // non alphanumeric, skip
133             artist_www += tolower(*cptr);
134         }
135     }
136     // here may be overrides for tracks
137         int length = track.length();
138         const char * cptr = &track[0];
139         for (int i = 0; i < length; i++, cptr++)
140         {
141             if ( isalnum(*cptr) == false ) continue;
142             track_www += tolower(*cptr);
143         }
144
145         return (rooturl + "/" + artist_www + "/" + track_www + ".html");
146
147 }
148
149 CURLcode AZLyricsDownloader::download()
150 {
151     CURL * handle;
152     CURLcode err;
153     ostringstream buff;
154     lyrics_str = new string;
155     handle = curl_easy_init();
156     if (! handle) return static_cast<CURLcode>(-1);
157     // set verbose if debug on
158     curl_easy_setopt( handle, CURLOPT_VERBOSE, DEBUG );
159     curl_easy_setopt( handle, CURLOPT_URL, toProviderCode().c_str() ); // set the download url to the generated one
160     curl_easy_setopt(handle, CURLOPT_WRITEDATA, &buff);
161     curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &AZLyricsDownloader::write_data_to_var); // set the function writing to ostringstream
162     curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); // curl needs to follow redirects with this provider
163     curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);
164     err = curl_easy_perform(handle);
165     curl_easy_cleanup(handle);
166
167     // copy the contents to text variable
168     *lyrics_str = buff.str();
169     return err;
170 }
171
172 bool AZLyricsDownloader::parse()
173 {
174     istringstream temp(*lyrics_str);
175     delete lyrics_str;
176     lyrics_str = 0;
177     string line;
178     QString lyrics_QStr, line_QStr;
179     while ( temp.good() ) // looking for comment about starting lyrics
180     {
181         getline(temp, line);
182         if (QString::fromStdString(line).contains(startcomment)) break;
183     }
184     if ( !temp.good() ) return 1; // something went wrong, returning blank string
185     // get every line until endcomment
186     while ( temp.good() )
187     {
188         getline(temp, line);
189         if (( line_QStr = QString::fromStdString(line) ).contains(endcomment)) break;
190         lyrics_QStr += line_QStr.remove(QRegExp("<br[ ]{0,1}[/]{0,1}>"));
191         lyrics_QStr += "\n";
192     }
193     if ( !temp.good() ) return 1; // something went wrong, returning blank string
194
195     lyrics = lyrics_QStr; // after parsing all the work will be done using QStrings
196     return 0;
197 }