diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 5c0ddbed4..3412fb15d 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -820,6 +820,24 @@ imageinfo.kernel Kernel: imageinfo.license Lizenz imageinfo.vcs Git: imageinfo.version Version: +imdb.data_actors Darsteller +imdb.data_awards Awards +imdb.data_boxoffice Einspielergebnis +imdb.data_director Regisseur +imdb.data_failed Keine Daten gefunden +imdb.data_genre Genre +imdb.data_metascore Metascore +imdb.data_plot Handlung +imdb.data_production Produktion +imdb.data_rating_failed Keine Bewertung +imdb.data_released Veröffentlicht +imdb.data_runtime Spieldauer +imdb.data_title Originaltitel +imdb.data_votes Stimmen +imdb.data_website Webseite +imdb.data_writer Drehbuchautor +imdb.info IMDb-Info +imdb.info_save Bild speichern inetradio.name Internetradio infoviewer.epgnotload Informationen noch nicht geladen ... infoviewer.epgwait Warte auf EPG-Informationen ... @@ -1723,6 +1741,7 @@ moviebrowser.hint_movieend Filmende in 5 Sekunden\n'0' zum Weitersehen moviebrowser.hint_newbook_backward Neue Wiederholung gestartet.\n'%s' bestimmt die Endposition, '0' bricht ab. moviebrowser.hint_newbook_forward Neuer Werbesprung gestartet.\n'%s' bestimmt die Endposition, '0' bricht ab. moviebrowser.hint_truncate Entfernt den Filmteil hinter der Filmende-Markierung +moviebrowser.imdb_data Lade IMDb-Daten moviebrowser.info_audio Audio moviebrowser.info_channel Kanal moviebrowser.info_file Datei @@ -2431,6 +2450,7 @@ timing.static_messages Interaktive Meldungen timing.volumebar Lautstärkeanzeige tmdb.api_key TMDb API Schlüssel tmdb.enabled TMDb-Unterstützung +tmdb.info TMDb-Info tmdb.read_data Suche TMDb-Daten ... tunersetup.cable Kabel (DVB-C) tunersetup.hybrid Hybrid (DVB-C/T/T2) diff --git a/data/locale/english.locale b/data/locale/english.locale index 5092c6661..93465d892 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -820,6 +820,24 @@ imageinfo.kernel Kernel: imageinfo.license License imageinfo.vcs Git: imageinfo.version Version: +imdb.data_actors Actors +imdb.data_awards Awards +imdb.data_boxoffice Boxoffice +imdb.data_director Director +imdb.data_failed No data found +imdb.data_genre Genre +imdb.data_metascore Metascore +imdb.data_plot Plot +imdb.data_production Production +imdb.data_rating_failed No rating +imdb.data_released Released +imdb.data_runtime Runtime +imdb.data_title Original title +imdb.data_votes Votes +imdb.data_website Website +imdb.data_writer Screenplay author +imdb.info IMDb-Info +imdb.info_save save Cover inetradio.name Internetradio infoviewer.epgnotload EPG not loaded ... infoviewer.epgwait waiting for EPG ... @@ -1723,6 +1741,7 @@ moviebrowser.hint_movieend Film end in 5 seconds\n'0' to cancel moviebrowser.hint_newbook_backward New jump back started\n'%s' to define endposition, '0' to cancel moviebrowser.hint_newbook_forward New jump forward started\n'%s' to define endposition, '0' to cancel moviebrowser.hint_truncate Truncating all data beyond the end-bookmark +moviebrowser.imdb_data Get IMDb data moviebrowser.info_audio Audio moviebrowser.info_channel Channel moviebrowser.info_file File @@ -2431,6 +2450,7 @@ timing.static_messages Interactive messages timing.volumebar Volume bar tmdb.api_key TMDb API key tmdb.enabled TMDb support +tmdb.info TMDb-Info tmdb.read_data Search TMDb data ... tunersetup.cable Cable (DVB-C) tunersetup.hybrid Hybrid (DVB-C/T/T2) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 9d19d6caf..07fdab156 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -62,6 +62,7 @@ libneutrino_gui_a_SOURCES = \ filebrowser.cpp \ followscreenings.cpp \ imageinfo.cpp \ + imdb.cpp \ info_menue.cpp \ infoviewer.cpp \ infoviewer_bb.cpp \ diff --git a/src/gui/epgview.cpp b/src/gui/epgview.cpp index acaedcdce..ee235cb3b 100644 --- a/src/gui/epgview.cpp +++ b/src/gui/epgview.cpp @@ -129,6 +129,11 @@ CEpgData::CEpgData() Bottombox = NULL; pb = NULL; font_title = NULL; + + + imdb = CIMDB::getInstance(); + imdb_active = false; + movie_filename.clear(); } CEpgData::~CEpgData() @@ -141,7 +146,7 @@ void CEpgData::start() ox = frameBuffer->getWindowWidth(bigFonts ? false /* big */ : true /* small */); oy = frameBuffer->getWindowHeight(bigFonts ? false /* big */ : true /* small */); - font_title = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_TITLE]; + font_title = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]; topheight = font_title->getHeight(); topboxheight = topheight + 6; botboxheight = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->getHeight() + 2*OFFSET_INNER_MIN; @@ -249,6 +254,9 @@ void CEpgData::showText(int startPos, int ypos, bool has_cover, bool fullClear) if (has_cover) { + if (imdb_active) + cover = imdb->posterfile; + g_PicViewer->getSize(cover.c_str(), &cover_width, &cover_height); if (cover_width && cover_height) { @@ -263,6 +271,7 @@ void CEpgData::showText(int startPos, int ypos, bool has_cover, bool fullClear) int offset = 0, count = 0; int max_mon_w = 0, max_wday_w = 0; int digi = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->getRenderWidth("29.."); + for(int i = 0; i < 12;i++){ max_mon_w = std::max(max_mon_w, g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->getRenderWidth(std::string(g_Locale->getText(CLocaleManager::getMonth(i))) + " ")); if(i > 6) @@ -273,7 +282,7 @@ void CEpgData::showText(int startPos, int ypos, bool has_cover, bool fullClear) frameBuffer->paintBoxRel(sx+offs, y, ox-SCROLLBAR_WIDTH-offs, sb, COL_MENUCONTENT_PLUS_0); // background of the text box if (has_cover) { - if (!g_PicViewer->DisplayImage(cover ,sx+OFFSET_INNER_MID ,y+OFFSET_INNER_MID+((sb-cover_height)/2), cover_width, cover_height, CFrameBuffer::TM_NONE)) { + if (!g_PicViewer->DisplayImage(cover ,sx+OFFSET_INNER_MID ,y+OFFSET_INNER_MID, cover_width, cover_height, CFrameBuffer::TM_NONE)) { cover_offset = 0; frameBuffer->paintBoxRel(sx, y, ox-SCROLLBAR_WIDTH, sb, COL_MENUCONTENT_PLUS_0); // background of the text box } @@ -287,6 +296,14 @@ void CEpgData::showText(int startPos, int ypos, bool has_cover, bool fullClear) frameBuffer->paintIcon(NEUTRINO_ICON_TMDB, sx+OFFSET_INNER_MID+cover_offset, y+(medlineheight-icon_h)/2); logo_offset = icon_w + OFFSET_INNER_MID; } + + if (imdb_active && startPos == 0) + { + frameBuffer->getIconSize(NEUTRINO_ICON_IMDB, &icon_w, &icon_h); + frameBuffer->paintIcon(NEUTRINO_ICON_IMDB, sx+OFFSET_INNER_MID+cover_offset, y+(medlineheight-icon_h)/2); + logo_offset = icon_w + OFFSET_INNER_MID; + } + if (stars > 0 && startPos == 0) { frameBuffer->getIconSize(NEUTRINO_ICON_STAR_OFF, &icon_w, &icon_h); @@ -295,6 +312,29 @@ void CEpgData::showText(int startPos, int ypos, bool has_cover, bool fullClear) for (int i = 0; i < stars; i++) frameBuffer->paintIcon(NEUTRINO_ICON_STAR_ON, sx+10+cover_offset+logo_offset + i*(icon_w+3), y+(medlineheight-icon_h)/2); } +#if 0 + if ((stars > 0 || imdb_stars > 0) && (tmdb_active || imdb_active) && startPos == 0) + { + if (stars <= 10) + stars *= 10; // recalculate stars value for starbar + + int stars_w = 0, stars_h = 0; + frameBuffer->getIconSize(NEUTRINO_ICON_STARS_BG, &stars_w, &stars_h); + + //create starbar item + CProgressBar *cc_starbar = new CProgressBar(); + cc_starbar->setProgress(sx+OFFSET_INNER_MID+cover_offset+logo_offset, y+(medlineheight-stars_h)/2, stars_w, medlineheight, imdb_active ? imdb_stars : stars, 100); + cc_starbar->setType(CProgressBar::PB_STARBAR); + cc_starbar->paint(); + + if (imdb_active) + { + int _x = sx+OFFSET_INNER_MID+cover_offset+logo_offset+cc_starbar->getWidth()+OFFSET_INNER_MID; + int _w = ox-OFFSET_INNER_MID-cover_offset-logo_offset-cc_starbar->getWidth()-OFFSET_INNER_MID; + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->RenderString(_x, y+medlineheight, _w, imdb_rating, COL_MENUCONTENT_TEXT, 0, true); + } + } +#endif for (int i = startPos; i < textSize && i < startPos + medlinecount; i++, y += medlineheight) { if(epgText[i].second){ @@ -523,6 +563,7 @@ int CEpgData::show_mp(MI_MOVIE_INFO *mi, int mp_position, int mp_duration, bool epgData.title = mp_movie_info->epgTitle; epgData.info1 = mp_movie_info->epgInfo1; epgData.info2 = mp_movie_info->epgInfo2; + movie_filename = mp_movie_info->file.Name; epgData.itemDescriptions.clear(); epgData.items.clear(); @@ -868,7 +909,8 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start header->hideCCItems(); // set channel logo - header->setChannelLogo(channel_id, channel_name); + if (g_settings.channellist_show_channellogo) + header->setChannelLogo(channel_id, channel_name); //paint head header->paint(CC_SAVE_SCREEN_NO); @@ -959,6 +1001,9 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start CNeutrinoApp::getInstance()->handleMsg(msg, data); break; case CRCInput::RC_left: + if(imdb_active) + imdb_active = false; + if ((prev_id != 0) && !call_fromfollowlist && !mp_info) { toph = topboxheight; @@ -967,6 +1012,9 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start } break; case CRCInput::RC_right: + if(imdb_active) + imdb_active = false; + if ((next_id != 0) && !call_fromfollowlist && !mp_info) { toph = topboxheight; @@ -978,7 +1026,7 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start if (showPos+scrollCountgotPoster()), false); } break; case CRCInput::RC_up: @@ -986,7 +1034,7 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start showPos -= scrollCount; if (showPos < 0) showPos = 0; - showText(showPos, sy + toph, tmdb_active, false); + showText(showPos, sy + toph, tmdb_active || (imdb_active && imdb->gotPoster()), false); } break; case CRCInput::RC_page_up: @@ -1121,8 +1169,14 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start printf("timerd not available\n"); } break; - case CRCInput::RC_help: + case CRCInput::RC_0: //imdb { + if (imdb_active) { + imdb_active = false; + showTimerEventBar(true, !mp_info && isCurrentEPG(channel_id), mp_info); //show buttons + epgText = epgText_saved; + textCount = epgText.size(); + } if (g_settings.tmdb_enabled) { showPos = 0; @@ -1140,7 +1194,7 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start processTextToArray(tmdb->CreateEPGText(), 0, tmdb->hasCover()); textCount = epgText.size(); stars = tmdb->getStars(); - showText(showPos, sy + toph, tmdb_active); + showText(showPos, sy + toph, tmdb_active || (imdb_active && imdb->gotPoster())); } else { ShowMsg(LOCALE_MESSAGEBOX_INFO, LOCALE_EPGVIEWER_NODETAILED, CMsgBox::mbrOk , CMsgBox::mbrOk); } @@ -1155,6 +1209,50 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start } break; } + case CRCInput::RC_green: + { + if (tmdb_active) { + tmdb_active = false; + epgText = epgText_saved; + textCount = epgText.size(); + stars=0; + } + if (!imdb_active) + { + //show IMDb info + imdb_active = true; + showIMDb(true); //show splashscreen only + imdb->getIMDb(epgData.title); + showIMDb(); + showTimerEventBar(true, !mp_info && isCurrentEPG(channel_id), mp_info); //show buttons + timeoutEnd = CRCInput::calcTimeoutEnd(timeout); + } + else if (imdb_active && imdb->gotPoster()) + { + imdb_active = false; + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, LOCALE_IMDB_INFO_SAVE); + hintBox->paint(); + + std::string picname; + if (mp_info) + { + size_t _pos; + if ((_pos = movie_filename.rfind(".")) != std::string::npos) + picname = movie_filename.substr(0, _pos) + ".jpg"; + } + else + picname = imdb->getFilename(channel, epgData.eventID); + + CFileHelpers fh; + if (!fh.copyFile(imdb->posterfile.c_str(), picname.c_str(), 0644)) + perror( "IMDb: error copy file" ); + + sleep(2); + hintBox->hide(); + showTimerEventBar(true, !mp_info && isCurrentEPG(channel_id), mp_info); //show buttons + } + break; + } case CRCInput::RC_yellow: { if (!mp_info) @@ -1163,6 +1261,14 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start { CAdZapMenu::getInstance()->exec(NULL, "enable"); loop = false; + + std::string tmp_msg; + tmp_msg = g_Locale->getText(LOCALE_WORD_IN); + tmp_msg += " "; + tmp_msg += to_string(g_settings.adzap_zapBackPeriod / 60); + tmp_msg += " "; + tmp_msg += g_Locale->getText(LOCALE_UNIT_SHORT_MINUTE); + ShowMsg(LOCALE_ADZAP, tmp_msg, CMsgBox::mbrBack, CMsgBox::mbBack, NEUTRINO_ICON_INFO); } //CTimerdClient timerdclient; else if (g_Timerd->isTimerdAvailable()) @@ -1182,6 +1288,9 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start } case CRCInput::RC_blue: { + if(imdb_active) + imdb_active = false; + if(!followlist.empty() && !call_fromfollowlist){ hide(); time_t tmp_sZeit = epgData.epg_times.startzeit; @@ -1208,6 +1317,8 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start bigFonts = bigFonts ? false : true; ResetModules(); frameBuffer->paintBackgroundBoxRel(sx, sy, ox, oy); + tmdb_active = false; // reset tmdb + imdb_active = false; // reset imdb showTimerEventBar (false); start(); // textypos = sy; @@ -1228,6 +1339,7 @@ int CEpgData::show(const t_channel_id channel_id, uint64_t a_id, time_t* a_start show(channel_id, id, &startzeit, false, call_fromfollowlist); showPos=0; break; + case CRCInput::RC_help: case CRCInput::RC_ok: case CRCInput::RC_timeout: if(fader.StartFadeOut()) { @@ -1286,6 +1398,10 @@ void CEpgData::hide() frameBuffer->paintBackgroundBoxRel(sx, sy, ox, oy); showTimerEventBar (false); + + // imdb + imdb_active = false; + imdb->cleanup(); } void CEpgData::GetEPGData(const t_channel_id channel_id, uint64_t id, time_t* startzeit, bool clear ) @@ -1318,7 +1434,7 @@ void CEpgData::GetEPGData(const t_channel_id channel_id, uint64_t id, time_t* st char temp[20]={0}; strftime( temp, sizeof(temp),"%d.%m.%Y", pStartZeit); epg_date = g_Locale->getText(CLocaleManager::getWeekday(pStartZeit)); - epg_date += "."; + epg_date += ", "; epg_date += temp; strftime( temp, sizeof(temp), "%H:%M", pStartZeit); epg_start= temp; @@ -1449,23 +1565,26 @@ void CEpgData::showProgressBar() // -- 2002-05-13 rasc // -#define EpgButtonsMax 4 -const struct button_label EpgButtons[][EpgButtonsMax] = +#define EpgButtonsMax 5 +struct button_label EpgButtons[][EpgButtonsMax] = { { // full view { NEUTRINO_ICON_BUTTON_RED, LOCALE_TIMERBAR_RECORDEVENT }, + { NEUTRINO_ICON_BUTTON_GREEN, LOCALE_IMDB_INFO }, { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_TIMERBAR_CHANNELSWITCH }, { NEUTRINO_ICON_BUTTON_BLUE, LOCALE_EPGVIEWER_MORE_SCREENINGS_SHORT }, - { NEUTRINO_ICON_BUTTON_INFO_SMALL, LOCALE_CHANNELLIST_ADDITIONAL } + { NEUTRINO_ICON_BUTTON_0, LOCALE_TMDB_INFO } }, { // w/o followscreenings { NEUTRINO_ICON_BUTTON_RED, LOCALE_TIMERBAR_RECORDEVENT }, + { NEUTRINO_ICON_BUTTON_GREEN, LOCALE_IMDB_INFO }, { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_TIMERBAR_CHANNELSWITCH }, - { NEUTRINO_ICON_BUTTON_INFO_SMALL, LOCALE_CHANNELLIST_ADDITIONAL } + { NEUTRINO_ICON_BUTTON_0, LOCALE_TMDB_INFO } }, { // movieplayer mode { NEUTRINO_ICON_BUTTON_RED, LOCALE_EPG_SAVING }, - { NEUTRINO_ICON_BUTTON_INFO_SMALL, LOCALE_CHANNELLIST_ADDITIONAL } + { NEUTRINO_ICON_BUTTON_GREEN, LOCALE_IMDB_INFO }, + { NEUTRINO_ICON_BUTTON_0, LOCALE_TMDB_INFO } } }; @@ -1494,8 +1613,19 @@ void CEpgData::showTimerEventBar (bool pshow, bool adzap, bool mp_info) } bool tmdb = g_settings.tmdb_enabled; bool fscr = (has_follow_screenings && !call_fromfollowlist); + + if (imdb_active) + { + EpgButtons[mp_info ? 2 : (fscr ? 0 : 1)][1].button = (imdb->gotPoster()) ? NEUTRINO_ICON_BUTTON_GREEN : NEUTRINO_ICON_BUTTON_DUMMY_SMALL; + EpgButtons[mp_info ? 2 : (fscr ? 0 : 1)][1].locale = LOCALE_IMDB_INFO_SAVE; + } + else + { + EpgButtons[mp_info ? 2 : (fscr ? 0 : 1)][1].button = NEUTRINO_ICON_BUTTON_GREEN; + EpgButtons[mp_info ? 2 : (fscr ? 0 : 1)][1].locale = LOCALE_IMDB_INFO; + } if (mp_info) - ::paintButtons(x, y, w, tmdb ? 2 : 1, EpgButtons[2], w, h); + ::paintButtons(x, y, w, tmdb ? 3 : 2, EpgButtons[2], w, h); else { int c = EpgButtonsMax; @@ -1504,12 +1634,64 @@ void CEpgData::showTimerEventBar (bool pshow, bool adzap, bool mp_info) if (!fscr) c--; // reduce blue button if (g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) - ::paintButtons(x, y, w, c, EpgButtons[fscr ? 0 : 1], w, h, "", false, COL_MENUFOOT_TEXT, adzap ? adzap_button.c_str() : NULL, 1); + ::paintButtons(x, y, w, c, EpgButtons[fscr ? 0 : 1], w, h, "", false, COL_MENUFOOT_TEXT, adzap ? adzap_button.c_str() : NULL, 2); else - ::paintButtons(x, y, w, c, &EpgButtons[fscr ? 0 : 1][1], w, h, "", false, COL_MENUFOOT_TEXT, adzap ? adzap_button.c_str() : NULL, 0); + ::paintButtons(x, y, w, c, &EpgButtons[fscr ? 0 : 1][1], w, h, "", false, COL_MENUFOOT_TEXT, adzap ? adzap_button.c_str() : NULL, 1); } } +//imdb start +int CEpgData::showIMDb(bool splash) +{ + fontIMDb = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]; + + frameBuffer->paintBoxRel(sx, sy+toph, ox /*- 15*/, sb, COL_MENUCONTENT_PLUS_0); + if (splash) + { + fontIMDb->RenderString(sx+OFFSET_INNER_MID, sy+toph+medlineheight, ox-OFFSET_INNER_MID, "IMDb: Daten werden geladen ...", COL_MENUCONTENT_TEXT, 0, true); + return 0; + } + + //titel + std::string title = imdb->getIMDbElement("Title"); + + if(((title.find(imdb->search_error)) != std::string::npos)) + return 1; + + // clear epg array + epgText_saved = epgText; + epgText.clear(); + + //data + std::string txt; + txt.clear(); + imdb->getIMDbData(txt); + processTextToArray(" ", 0, imdb->gotPoster()); // empty line to get space for the rating stars + processTextToArray(txt, 0, imdb->gotPoster()); + + textCount = epgText.size(); + + //rating + imdb_rating = imdb->getIMDbElement("imdbRating"); + + std::string value = imdb_rating; + if (imdb_rating == "N/A") + { + value = "0"; + imdb_rating = g_Locale->getText(LOCALE_IMDB_DATA_RATING_FAILED); + } + else + imdb_rating += "/10"; + + size_t pos = value.find_first_of(",."); + if (pos != std::string::npos) + value.replace(pos, 1, ""); // change 8,1 or 8.1 to 81 + imdb_stars = atoi(value); + + showText(0, sy + toph, imdb->gotPoster()); + return 0; +} + void CEpgData::ResetModules() { if (header){ diff --git a/src/gui/epgview.h b/src/gui/epgview.h index 313586e11..66a9c68ba 100644 --- a/src/gui/epgview.h +++ b/src/gui/epgview.h @@ -35,6 +35,7 @@ #include +#include #include #include "widget/menue.h" #include "widget/navibar.h" @@ -49,6 +50,8 @@ class CEpgData CChannelEventList evtlist; CChannelEventList followlist; CEPGData epgData; + CIMDB *imdb; + CComponentsHeader *header; CNaviBar *Bottombox; CProgressBar *pb; @@ -94,6 +97,15 @@ class CEpgData void showProgressBar(); bool isCurrentEPG(const t_channel_id channel_id); + + bool imdb_active; + int imdb_stars; + std::string imdb_rating; + std::string epg_title; + std::string movie_filename; + int showIMDb(bool splash = false); + Font *fontIMDb; + public: CEpgData(); diff --git a/src/gui/imdb.cpp b/src/gui/imdb.cpp new file mode 100644 index 000000000..8c024e47d --- /dev/null +++ b/src/gui/imdb.cpp @@ -0,0 +1,475 @@ +/* + imdb + + (C) 2009-2016 NG-Team + (C) 2016 NI-Team + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "imdb.h" + + +CIMDB::CIMDB() +{ + search_url = "http://www.google.de/search?q="; + search_outfile = "/tmp/google.out"; + search_error = "IMDb: Google download failed"; + imdb_url = "http://www.omdbapi.com/?plot=full&r=json&i="; + imdb_outfile = "/tmp/imdb.json"; + omdb_apikey = ""; + posterfile = "/tmp/imdb.jpg"; +} + +CIMDB::~CIMDB() +{ + cleanup(); +} + +CIMDB* CIMDB::getInstance() +{ + static CIMDB* imdb = NULL; + if(!imdb) + imdb = new CIMDB(); + return imdb; +} + +std::string CIMDB::utf82url(std::string s) +{ + std::stringstream ss; + for (size_t i = 0; i < s.length(); ++i) + { + if (unsigned(s[i]) <= ' ') { + ss << '+'; + } + else if (unsigned(s[i]) <= '\x27') { + ss << "%" << std::hex << unsigned(s[i]); + } + else { + ss << s[i]; + } + } + return ss.str(); +} + +std::string CIMDB::parseString(std::string search1, std::string search2, std::string str) +{ + std::string ret, search; + size_t pos_wildcard, pos_firstline, pos_search1, pos_search2; + pos_wildcard = pos_firstline = pos_search1 = pos_search2 = std::string::npos; + + if((pos_wildcard = search1.find('*')) != std::string::npos) + { + search = search1.substr(0, pos_wildcard); + //std::cout << "wildcard detected" << '\t' << "= " << search << "[*]" << search1.substr(pos_wildcard+1) << std::endl; + } + else + search = search1; + + //std::cout << "search1" << "\t\t\t" << "= " << '"' << search << '"' << std::endl; + if((pos_search1 = str.find(search)) != std::string::npos) + { + //std::cout << "search1 found" << "\t\t" << "= " << '"' << search << '"' << " at pos "<< (int)(pos_search1) << " => " << str << std::endl; + + pos_search1 += search.length(); + + if(pos_wildcard != std::string::npos) + { + size_t pos_wildcard_ext; + std::string wildcard_ext = search1.substr(pos_wildcard+1); + + //std::cout << "wildcard_ext" << "\t\t" << "= " << '"' << wildcard_ext << '"' << std::endl; + if((pos_wildcard_ext = str.find(wildcard_ext,pos_wildcard+1)) != std::string::npos) + { + //std::cout << "wildcard_ext found" << "\t" << "= " << '"' << wildcard_ext << '"' << " at pos "<< (int)(pos_wildcard_ext) << " => " << str << std::endl; + pos_search1 = pos_wildcard_ext + wildcard_ext.length(); + } + else + { + //std::cout << "wildcard_ext not found in line " << acc << " - exit" << std::endl; + return(""); + } + } + } + else + { + //std::cout << "search1 not found in line " << acc << " - exit" << std::endl; + return(""); + } + + if(pos_search1 != std::string::npos) + { + //std::cout << "search2 " << "\t\t" << "= " << '"' << search2 << '"' << std::endl; + + if(search2 == "\n") + { + ret = str.substr(pos_search1, str.length() - pos_search1); + return(ret); + } + + if((pos_search2 = str.find(search2, pos_search1)) != std::string::npos) + { + if(search2.empty()) + pos_search2 = str.length(); + + //std::cout << "search2" << "\t\t\t" << "= " << '"' << search2 << '"' << " found at "<< (int)(pos_search2) << " => " << str << std::endl; + ret = str.substr(pos_search1, pos_search2 - pos_search1); + } + //else + //std::cout << "search2 not found in line " << acc << " - exit" << std::endl; + + } + + return(ret); +} + +std::string CIMDB::parseFile(std::string search1, std::string search2, const char* file, std::string firstline, int line_offset) +{ + int line = 0; + acc = 0; + std::ifstream fh; + std::string str, ret, search; + size_t pos_firstline, pos_search1, pos_search2; + pos_firstline = pos_search1 = pos_search2 = std::string::npos; + + if(firstline.empty()) + pos_firstline = 0; + + fh.open(file, std::ios::in); + if(fh.is_open()) + { + while (!fh.eof()) + { + getline(fh, str); + acc++; + + if(pos_firstline == std::string::npos) + { + if((pos_firstline = str.find(firstline)) != std::string::npos) + { + //std::cout << "firstline found " << str << std::endl; + } + continue; + } + + if(line_offset /*&& pos_firstline != std::string::npos*/) + { + if(line+1 != line_offset) + { + line++; + continue; + } + } + + ret = parseString(search1,search2,str); + + if(!ret.empty()) + break; + } + fh.close(); + } + + return(ret); +} + +std::string CIMDB::googleIMDb(std::string s) +{ + CHTTPTool httpTool; + std::string ret = search_error; + std::string search_string("title+"); + char* search_char = (char*) s.c_str(); + + m.clear(); + unlink(search_outfile.c_str()); + unlink(imdb_outfile.c_str()); + unlink(posterfile.c_str()); + + while (*search_char != 0) + { + if (*search_char == ' ') + { + search_string += '+'; + } + else + { + search_string += *search_char; + } + search_char++; + } + + std::string url = search_url + utf82url(search_string) + "%20site:www.imdb.com"; + + if (httpTool.downloadFile(url, search_outfile.c_str())) + { + ret = parseFile("http://www.imdb.com/title/", ">", search_outfile.c_str()); + + if(ret.empty()) + ret = parseFile("http://www.imdb.de/title/", ">", search_outfile.c_str()); + + std::string delimiters = "/&;"; + size_t next = ret.find_first_of(delimiters, 0); + ret = ret.substr(0, next); + } + + return ret; +} + +void CIMDB::initMap( std::map& my ) +{ + std::string errMsg = ""; + Json::Value root; + + std::ostringstream ss; + std::ifstream fh(imdb_outfile.c_str(),std::ifstream::in); + ss << fh.rdbuf(); + std::string filedata = ss.str(); + + bool parsedSuccess = parseJsonFromString(filedata, &root, &errMsg); + + if(!parsedSuccess) + { + std::cout << "Failed to parse JSON\n"; + std::cout << errMsg << std::endl; + + my["Response"] = "False"; // we fake a false response + return; + } + + /* + we grab only what we need to avoid bad surprises + when api is changed + */ + + my["Actors"] = root.get("Actors", "").asString(); + my["Awards"] = root.get("Awards", "").asString(); + my["BoxOffice"] = root.get("BoxOffice", "").asString(); + my["Country"] = root.get("Country", "").asString(); + my["Director"] = root.get("Director", "").asString(); + my["Genre"] = root.get("Genre", "").asString(); + my["imdbID"] = root.get("imdbID", "").asString(); + my["imdbRating"] = root.get("imdbRating", "N/A").asString(); + my["imdbVotes"] = root.get("imdbVotes", "").asString(); + my["Metascore"] = root.get("Metascore", "N/A").asString(); + my["Plot"] = root.get("Plot", "").asString(); + my["Poster"] = root.get("Poster", "N/A").asString(); + my["Production"] = root.get("Production", "").asString(); + my["Released"] = root.get("Released", "").asString(); + my["Response"] = root.get("Response", "False").asString(); + my["Runtime"] = root.get("Runtime", "").asString(); + my["Title"] = root.get("Title", "").asString(); + my["Website"] = root.get("Website", "").asString(); + my["Writer"] = root.get("Writer", "").asString(); + my["Year"] = root.get("Year", "").asString(); + + // currently unused + //my["Rated"] = root.get("Rated", "").asString(); + //my["Type"] = root.get("Type", "").asString(); +} + +int CIMDB::getIMDb(const std::string& epgTitle) +{ + CHTTPTool httpTool; + int ret = 0; + + std::string imdb_id = googleIMDb(epgTitle); + + if(((imdb_id.find(search_error)) != std::string::npos)) + return ret; + + std::string url = imdb_url + imdb_id + omdb_apikey; + + if (httpTool.downloadFile(url, imdb_outfile.c_str())) + { + initMap(m); + + //std::cout << "m now contains " << m.size() << " elements.\n"; + + if(m.empty() || m["Response"]!="True") + return 0; + + //for (std::map::iterator it=m.begin(); it!=m.end(); ++it) + // std::cout << it->first << " => " << it->second << '\n'; + + //download Poster + if(m["Poster"] != "N/A") + { + // if possible load bigger image + std::string origURL ("300"); + std::string replURL ("600"); + + if (m["Poster"].compare(m["Poster"].size()-7,3,origURL) == 0){ + //std::cout << "########## " << m["Poster"] << " contains " << origURL << '\n'; + m["Poster"].replace(m["Poster"].size()-7,3,replURL); + //std::cout << "########## New string: " << m["Poster"] << '\n'; + } + + if (httpTool.downloadFile(m["Poster"], posterfile.c_str())) + return 2; + else { + if (access(posterfile.c_str(), F_OK) == 0) + unlink(posterfile.c_str()); + return 1; + } + } + ret=2; + } + + return ret; +} + +bool CIMDB::checkIMDbElement(std::string element) +{ + if (m[element].empty() || m[element].compare("N/A") == 0) + return false; + else + return true; +} + +void CIMDB::getIMDbData(std::string& txt) +{ + if (m["imdbID"].empty() || m["Response"] != "True") + { + txt = g_Locale->getText(LOCALE_IMDB_DATA_FAILED); + return; + } + + txt += g_Locale->getString(LOCALE_IMDB_DATA_VOTES) + ": " + m["imdbVotes"] + "\n"; + if (checkIMDbElement("Metascore")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_METASCORE) + ": " + m["Metascore"] + "/100\n"; + txt += g_Locale->getString(LOCALE_IMDB_DATA_TITLE) + ": " + m["Title"] + "\n"; + if (checkIMDbElement("Released")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_RELEASED) + ": " + m["Country"] + ", " + m["Released"] + "\n"; + if (checkIMDbElement("Runtime")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_RUNTIME) + ": " + m["Runtime"] + "\n"; + if (checkIMDbElement("Genre")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_GENRE) + ": " + m["Genre"] + "\n"; + if (checkIMDbElement("Awards")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_AWARDS) + ": " + m["Awards"] + "\n"; + if (checkIMDbElement("Director")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_DIRECTOR) + ": " + m["Director"] + "\n"; + if (checkIMDbElement("Writer")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_WRITER) + ": " + m["Writer"] + "\n"; + if (checkIMDbElement("Production")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_PRODUCTION) + ": " + m["Production"] + "\n"; + if (checkIMDbElement("Website")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_WEBSITE) + ": " + m["Website"] + "\n"; + if (checkIMDbElement("BoxOffice")) + txt += g_Locale->getString(LOCALE_IMDB_DATA_BOXOFFICE) + ": " + m["BoxOffice"] + "\n"; + if (checkIMDbElement("Actors")) + { + txt += "\n"; + txt += g_Locale->getString(LOCALE_IMDB_DATA_ACTORS) + ": " + m["Actors"] + "\n"; + } + if (checkIMDbElement("Plot")) + { + txt += "\n"; + txt += g_Locale->getString(LOCALE_IMDB_DATA_PLOT) + ": " + m["Plot"]; + } +} + +std::string CIMDB::getFilename(CZapitChannel * channel, uint64_t id) +{ + char fname[512]; // UTF-8 + char buf[256]; + unsigned int pos = 0; + + if(check_dir(g_settings.network_nfs_recordingdir.c_str())) + return (""); + + snprintf(fname, sizeof(fname), "%s/", g_settings.network_nfs_recordingdir.c_str()); + pos = strlen(fname); + + // %C == channel, %T == title, %I == info1, %d == date, %t == time_t + std::string FilenameTemplate = g_settings.recording_filename_template; + if (FilenameTemplate.empty()) + FilenameTemplate = "%C_%T_%d_%t"; + + StringReplace(FilenameTemplate,"%d",""); + StringReplace(FilenameTemplate,"%t",""); + StringReplace(FilenameTemplate,"__","_"); + + std::string channel_name = channel->getName(); + if (!(channel_name.empty())) { + strcpy(buf, UTF8_TO_FILESYSTEM_ENCODING(channel_name.c_str())); + ZapitTools::replace_char(buf); + StringReplace(FilenameTemplate,"%C",buf); + } + else + StringReplace(FilenameTemplate,"%C","no_channel"); + + CShortEPGData epgdata; + if(CEitManager::getInstance()->getEPGidShort(id, &epgdata)) { + if (!(epgdata.title.empty())) { + strcpy(buf, epgdata.title.c_str()); + ZapitTools::replace_char(buf); + StringReplace(FilenameTemplate,"%T",buf); + } + else + StringReplace(FilenameTemplate,"%T","no_title"); + + if (!(epgdata.info1.empty())) { + strcpy(buf, epgdata.info1.c_str()); + ZapitTools::replace_char(buf); + StringReplace(FilenameTemplate,"%I",buf); + } + else + StringReplace(FilenameTemplate,"%I","no_info"); + } + + strcpy(&(fname[pos]), UTF8_TO_FILESYSTEM_ENCODING(FilenameTemplate.c_str())); + + pos = strlen(fname); + + strcpy(&(fname[pos]), ".jpg"); + + return (fname); +} + +void CIMDB::StringReplace(std::string &str, const std::string search, const std::string rstr) +{ + std::string::size_type ptr = 0; + std::string::size_type pos = 0; + while((ptr = str.find(search,pos)) != std::string::npos){ + str.replace(ptr,search.length(),rstr); + pos = ptr + rstr.length(); + } +} + +void CIMDB::cleanup() +{ + if (access(search_outfile.c_str(), F_OK) == 0) + unlink(search_outfile.c_str()); + if (access(posterfile.c_str(), F_OK) == 0) + unlink(posterfile.c_str()); +} diff --git a/src/gui/imdb.h b/src/gui/imdb.h new file mode 100644 index 000000000..c6e5d952d --- /dev/null +++ b/src/gui/imdb.h @@ -0,0 +1,72 @@ +/* + imdb + + (C) 2009-2016 NG-Team + (C) 2016 NI-Team + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __imdb__ +#define __imdb__ + +#include + +#include +#include + +class CIMDB +{ + public: + CIMDB(); + ~CIMDB(); + static CIMDB* getInstance(); + + std::string search_url; + std::string search_outfile; + std::string search_error; + std::string imdb_outfile; + std::string posterfile; + + int getIMDb(const std::string& epgTitle); + std::string getFilename(CZapitChannel * channel, uint64_t id); + void StringReplace(std::string &str, const std::string search, const std::string rstr); + void cleanup(); + + void getIMDbData(std::string& txt); + + bool gotPoster() { return (access(posterfile.c_str(), F_OK) == 0); }; + + bool checkIMDbElement(std::string element); + //FIXME: what if m[element] doesn't exist? + std::string getIMDbElement(std::string element) { return m[element]; }; + + private: + int acc; + std::string imdb_url; + std::string omdb_apikey; + std::string googleIMDb(std::string s); + std::string utf82url(std::string s); + std::string parseString(std::string search1, std::string search2, std::string str); + std::string parseFile(std::string search1, std::string search2, const char* file, std::string firstline="", int line_offset=0); + std::map m; + + void initMap(std::map& my); +}; + +#endif diff --git a/src/system/localize.cpp b/src/system/localize.cpp index fd0a9c516..e6d89aa4d 100644 --- a/src/system/localize.cpp +++ b/src/system/localize.cpp @@ -253,6 +253,11 @@ const char * CLocaleManager::getText(const neutrino_locale_t keyName) const return localeData[keyName]; } +std::string CLocaleManager::getString(const neutrino_locale_t keyName) const +{ + return (std::string) localeData[keyName]; +} + static const neutrino_locale_t locale_weekday[7] = { LOCALE_DATE_SUN, diff --git a/src/system/localize.h b/src/system/localize.h index 0794ff499..c2c67e3eb 100644 --- a/src/system/localize.h +++ b/src/system/localize.h @@ -69,6 +69,7 @@ class CLocaleManager loadLocale_ret_t loadLocale(const char * const locale, bool asdefault = false); const char * getText(const neutrino_locale_t keyName) const; + std::string getString(const neutrino_locale_t keyName) const; std::string getTextAsString(const neutrino_locale_t keyName) const {return (static_cast(getText(keyName)));} static neutrino_locale_t getMonth (const struct tm * struct_tm_p); diff --git a/src/system/locals.h b/src/system/locals.h index 1f16accf8..477774faf 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -847,6 +847,24 @@ typedef enum LOCALE_IMAGEINFO_LICENSE, LOCALE_IMAGEINFO_VCS, LOCALE_IMAGEINFO_VERSION, + LOCALE_IMDB_DATA_ACTORS, + LOCALE_IMDB_DATA_AWARDS, + LOCALE_IMDB_DATA_BOXOFFICE, + LOCALE_IMDB_DATA_DIRECTOR, + LOCALE_IMDB_DATA_FAILED, + LOCALE_IMDB_DATA_GENRE, + LOCALE_IMDB_DATA_METASCORE, + LOCALE_IMDB_DATA_PLOT, + LOCALE_IMDB_DATA_PRODUCTION, + LOCALE_IMDB_DATA_RATING_FAILED, + LOCALE_IMDB_DATA_RELEASED, + LOCALE_IMDB_DATA_RUNTIME, + LOCALE_IMDB_DATA_TITLE, + LOCALE_IMDB_DATA_VOTES, + LOCALE_IMDB_DATA_WEBSITE, + LOCALE_IMDB_DATA_WRITER, + LOCALE_IMDB_INFO, + LOCALE_IMDB_INFO_SAVE, LOCALE_INETRADIO_NAME, LOCALE_INFOVIEWER_EPGNOTLOAD, LOCALE_INFOVIEWER_EPGWAIT, @@ -1750,6 +1768,7 @@ typedef enum LOCALE_MOVIEBROWSER_HINT_NEWBOOK_BACKWARD, LOCALE_MOVIEBROWSER_HINT_NEWBOOK_FORWARD, LOCALE_MOVIEBROWSER_HINT_TRUNCATE, + LOCALE_MOVIEBROWSER_IMDB_DATA, LOCALE_MOVIEBROWSER_INFO_AUDIO, LOCALE_MOVIEBROWSER_INFO_CHANNEL, LOCALE_MOVIEBROWSER_INFO_FILE, @@ -2458,6 +2477,7 @@ typedef enum LOCALE_TIMING_VOLUMEBAR, LOCALE_TMDB_API_KEY, LOCALE_TMDB_ENABLED, + LOCALE_TMDB_INFO, LOCALE_TMDB_READ_DATA, LOCALE_TUNERSETUP_CABLE, LOCALE_TUNERSETUP_HYBRID, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index b8fd92fbf..919e4384a 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -847,6 +847,24 @@ const char * locale_real_names[] = "imageinfo.license", "imageinfo.vcs", "imageinfo.version", + "imdb.data_actors", + "imdb.data_awards", + "imdb.data_boxoffice", + "imdb.data_director", + "imdb.data_failed", + "imdb.data_genre", + "imdb.data_metascore", + "imdb.data_plot", + "imdb.data_production", + "imdb.data_rating_failed", + "imdb.data_released", + "imdb.data_runtime", + "imdb.data_title", + "imdb.data_votes", + "imdb.data_website", + "imdb.data_writer", + "imdb.info", + "imdb.info_save", "inetradio.name", "infoviewer.epgnotload", "infoviewer.epgwait", @@ -1750,6 +1768,7 @@ const char * locale_real_names[] = "moviebrowser.hint_newbook_backward", "moviebrowser.hint_newbook_forward", "moviebrowser.hint_truncate", + "moviebrowser.imdb_data", "moviebrowser.info_audio", "moviebrowser.info_channel", "moviebrowser.info_file", @@ -2458,6 +2477,7 @@ const char * locale_real_names[] = "timing.volumebar", "tmdb.api_key", "tmdb.enabled", + "tmdb.info", "tmdb.read_data", "tunersetup.cable", "tunersetup.hybrid",