1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
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. *
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. *
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 ***************************************************************************/
23 #ifdef HAVE_CURL_CURL_H
28 # include <sys/stat.h>
30 # include "curl/curl.h"
37 #include "media_library.h"
39 #include "playlist_editor.h"
40 #include "search_engine.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;
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
},
78 w
= new Scrollpad(0, MainStartY
, COLS
, MainHeight
, "", Config
.main_color
, brNone
);
84 w
->Resize(COLS
, MainHeight
);
85 w
->MoveTo(0, MainStartY
);
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)
99 pthread_join(*Downloader
, 0);
106 #endif // HAVE_CURL_CURL_H && HAVE_PTHREAD_H
110 if (myScreen
== this)
112 myOldScreen
->SwitchTo();
119 MPD::Song
*s
= myScreen
->CurrentSong();
127 myOldScreen
= myScreen
;
129 Global::RedrawHeader
= 1;
130 itsTitle
= "Song info";
139 #ifdef HAVE_CURL_CURL_H
141 void Info::GetArtist()
143 if (myScreen
== this)
145 myOldScreen
->SwitchTo();
152 # ifdef HAVE_PTHREAD_H
153 if (Downloader
&& !ArtistReady
)
155 ShowMessage("Artist info is being downloaded...");
158 else if (ArtistReady
)
160 # endif // HAVE_PTHREAD_H
162 MPD::Song
*s
= myScreen
->CurrentSong();
164 if (!s
&& myScreen
->ActiveWindow() != myLibrary
->Artists
)
167 itsArtist
= !s
? myLibrary
->Artists
->Current() : s
->GetArtist();
169 if (itsArtist
.empty())
174 myOldScreen
= myScreen
;
176 Global::RedrawHeader
= 1;
177 itsTitle
= "Artist info - " + itsArtist
;
180 static_cast<Window
&>(*w
) << "Fetching artist info...";
181 w
->Window::Refresh();
182 # ifdef HAVE_PTHREAD_H
184 # endif // HAVE_PTHREAD_H
186 locale_to_utf(itsArtist
);
188 std::string file
= itsArtist
+ ".txt";
190 EscapeUnallowedChars(file
);
192 itsFilenamePath
= Folder
+ "/" + file
;
200 std::ifstream
input(itsFilenamePath
.c_str());
205 while (getline(input
, line
))
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();
222 # ifdef HAVE_PTHREAD_H
223 Downloader
= new pthread_t
;
224 pthread_create(Downloader
, 0, PrepareArtist
, this);
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=";
241 url
+= "&api_key=d94e5b6e26469a2d1ffae8ef20131b79";
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
);
259 if (code
!= CURLE_OK
)
261 *screen
->w
<< "Error while fetching artist's info: " << curl_easy_strerror(code
);
269 a
= result
.find("status=\"failed\"");
271 if (a
!= std::string::npos
)
274 *screen
->w
<< "Last.fm returned an error message: " << result
;
279 std::vector
<std::string
> similar
;
280 for (size_t i
= result
.find("<name>"); i
!= std::string::npos
; i
= result
.find("<name>"))
283 size_t j
= result
.find("</name>");
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>"))
293 size_t j
= result
.find("</url>");
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
)
310 *screen
->w
<< "Error: Fetched data could not be parsed";
317 result
= "No description available for this artist.";
322 a
+= static_strlen("<![CDATA[");
323 b
-= static_strlen("]]>");
324 result
= result
.substr(a
, b
-a
);
330 std::ostringstream filebuffer
;
332 filebuffer
<< result
;
333 utf_to_locale(result
);
334 *screen
->w
<< result
;
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
)
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
] << ")";
349 filebuffer
<< "\n\n" << urls
.front();
350 utf_to_locale(urls
.front());
351 *screen
->w
<< "\n\n" << urls
.front();
355 std::ofstream
output(screen
->itsFilenamePath
.c_str());
356 if (output
.is_open())
358 output
<< filebuffer
.str();
365 #endif // HVAE_CURL_CURL_H
367 void Info::PrepareSong(MPD::Song
&s
)
369 # ifdef HAVE_TAGLIB_H
370 std::string path_to_file
;
372 path_to_file
+= Config
.mpd_music_dir
;
373 path_to_file
+= s
.GetFile();
374 TagLib::FileRef
f(path_to_file
.c_str());
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
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
394 for (const Metadata
*m
= Tags
; m
->Name
; ++m
)
396 *w
<< fmtBold
<< "\n" << m
->Name
<< ": " << fmtBoldEnd
;
397 ShowTag(*w
, s
.GetTags(m
->Get
));