get rid of case sensivity switch in search engine
[ncmpcpp.git] / src / info.cpp
blob2bf40c3769c0e0c619315323df3884f9f85a42f0
1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "info.h"
23 #ifdef HAVE_CURL_CURL_H
24 # include <fstream>
25 # ifdef WIN32
26 # include <io.h>
27 # else
28 # include <sys/stat.h>
29 # endif // WIN32
30 # include "curl/curl.h"
31 # include "helpers.h"
32 #endif
34 #include "browser.h"
35 #include "charset.h"
36 #include "global.h"
37 #include "media_library.h"
38 #include "playlist.h"
39 #include "playlist_editor.h"
40 #include "search_engine.h"
41 #include "status.h"
42 #include "tag_editor.h"
44 using Global::MainHeight;
45 using Global::MainStartY;
46 using Global::myScreen;
47 using Global::myOldScreen;
49 #ifdef HAVE_CURL_CURL_H
50 const std::string Info::Folder = home_path + HOME_FOLDER"artists";
51 bool Info::ArtistReady = 0;
53 #ifdef HAVE_PTHREAD_H
54 pthread_t *Info::Downloader = 0;
55 #endif // HAVE_PTHREAD_H
57 #endif // HAVE_CURL_CURL_H
59 Info *myInfo = new Info;
61 const Info::Metadata Info::Tags[] =
63 { "Title", &MPD::Song::GetTitle, &MPD::Song::SetTitle },
64 { "Artist", &MPD::Song::GetArtist, &MPD::Song::SetArtist },
65 { "Album", &MPD::Song::GetAlbum, &MPD::Song::SetAlbum },
66 { "Year", &MPD::Song::GetDate, &MPD::Song::SetDate },
67 { "Track", &MPD::Song::GetTrack, &MPD::Song::SetTrack },
68 { "Genre", &MPD::Song::GetGenre, &MPD::Song::SetGenre },
69 { "Composer", &MPD::Song::GetComposer, &MPD::Song::SetComposer },
70 { "Performer", &MPD::Song::GetPerformer, &MPD::Song::SetPerformer },
71 { "Disc", &MPD::Song::GetDisc, &MPD::Song::SetDisc },
72 { "Comment", &MPD::Song::GetComment, &MPD::Song::SetComment },
73 { 0, 0, 0 }
76 void Info::Init()
78 w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone);
79 isInitialized = 1;
82 void Info::Resize()
84 w->Resize(COLS, MainHeight);
85 w->MoveTo(0, MainStartY);
86 hasToBeResized = 0;
89 std::basic_string<my_char_t> Info::Title()
91 return TO_WSTRING(itsTitle);
94 #if defined(HAVE_CURL_CURL_H) && defined(HAVE_PTHREAD_H)
95 void Info::Update()
97 if (!ArtistReady)
98 return;
99 pthread_join(*Downloader, 0);
100 w->Flush();
101 w->Refresh();
102 delete Downloader;
103 Downloader = 0;
104 ArtistReady = 0;
106 #endif // HAVE_CURL_CURL_H && HAVE_PTHREAD_H
108 void Info::GetSong()
110 if (myScreen == this)
112 myOldScreen->SwitchTo();
114 else
116 if (!isInitialized)
117 Init();
119 MPD::Song *s = myScreen->CurrentSong();
121 if (!s)
122 return;
124 if (hasToBeResized)
125 Resize();
127 myOldScreen = myScreen;
128 myScreen = this;
129 Global::RedrawHeader = 1;
130 itsTitle = "Song info";
131 w->Clear();
132 w->Reset();
133 PrepareSong(*s);
134 w->Window::Clear();
135 w->Flush();
139 #ifdef HAVE_CURL_CURL_H
141 void Info::GetArtist()
143 if (myScreen == this)
145 myOldScreen->SwitchTo();
147 else
149 if (!isInitialized)
150 Init();
152 # ifdef HAVE_PTHREAD_H
153 if (Downloader && !ArtistReady)
155 ShowMessage("Artist info is being downloaded...");
156 return;
158 else if (ArtistReady)
159 Update();
160 # endif // HAVE_PTHREAD_H
162 MPD::Song *s = myScreen->CurrentSong();
164 if (!s && myScreen->ActiveWindow() != myLibrary->Artists)
165 return;
167 itsArtist = !s ? myLibrary->Artists->Current() : s->GetArtist();
169 if (itsArtist.empty())
170 return;
172 if (hasToBeResized)
173 Resize();
174 myOldScreen = myScreen;
175 myScreen = this;
176 Global::RedrawHeader = 1;
177 itsTitle = "Artist info - " + itsArtist;
178 w->Clear();
179 w->Reset();
180 static_cast<Window &>(*w) << "Fetching artist info...";
181 w->Window::Refresh();
182 # ifdef HAVE_PTHREAD_H
183 if (!Downloader)
184 # endif // HAVE_PTHREAD_H
186 locale_to_utf(itsArtist);
188 std::string file = itsArtist + ".txt";
189 ToLower(file);
190 EscapeUnallowedChars(file);
192 itsFilenamePath = Folder + "/" + file;
194 mkdir(Folder.c_str()
195 # ifndef WIN32
196 , 0755
197 # endif // !WIN32
200 std::ifstream input(itsFilenamePath.c_str());
201 if (input.is_open())
203 bool first = 1;
204 std::string line;
205 while (getline(input, line))
207 if (!first)
208 *w << "\n";
209 utf_to_locale(line);
210 *w << line;
211 first = 0;
213 input.close();
214 w->SetFormatting(fmtBold, U("\n\nSimilar artists:\n"), fmtBoldEnd, 0);
215 w->SetFormatting(Config.color2, U("\n * "), clEnd, 1);
216 // below is used so format won't be removed using RemoveFormatting() by accident.
217 w->ForgetFormatting();
218 w->Flush();
220 else
222 # ifdef HAVE_PTHREAD_H
223 Downloader = new pthread_t;
224 pthread_create(Downloader, 0, PrepareArtist, this);
225 # else
226 PrepareArtist(this);
227 w->Flush();
228 # endif // HAVE_PTHREAD_H
234 void *Info::PrepareArtist(void *screen_void_ptr)
236 Info *screen = static_cast<Info *>(screen_void_ptr);
238 char *c_artist = curl_easy_escape(0, screen->itsArtist.c_str(), screen->itsArtist.length());
239 std::string url = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=";
240 url += c_artist;
241 url += "&api_key=d94e5b6e26469a2d1ffae8ef20131b79";
243 std::string result;
244 CURLcode code;
246 pthread_mutex_lock(&Global::CurlLock);
247 CURL *info = curl_easy_init();
248 curl_easy_setopt(info, CURLOPT_URL, url.c_str());
249 curl_easy_setopt(info, CURLOPT_WRITEFUNCTION, write_data);
250 curl_easy_setopt(info, CURLOPT_WRITEDATA, &result);
251 curl_easy_setopt(info, CURLOPT_CONNECTTIMEOUT, 10);
252 curl_easy_setopt(info, CURLOPT_NOSIGNAL, 1);
253 code = curl_easy_perform(info);
254 curl_easy_cleanup(info);
255 pthread_mutex_unlock(&Global::CurlLock);
257 curl_free(c_artist);
259 if (code != CURLE_OK)
261 *screen->w << "Error while fetching artist's info: " << curl_easy_strerror(code);
262 ArtistReady = 1;
263 pthread_exit(0);
266 size_t a, b;
267 bool save = 1;
269 a = result.find("status=\"failed\"");
271 if (a != std::string::npos)
273 EscapeHtml(result);
274 *screen->w << "Last.fm returned an error message: " << result;
275 ArtistReady = 1;
276 pthread_exit(0);
279 std::vector<std::string> similar;
280 for (size_t i = result.find("<name>"); i != std::string::npos; i = result.find("<name>"))
282 result[i] = '.';
283 size_t j = result.find("</name>");
284 result[j] = '.';
285 i += static_strlen("<name>");
286 similar.push_back(result.substr(i, j-i));
287 EscapeHtml(similar.back());
289 std::vector<std::string> urls;
290 for (size_t i = result.find("<url>"); i != std::string::npos; i = result.find("<url>"))
292 result[i] = '.';
293 size_t j = result.find("</url>");
294 result[j] = '.';
295 i += static_strlen("<url>");
296 urls.push_back(result.substr(i, j-i));
299 bool parse_failed = 0;
300 if ((a = result.find("<content>")) != std::string::npos)
302 a += static_strlen("<content>");
303 if ((b = result.find("</content>")) == std::string::npos)
304 parse_failed = 1;
306 else
307 parse_failed = 1;
308 if (parse_failed)
310 *screen->w << "Error: Fetched data could not be parsed";
311 ArtistReady = 1;
312 pthread_exit(0);
315 if (a == b)
317 result = "No description available for this artist.";
318 save = 0;
320 else
322 a += static_strlen("<![CDATA[");
323 b -= static_strlen("]]>");
324 result = result.substr(a, b-a);
327 EscapeHtml(result);
328 Trim(result);
330 std::ostringstream filebuffer;
331 if (save)
332 filebuffer << result;
333 utf_to_locale(result);
334 *screen->w << result;
336 if (save)
337 filebuffer << "\n\nSimilar artists:\n";
338 *screen->w << fmtBold << "\n\nSimilar artists:\n" << fmtBoldEnd;
339 for (size_t i = 1; i < similar.size(); ++i)
341 if (save)
342 filebuffer << "\n * " << similar[i] << " (" << urls[i] << ")";
343 utf_to_locale(similar[i]);
344 utf_to_locale(urls[i]);
345 *screen->w << "\n" << Config.color2 << " * " << clEnd << similar[i] << " (" << urls[i] << ")";
348 if (save)
349 filebuffer << "\n\n" << urls.front();
350 utf_to_locale(urls.front());
351 *screen->w << "\n\n" << urls.front();
353 if (save)
355 std::ofstream output(screen->itsFilenamePath.c_str());
356 if (output.is_open())
358 output << filebuffer.str();
359 output.close();
362 ArtistReady = 1;
363 pthread_exit(0);
365 #endif // HVAE_CURL_CURL_H
367 void Info::PrepareSong(MPD::Song &s)
369 # ifdef HAVE_TAGLIB_H
370 std::string path_to_file;
371 if (s.isFromDB())
372 path_to_file += Config.mpd_music_dir;
373 path_to_file += s.GetFile();
374 TagLib::FileRef f(path_to_file.c_str());
375 if (!f.isNull())
376 s.SetComment(f.tag()->comment().to8Bit(1));
377 # endif // HAVE_TAGLIB_H
379 *w << fmtBold << Config.color1 << "Filename: " << fmtBoldEnd << Config.color2 << s.GetName() << "\n" << clEnd;
380 *w << fmtBold << "Directory: " << fmtBoldEnd << Config.color2;
381 ShowTag(*w, s.GetDirectory());
382 *w << "\n\n" << clEnd;
383 *w << fmtBold << "Length: " << fmtBoldEnd << Config.color2 << s.GetLength() << "\n" << clEnd;
384 # ifdef HAVE_TAGLIB_H
385 if (!f.isNull())
387 *w << fmtBold << "Bitrate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->bitrate() << " kbps\n" << clEnd;
388 *w << fmtBold << "Sample rate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->sampleRate() << " Hz\n" << clEnd;
389 *w << fmtBold << "Channels: " << fmtBoldEnd << Config.color2 << (f.audioProperties()->channels() == 1 ? "Mono" : "Stereo") << "\n" << clDefault;
391 # endif // HAVE_TAGLIB_H
392 *w << clDefault;
394 for (const Metadata *m = Tags; m->Name; ++m)
396 *w << fmtBold << "\n" << m->Name << ": " << fmtBoldEnd;
397 ShowTag(*w, s.GetTags(m->Get));