/* Neutrino-GUI - DBoxII-Project - AudioPlayer by Dirch, Zwen Copyright (C) 2001 Steffen Hehn 'McClean' Copyright (C) 2002-2008 the tuxbox project contributors Copyright (C) 2008 Novell, Inc. Author: Stefan Seyfried Copyright (C) 2011-2013,2015,2017 Stefan Seyfried Copyright (C) 2017 Sven Hoefer 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, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ENABLE_GUI_MOUNT #include #endif #include #include #include #include #include #include #include #include #include #include "gui/pictureviewer.h" extern CPictureViewer * g_PicViewer; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if LIBCURL_VERSION_NUM < 0x071507 #include #endif #include #include extern cVideo * videoDecoder; #define AUDIOPLAYERGUI_SMSKEY_TIMEOUT 1000 #define SHOW_FILE_LOAD_LIMIT 50 #define AUDIOPLAYER_TIME_DEBUG // check if files to be added are already in the playlist #define AUDIOPLAYER_CHECK_FOR_DUPLICATES #define AUDIOPLAYER_START_SCRIPT "audioplayer.start" #define AUDIOPLAYER_END_SCRIPT "audioplayer.end" #define DEFAULT_RADIOSTATIONS_XMLFILE CONFIGDIR "/radio-stations.xml" #define DEFAULT_RADIOFAVORITES_XMLFILE CONFIGDIR "/radio-favorites.xml" const char RADIO_STATION_XML_FILE[] = {DEFAULT_RADIOSTATIONS_XMLFILE}; const char RADIO_FAVORITES_XML_FILE[] = {DEFAULT_RADIOFAVORITES_XMLFILE}; CAudiofileExt::CAudiofileExt() : CAudiofile(), firstChar('\0') { } CAudiofileExt::CAudiofileExt(std::string name, CFile::FileType type) : CAudiofile(name, type), firstChar('\0') { } CAudiofileExt::CAudiofileExt(const CAudiofileExt& src) : CAudiofile(src), firstChar(src.firstChar) { } void CAudiofileExt::operator=(const CAudiofileExt& src) { if (&src == this) return; CAudiofile::operator=(src); firstChar = src.firstChar; } CAudioPlayerGui::CAudioPlayerGui(bool inetmode) { m_frameBuffer = CFrameBuffer::getInstance(); m_visible = false; m_inetmode = inetmode; m_detailsline = NULL; m_infobox = NULL; m_titlebox = NULL; Init(); } void CAudioPlayerGui::Init(void) { m_selected = 0; m_metainfo.clear(); pictureviewer = false; m_select_title_by_name = g_settings.audioplayer_select_title_by_name==1; if (!g_settings.network_nfs_audioplayerdir.empty()) m_Path = g_settings.network_nfs_audioplayerdir.c_str(); else m_Path = "/"; audiofilefilter.Clear(); if (m_inetmode) { audiofilefilter.addFilter("url"); audiofilefilter.addFilter("xml"); audiofilefilter.addFilter("m3u"); audiofilefilter.addFilter("pls"); } else { audiofilefilter.addFilter("cdr"); audiofilefilter.addFilter("mp3"); audiofilefilter.addFilter("m2a"); audiofilefilter.addFilter("mpa"); audiofilefilter.addFilter("mp2"); audiofilefilter.addFilter("m3u"); audiofilefilter.addFilter("ogg"); audiofilefilter.addFilter("wav"); audiofilefilter.addFilter("flac"); audiofilefilter.addFilter("flv"); #ifdef ENABLE_FFMPEGDEC audiofilefilter.addFilter("aac"); audiofilefilter.addFilter("dts"); audiofilefilter.addFilter("m4a"); #endif } m_SMSKeyInput.setTimeout(AUDIOPLAYERGUI_SMSKEY_TIMEOUT); } CAudioPlayerGui::~CAudioPlayerGui() { m_playlist.clear(); m_radiolist.clear(); m_filelist.clear(); m_title2Pos.clear(); delete m_detailsline; delete m_infobox; delete m_titlebox; } /*const*/ struct button_label AudioPlayerButtons[][4] = { { { NEUTRINO_ICON_BUTTON_STOP , LOCALE_AUDIOPLAYER_STOP }, { NEUTRINO_ICON_BUTTON_BACKWARD , LOCALE_AUDIOPLAYER_REWIND }, { NEUTRINO_ICON_BUTTON_PAUSE , LOCALE_AUDIOPLAYER_PAUSE }, { NEUTRINO_ICON_BUTTON_FORWARD , LOCALE_AUDIOPLAYER_FASTFORWARD }, }, { { NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_DELETE }, { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD }, { NEUTRINO_ICON_BUTTON_YELLOW , LOCALE_AUDIOPLAYER_DELETEALL }, { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_SHUFFLE }, }, { { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_JUMP_BACKWARDS }, { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_JUMP_FORWARDS }, }, { { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_JUMP_BACKWARDS }, { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_JUMP_FORWARDS }, }, { { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_SAVE_PLAYLIST }, { NEUTRINO_ICON_BUTTON_YELLOW , LOCALE_AUDIOPLAYER_BUTTON_SELECT_TITLE_BY_ID }, }, { { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_SAVE_PLAYLIST }, { NEUTRINO_ICON_BUTTON_YELLOW , LOCALE_AUDIOPLAYER_BUTTON_SELECT_TITLE_BY_NAME}, }, { { NEUTRINO_ICON_BUTTON_STOP , LOCALE_AUDIOPLAYER_STOP }, { NEUTRINO_ICON_BUTTON_PAUSE , LOCALE_AUDIOPLAYER_PAUSE }, { NEUTRINO_ICON_BUTTON_RECORD_ACTIVE, LOCALE_AUDIOPLAYER_STREAMRIPPER_START }, }, { { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD }, { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_INETRADIO_NAME }, }, { { NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_DELETE }, { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD }, { NEUTRINO_ICON_BUTTON_YELLOW , LOCALE_AUDIOPLAYER_DELETEALL }, { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_INETRADIO_NAME }, }, }; int CAudioPlayerGui::exec(CMenuTarget* parent, const std::string &actionKey) { if (actionKey == "init") Init(); CNeutrinoApp::getInstance()->StopSubtitles(); CAudioPlayer::getInstance()->init(); m_state = CAudioPlayerGui::STOP; m_show_playlist = g_settings.audioplayer_show_playlist==1; if (m_select_title_by_name != (g_settings.audioplayer_select_title_by_name==1)) { if ((g_settings.audioplayer_select_title_by_name == 1) && m_playlistHasChanged) { buildSearchTree(); } m_select_title_by_name = g_settings.audioplayer_select_title_by_name; } //auto-load favorites if ((m_inetmode) && (m_playlist.empty())) { if (access(RADIO_FAVORITES_XML_FILE, F_OK) == 0) scanXmlFile(RADIO_FAVORITES_XML_FILE); } if (m_playlist.empty()) m_current = -1; else m_current = 0; m_selected = 0; m_width = m_frameBuffer->getWindowWidth(); m_height = m_frameBuffer->getWindowHeight(); m_header_height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); m_item_height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); m_meta_height = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight(); m_title_height = 3*OFFSET_INNER_SMALL + 2*m_item_height + m_meta_height; m_cover_width = 0; m_info_height = 2*OFFSET_INNER_SMALL + 2*g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getHeight(); m_button_height = ::paintButtons(AudioPlayerButtons[0], 4, 0, 0, 0, 0, 0, false, NULL, NULL); m_listmaxshow = (m_height - m_title_height - OFFSET_SHADOW - OFFSET_INTER - m_header_height - 2*m_button_height - OFFSET_SHADOW - OFFSET_INTER - m_info_height - OFFSET_SHADOW) / (m_item_height); m_height = m_title_height + OFFSET_SHADOW + OFFSET_INTER + m_header_height + m_listmaxshow*m_item_height + 2*m_button_height + OFFSET_SHADOW + OFFSET_INTER + m_info_height + OFFSET_SHADOW; // recalc height m_x = getScreenStartX(m_width); if (m_x < DETAILSLINE_WIDTH) m_x = DETAILSLINE_WIDTH; m_y = getScreenStartY(m_height); m_cover.clear(); m_stationlogo = false; m_streamripper_available = !find_executable("streamripper").empty() && !find_executable("streamripper.sh").empty(); m_streamripper_active = false; if (parent) parent->hide(); bool usedBackground = m_frameBuffer->getuseBackground(); if (usedBackground) m_frameBuffer->saveBackgroundImage(); // set zapit in lock mode CNeutrinoApp::getInstance()->stopPlayBack(true); m_frameBuffer->showFrame("mp3.jpg"); // tell neutrino we're in audio mode m_LastMode = CNeutrinoApp::getInstance()->getMode(); CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , NeutrinoModes::mode_audio); // wake up hdd printf("[audioplayer.cpp] wakeup_hdd(%s)\n", g_settings.network_nfs_audioplayerdir.c_str()); wakeup_hdd(g_settings.network_nfs_audioplayerdir.c_str()/*,true*/); exec_controlscript(AUDIOPLAYER_START_SCRIPT); int res = show(); // Restore previous background if (usedBackground) m_frameBuffer->restoreBackgroundImage(); m_frameBuffer->useBackground(usedBackground); m_frameBuffer->paintBackground(); exec_controlscript(AUDIOPLAYER_END_SCRIPT); //g_Zapit->unlockPlayBack(); CZapit::getInstance()->EnablePlayback(true); m_frameBuffer->stopFrame(); CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , m_LastMode); g_RCInput->postMsg(NeutrinoMessages::SHOW_INFOBAR, 0); CNeutrinoApp::getInstance()->StartSubtitles(); return res; } int CAudioPlayerGui::show() { neutrino_msg_t msg; neutrino_msg_data_t data; int ret = menu_return::RETURN_REPAINT; // clear whole screen m_frameBuffer->paintBackground(); CInfoClock::getInstance()->block(); CScreenSaver::getInstance()->OnAfterStop.connect(sigc::mem_fun(CInfoClock::getInstance(), &CInfoClock::block)); CScreenSaver::getInstance()->resetIdleTime(); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); bool loop = true; bool update = true; bool clear_before_update = false; m_key_level = 0; // auto-play first entry from favorites if (g_settings.inetradio_autostart) { if ((m_inetmode) && (!m_playlist.empty())) { m_current = 0; m_selected = 0; play(m_selected); } } while (loop) { if (msg <= CRCInput::RC_MaxRC) CScreenSaver::getInstance()->resetIdleTime(); updateMetaData(); updateTimes(); // stop if mode was changed in another thread if (CNeutrinoApp::getInstance()->getMode() != NeutrinoModes::mode_audio) loop = false; if ( (m_state != CAudioPlayerGui::STOP) && (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP) && (!m_playlist.empty()) ) { if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO) playNext(); } if (m_streamripper_active && !getpidof("streamripper")) { printf("streamripper should but doesn't work.\n"); m_streamripper_active = false; update = true; } if (update) { if (clear_before_update) { hide(); clear_before_update = false; } update = false; paint(); } g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display if (msg == CRCInput::RC_playpause) { // manipulate msg if (m_state == CAudioPlayerGui::PAUSE) msg = CRCInput::RC_play; else msg = CRCInput::RC_pause; } if (msg == CRCInput::RC_timeout || msg == NeutrinoMessages::EVT_TIMER) { if (CScreenSaver::getInstance()->canStart() && !CScreenSaver::getInstance()->isActive()) { CScreenSaver::getInstance()->Start(); } } else if (!CScreenSaver::getInstance()->ignoredMsg(msg)) { if (CScreenSaver::getInstance()->isActive()) { printf("[audioplayer.cpp] CScreenSaver stop; msg: %lX\n", msg); CScreenSaver::getInstance()->Stop(); m_frameBuffer->stopFrame(); m_frameBuffer->showFrame("mp3.jpg"); paint(); if (msg <= CRCInput::RC_MaxRC) { // ignore first keypress - just quit the screensaver g_RCInput->clearRCMsg(); continue; } } } if (msg == CRCInput::RC_home) { if (m_state == CAudioPlayerGui::STOP) loop=false; } else if (msg == CRCInput::RC_stop) { if (m_state != CAudioPlayerGui::STOP) stop(); } //add key_favorites for internetradio else if ((msg == (neutrino_msg_t) g_settings.key_favorites) && (m_inetmode)) { if (m_key_level == 0) { // clear playlist and load RADIO_FAVORITES_XML_FILE if (access(RADIO_FAVORITES_XML_FILE, F_OK) == 0) { if (!m_playlist.empty()) clearPlaylist(); scanXmlFile(RADIO_FAVORITES_XML_FILE); clear_before_update = true; update = true; } } } else if (msg == CRCInput::RC_left || msg == CRCInput::RC_previoussong) { if (m_key_level == 1) { playPrev(); } else { if (!m_show_playlist) { m_current--; if (m_current < 0) m_current = m_playlist.size()-1; update = true; } else if (!m_playlist.empty()) { if (m_selected < m_listmaxshow) m_selected = m_playlist.size()-1; else m_selected -= m_listmaxshow; m_liststart = (m_selected / m_listmaxshow) * m_listmaxshow; update = true; } } } else if (msg == CRCInput::RC_right || msg == CRCInput::RC_nextsong) { if (m_key_level == 1) { playNext(); } else { if (!m_show_playlist) { m_current++; if (m_current >= (int)m_playlist.size()) m_current = 0; update = true; } else if (!m_playlist.empty()) { m_selected += m_listmaxshow; if (m_selected >= m_playlist.size()) { if (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow == m_playlist.size() + m_listmaxshow) m_selected = 0; else m_selected = m_selected < (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow) ? (m_playlist.size()-1) : 0; } m_liststart = (m_selected / m_listmaxshow) * m_listmaxshow; update = true; } } } else if ((msg &~ CRCInput::RC_Repeat) == CRCInput::RC_up || (msg &~ CRCInput::RC_Repeat) == CRCInput::RC_page_up) { if (m_show_playlist && !m_playlist.empty()) { int prevselected = m_selected; int step = msg == CRCInput::RC_page_up ? m_listmaxshow : 1; m_selected -= step; if ((prevselected-step) < 0) m_selected = m_playlist.size()-1; unsigned int oldliststart = m_liststart; m_liststart = (m_selected/m_listmaxshow)*m_listmaxshow; if (oldliststart != m_liststart) { update = true; } else { paintItem(prevselected - m_liststart); paintItem(m_selected - m_liststart); } } } else if ((msg &~ CRCInput::RC_Repeat) == CRCInput::RC_down || (msg &~ CRCInput::RC_Repeat) == CRCInput::RC_page_down) { if (m_show_playlist && !m_playlist.empty()) { int prevselected = m_selected; unsigned int step = msg == CRCInput::RC_page_down ? m_listmaxshow : 1; m_selected += step; if (m_selected >= m_playlist.size()) { if (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow == m_playlist.size() + m_listmaxshow) // last page has full entries m_selected = 0; else m_selected = ((step == m_listmaxshow) && (m_selected < (((m_playlist.size() / m_listmaxshow)+1) * m_listmaxshow))) ? (m_playlist.size() - 1) : 0; } //m_selected = (m_selected + 1) % m_playlist.size(); unsigned int oldliststart = m_liststart; m_liststart = (m_selected/m_listmaxshow)*m_listmaxshow; if (oldliststart != m_liststart) { update = true; } else { paintItem(prevselected - m_liststart); paintItem(m_selected - m_liststart); } } } else if (msg == CRCInput::RC_ok || msg == CRCInput::RC_play) { if (!m_playlist.empty()) { if (!m_show_playlist) play(m_current); else play(m_selected); } } else if (msg == CRCInput::RC_red) { if (m_key_level == 0) { if (!m_playlist.empty()) { removeFromPlaylist(m_selected); if ((int)m_selected == m_current) m_current--; if (m_selected >= m_playlist.size()) m_selected = m_playlist.empty() ? m_playlist.size() : m_playlist.size() - 1; update = true; } } else if (m_key_level == 1) { stop(); } else { // key_level==2 } } else if (msg == CRCInput::RC_stop) { if (m_key_level == 1) stop(); } else if ((msg == CRCInput::RC_rewind) || (msg == CRCInput::RC_green)) { if (m_key_level == 0) { openFilebrowser(); update=true; } else if (m_key_level == 1) { if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO) rev(); } else { // key_level == 2 if (m_state == CAudioPlayerGui::STOP) { if (!m_playlist.empty()) { savePlaylist(); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); update = true; } } else { // keylevel 2 can only be reached if the currently played file // is no stream, so we do not have to test for this case int seconds=0; CIntInput secondsInput( LOCALE_AUDIOPLAYER_JUMP_DIALOG_TITLE, &seconds, 5, LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT1, LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT2); int res = secondsInput.exec(NULL,""); if (seconds != 0 && res!= menu_return::RETURN_EXIT_ALL) rev(seconds); update=true; } } } else if ((msg == CRCInput::RC_pause) || (msg == CRCInput::RC_yellow)) { if (m_key_level == 0) { if (!m_playlist.empty()) { //stop(); clearPlaylist(); clear_before_update = true; update = true; } } else if (m_key_level == 1) { pause(); } else { // key_level==2 m_select_title_by_name =! m_select_title_by_name; if (m_select_title_by_name && m_playlistHasChanged) buildSearchTree(); paint(); } } else if ((msg == CRCInput::RC_forward) || (msg == CRCInput::RC_blue)) { if (m_key_level == 0) { if (m_inetmode) { static int old_select = 0; char cnt[5]; CMenuWidget InputSelector(LOCALE_AUDIOPLAYER_LOAD_RADIO_STATIONS, NEUTRINO_ICON_AUDIO); int count = 0; int select = -1; CMenuSelectorTarget *InetRadioInputChanger = new CMenuSelectorTarget(&select); // -- setup menue for inetradio input sprintf(cnt, "%d", count); InputSelector.addItem(new CMenuForwarder( LOCALE_AUDIOPLAYER_ADD_FAV, true, NULL, InetRadioInputChanger, cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count); sprintf(cnt, "%d", ++count); InputSelector.addItem(new CMenuForwarder( LOCALE_AUDIOPLAYER_ADD_LOC, true, NULL, InetRadioInputChanger, cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count); sprintf(cnt, "%d", ++count); InputSelector.addItem(new CMenuForwarder( LOCALE_AUDIOPLAYER_ADD_IC, true, NULL, InetRadioInputChanger, cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count); sprintf(cnt, "%d", ++count); InputSelector.addItem(new CMenuForwarder( LOCALE_AUDIOPLAYER_ADD_SC, g_settings.shoutcast_enabled, NULL, InetRadioInputChanger, cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count); //InputSelector.addItem(GenericMenuSeparator); hide(); InputSelector.exec(NULL, ""); delete InetRadioInputChanger; if (!m_playlist.empty()) clearPlaylist(); if (select >= 0) old_select = select; switch (select) { case 0: scanXmlFile(RADIO_FAVORITES_XML_FILE); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); break; case 1: scanXmlFile(RADIO_STATION_XML_FILE); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); break; case 2: readDir_ic(); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); break; case 3: openSCbrowser(); break; default: break; } m_current = 0; m_selected = 0; update=true; } else if (shufflePlaylist()) { update = true; } } else if (m_key_level == 1) { if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO) ff(); } else // key_level == 2 { if (m_state != CAudioPlayerGui::STOP) { // keylevel 2 can only be reached if the currently played file // is no stream, so we do not have to test for this case int seconds=0; CIntInput secondsInput( LOCALE_AUDIOPLAYER_JUMP_DIALOG_TITLE, &seconds, 5, LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT1, LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT2); int res = secondsInput.exec(NULL,""); if (seconds != 0 && res!= menu_return::RETURN_EXIT_ALL) ff(seconds); update = true; } } } #if 0 // FIXME; this seems totally broken else if (msg == CRCInput::RC_info && !m_playlist.empty()) { pictureviewer = true; m_frameBuffer->Clear(); m_frameBuffer->stopFrame(); CPictureViewerGui * picture = new CPictureViewerGui(); picture->m_audioPlayer = this; picture->exec(this, "audio"); delete picture; pictureviewer = false; CScreenSaver::getInstance()->resetIdleTime(); videoDecoder->setBlank(true); m_frameBuffer->showFrame("mp3.jpg"); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); update = true; } #endif else if (msg == CRCInput::RC_help) { if (m_key_level == 2) m_key_level = 0; else m_key_level++; if (m_state != CAudioPlayerGui::STOP) { // jumping in streams not supported if (m_key_level == 2 && m_curr_audiofile.FileType == CFile::STREAM_AUDIO) { m_key_level = 0; } } // there are only two keylevels in the "STOP"-case else if (m_key_level == 1) { m_key_level = 2; } paintFoot(); } else if (msg == CRCInput::RC_0) { if (m_current >= 0) { m_selected = m_current; update = true; } } else if (msg == (neutrino_msg_t) g_settings.key_record) { if (m_key_level == 1) { if (m_curr_audiofile.FileType == CFile::STREAM_AUDIO && m_streamripper_available) { if (m_streamripper_active) { ShowHint(LOCALE_MESSAGEBOX_INFO, LOCALE_AUDIOPLAYER_STREAMRIPPER_STOP, HINTBOX_MIN_WIDTH, 2); my_system(2, "streamripper.sh", "stop"); m_streamripper_active = false; } else { ShowHint(LOCALE_MESSAGEBOX_INFO, LOCALE_AUDIOPLAYER_STREAMRIPPER_START, HINTBOX_MIN_WIDTH, 2); printf("streamripper.sh start \"%s\"\n", m_playlist[m_current].MetaData.url.c_str()); puts("[audioplayer.cpp] executing streamripper"); if (my_system(3, "streamripper.sh", "start", m_playlist[m_current].MetaData.url.c_str()) != 0) perror("[audioplayer.cpp]: streamripper.sh failed\n"); else m_streamripper_active = true; } update = true; } } } else if (CRCInput::isNumeric(msg) && !(m_playlist.empty())) { //numeric zap or SMS zap if (m_select_title_by_name) { //printf("select by name\n"); unsigned char smsKey = 0; int w = 0; do { //FIXME - remove fixed values smsKey = m_SMSKeyInput.handleMsg(msg); //printf(" new key: %c", smsKey); /* show a hint box with current char (too slow at the moment?)*/ char selectedKey[2]; sprintf(selectedKey,"%c",smsKey); int x1=(g_settings.screen_EndX- g_settings.screen_StartX)/2 + g_settings.screen_StartX-50; int y1=(g_settings.screen_EndY- g_settings.screen_StartY)/2 + g_settings.screen_StartY; int h = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight(); w = std::max(w, g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getRenderWidth(selectedKey)); m_frameBuffer->paintBoxRel(x1 - 7, y1 - h - 5, w + 14, h + 10, COL_FRAME_PLUS_0, RADIUS_SMALL); m_frameBuffer->paintBoxRel(x1 - 6, y1 - h - 4, w + 12, h + 8, COL_MENUCONTENTSELECTED_PLUS_0, RADIUS_SMALL); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(x1,y1,w+1,selectedKey,COL_MENUCONTENTSELECTED_TEXT); g_RCInput->getMsg_ms(&msg, &data, AUDIOPLAYERGUI_SMSKEY_TIMEOUT - 200); } while (CRCInput::isNumeric(msg) && !(m_playlist.empty())); if (msg == CRCInput::RC_timeout || msg == CRCInput::RC_nokey) { //printf("selected key: %c\n",smsKey); selectTitle(smsKey); } update = true; m_SMSKeyInput.resetOldKey(); } else { //printf("numeric zap\n"); int val = 0; if (getNumericInput(msg,val)) m_selected = std::min((int)m_playlist.size(), val) - 1; update = true; } } #ifdef ENABLE_GUI_MOUNT else if ((msg == CRCInput::RC_setup) && !m_inetmode) { CNFSSmallMenu nfsMenu; nfsMenu.exec(this, ""); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); update = true; } #endif else if (msg == NeutrinoMessages::CHANGEMODE) { if ((data & NeutrinoModes::mode_mask) != NeutrinoModes::mode_audio) { loop = false; m_LastMode=data; } } else if ( msg == NeutrinoMessages::RECORD_START || msg == NeutrinoMessages::ZAPTO || msg == NeutrinoMessages::STANDBY_ON || msg == NeutrinoMessages::LEAVE_ALL || msg == NeutrinoMessages::SHUTDOWN || (msg == NeutrinoMessages::SLEEPTIMER && !data) ) { if (msg != NeutrinoMessages::RECORD_START) ret = menu_return::RETURN_EXIT_ALL; // Exit for Record/Zapto Timers loop = false; g_RCInput->postMsg(msg, data); } else if (msg == NeutrinoMessages::EVT_TIMER) { CNeutrinoApp::getInstance()->handleMsg(msg, data); } else { if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) { ret = menu_return::RETURN_EXIT_ALL; loop = false; } //paintLCD(); } } hide(); if (m_state != CAudioPlayerGui::STOP) stop(); CInfoClock::getInstance()->enableInfoClock(CInfoClock::getInstance()->isRun()); CScreenSaver::getInstance()->OnAfterStop.clear(); return ret; } bool CAudioPlayerGui::playNext(bool allow_rotate) { bool result = false; if (!(m_playlist.empty())) { int next = getNext(); if (next >= 0) play(next); else if (allow_rotate) play(0); else stop(); result = true; } return(result); } void CAudioPlayerGui::wantNextPlay() { if ( (m_state != CAudioPlayerGui::STOP) && (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP) && (!m_playlist.empty()) ) { if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO) playNext(); } } bool CAudioPlayerGui::playPrev(bool allow_rotate) { bool result = false; if (!(m_playlist.empty())) { if (m_current == -1) stop(); else if (m_current-1 > 0) play(m_current-1); else if (allow_rotate) play(m_playlist.size()-1); else play(0); result = true; } return(result); } bool CAudioPlayerGui::clearPlaylist(void) { bool result = false; CAudioPlayList::const_iterator it; #if 0 for (it = m_playlist.begin(); it!=m_playlist.end(); ++it) { unlink(it->MetaData.cover.c_str()); } #endif if (!(m_playlist.empty())) { m_playlist.clear(); m_current = -1; m_selected = 0; m_title2Pos.clear(); result = true; } return(result); } bool CAudioPlayerGui::shufflePlaylist(void) { RandomNumber rnd; bool result = false; if (!(m_playlist.empty())) { if (m_current > 0) { std::swap(m_playlist[0], m_playlist[m_current]); m_current = 0; } std::random_shuffle((m_current != 0) ? m_playlist.begin() : m_playlist.begin() + 1, m_playlist.end(), rnd); if (m_select_title_by_name) buildSearchTree(); m_playlistHasChanged = true; m_selected = 0; result = true; } return(result); } void CAudioPlayerGui::addUrl2Playlist(const char *url, const char *name, const char *logo, const time_t bitrate) { CAudiofileExt mp3(url, CFile::STREAM_AUDIO); //tmp = tmp.substr(0,tmp.length()-4); //remove .url //printf("[addUrl2Playlist], name = %s, url = %s\n", name, url); if (name != NULL) { mp3.MetaData.title = name; } else { std::string filename = mp3.Filename.substr(mp3.Filename.rfind('/') + 1); mp3.MetaData.title = filename; } if (logo != NULL) mp3.MetaData.logo = logo; else mp3.MetaData.logo.clear(); if (bitrate) mp3.MetaData.total_time = bitrate; else mp3.MetaData.total_time = 0; mp3.MetaData.url = url; if (url[0] != '#') addToPlaylist(mp3); } void CAudioPlayerGui::processPlaylistUrl(const char *url, const char *name, const char *logo, const time_t tim) { CURL *curl_handle; struct MemoryStruct chunk; const long int GET_PLAYLIST_TIMEOUT = 2; printf("CAudioPlayerGui::processPlaylistUrl (%s, %s)\n", url, name); chunk.memory=NULL; /* we expect realloc(NULL, size) to work */ chunk.size = 0; /* no data at this point */ curl_global_init(CURL_GLOBAL_ALL); /* init the curl session */ curl_handle = curl_easy_init(); /* specify URL to get */ curl_easy_setopt(curl_handle, CURLOPT_URL, url); /* send all data to this function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); /* some servers don't like requests that are made without a user-agent field, so we provide one */ curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); /* don't use signal for timeout */ curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, (long)1); /* set timeout to 10 seconds */ curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, GET_PLAYLIST_TIMEOUT); /* get it! */ curl_easy_perform(curl_handle); /* Now, our chunk.memory points to a memory block that is chunk.size bytes big and contains the remote file. Do something nice with it! You should be aware of the fact that at this point we might have an allocated data block, and nothing has yet deallocated that data. So when you're done with it, you should free() it as a nice application. */ long res_code; if (curl_easy_getinfo(curl_handle, CURLINFO_HTTP_CODE/*CURLINFO_RESPONSE_CODE*/, &res_code) == CURLE_OK) { if (200 == res_code) { //printf("\nchunk = %s\n", chunk.memory); std::istringstream iss; iss.str (std::string(chunk.memory, chunk.size)); char line[512]; char *ptr; while (iss.rdstate() == std::ifstream::goodbit) { iss.getline(line, 512); if (line[0] != '#') { //printf("chunk: line = %s\n", line); const char *schemes[] = {"http://", "https://", NULL }; const char **scheme = schemes; while (*scheme) { ptr = strstr(line, *scheme); scheme++; if (ptr == NULL) continue; char *tmp; // strip \n and \r characters from url tmp = strchr(line, '\r'); if (tmp != NULL) *tmp = '\0'; tmp = strchr(line, '\n'); if (tmp != NULL) *tmp = '\0'; addUrl2Playlist(ptr, name, logo, tim); break; } } } } } /* cleanup curl stuff */ curl_easy_cleanup(curl_handle); if (chunk.memory) free(chunk.memory); /* we're done with libcurl, so clean it up */ curl_global_cleanup(); } void CAudioPlayerGui::readDir_ic(void) { const std::string icecasturl = "http://dir.xiph.org/yp.xml"; const long int GET_ICECAST_TIMEOUT = 90; // list is about 500kB! std::string answer=""; std::cout << "[readDir_ic] IC URL: " << icecasturl << std::endl; CURL *curl_handle; CURLcode httpres; /* init the curl session */ curl_handle = curl_easy_init(); /* specify URL to get */ curl_easy_setopt(curl_handle, CURLOPT_URL, icecasturl.c_str()); /* send all data to this function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, CurlWriteToString); /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl_handle, CURLOPT_FILE, (void *)&answer); /* Generate error if http error >= 400 occurs */ curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); /* set timeout to 30 seconds */ curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, GET_ICECAST_TIMEOUT); /* error handling */ char error[CURL_ERROR_SIZE]; curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error); /* get it! */ CHintBox *scanBox = new CHintBox(LOCALE_AUDIOPLAYER_ADD_IC, g_Locale->getText(LOCALE_AUDIOPLAYER_RECEIVING_LIST)); // UTF-8 scanBox->paint(); httpres = curl_easy_perform(curl_handle); /* cleanup curl stuff */ curl_easy_cleanup(curl_handle); //std::cout << "Answer:" << std::endl << "----------------" << std::endl << answer << std::endl; if (!answer.empty() && httpres == 0) { xmlDocPtr answer_parser = parseXml(answer.c_str()); scanBox->hide(); scanXmlData(answer_parser, "listen_url", "server_name", "", "bitrate", true); } else scanBox->hide(); delete scanBox; } void CAudioPlayerGui::scanXmlFile(std::string filename) { xmlDocPtr answer_parser = parseXmlFile(filename.c_str()); scanXmlData(answer_parser, "url", "name", "logo"); } void CAudioPlayerGui::scanXmlData(xmlDocPtr answer_parser, const char *urltag, const char *nametag, const char *logotag, const char *bitratetag, bool usechild) { #define IC_typetag "server_type" if (answer_parser != NULL) { xmlNodePtr element = xmlDocGetRootElement(answer_parser); element = xmlChildrenNode(element); xmlNodePtr element_tmp = element; if (element == NULL) { printf("[openFilebrowser] No valid XML File.\n"); } else { CProgressWindow progress; long maxProgress = 1; // count # of entries while (element) { maxProgress++; element = xmlNextNode(element); } element = element_tmp; long listPos = -1; progress.setTitle(LOCALE_AUDIOPLAYER_LOAD_RADIO_STATIONS); progress.exec(this, ""); neutrino_msg_t msg; neutrino_msg_data_t data; g_RCInput->getMsg(&msg, &data, 0); while (element && msg != CRCInput::RC_home) { const char *ptr = NULL; const char *name = NULL; const char *url = NULL; const char *logo = NULL; time_t bitrate = 0; bool skip = true; listPos++; // show status int global = 100*listPos / maxProgress; progress.showStatus(global); #ifdef LCD_UPDATE CVFD::getInstance()->showProgressBar(global, "read xmldata..."); CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR); #endif // LCD_UPDATE if (usechild) { const char *type = NULL; xmlNodePtr child = xmlChildrenNode(element); while (child) { if (strcmp(xmlGetName(child), urltag) == 0) url = xmlGetData(child); else if (strcmp(xmlGetName(child), nametag) == 0) name = xmlGetData(child); else if (strcmp(xmlGetName(child), logotag) == 0) logo = xmlGetData(child); else if (strcmp(xmlGetName(child), IC_typetag) == 0) type = xmlGetData(child); else if (bitratetag && strcmp(xmlGetName(child), bitratetag) == 0) { ptr = xmlGetData(child); if (ptr) bitrate = atoi(ptr); } child = xmlNextNode(child); } if (type) { if (strcmp("audio/mpeg", type) == 0) skip = false; else if (strcmp("application/ogg", type) == 0) skip = false; else if (strcmp("mp3", type) == 0) skip = false; else if (strcmp("application/mp3", type) == 0) skip = false; } } else { url = xmlGetAttribute(element, urltag); name = xmlGetAttribute(element, nametag); logo = xmlGetAttribute(element, logotag); if (bitratetag) { ptr = xmlGetAttribute(element, bitratetag); if (ptr) bitrate = atoi(ptr); } skip = false; } if ((url != NULL) && !skip) { progress.showStatusMessageUTF(url); //printf("Processing %s, %s\n", url, name); if (strstr(url, ".m3u") || strstr(url, ".pls")) processPlaylistUrl(url, name, logo); else addUrl2Playlist(url, name, logo, bitrate); } element = xmlNextNode(element); g_RCInput->getMsg(&msg, &data, 0); if( ( msg>= CRCInput::RC_WithData ) && ( msg< CRCInput::RC_WithData+ 0x10000000 ) ) delete[] (unsigned char*) data; } progress.hide(); } xmlFreeDoc(answer_parser); } else printf("[scanXmlData] answer_parser == NULL"); } bool CAudioPlayerGui::openFilebrowser(void) { bool result = false; CFileBrowser filebrowser((g_settings.filebrowser_denydirectoryleave) ? g_settings.network_nfs_audioplayerdir.c_str() : ""); filebrowser.Multi_Select = true; filebrowser.Dirs_Selectable = true; filebrowser.Filter = &audiofilefilter; hide(); if (filebrowser.exec(m_Path.c_str())) { #ifdef AUDIOPLAYER_TIME_DEBUG timeval start; gettimeofday(&start,NULL); #endif CProgressWindow progress; long maxProgress = (filebrowser.getSelectedFiles().size() > 1) ? filebrowser.getSelectedFiles().size() - 1 : 1; long currentProgress = -1; if (maxProgress > SHOW_FILE_LOAD_LIMIT) { progress.setTitle(LOCALE_AUDIOPLAYER_READING_FILES); progress.exec(this,""); } m_Path = filebrowser.getCurrentDir(); CFileList::const_iterator files = filebrowser.getSelectedFiles().begin(); for (; files != filebrowser.getSelectedFiles().end(); ++files) { if (maxProgress > SHOW_FILE_LOAD_LIMIT) { currentProgress++; // show status int global = 100*currentProgress/maxProgress; progress.showStatus(global); progress.showStatusMessageUTF(files->Name); #ifdef LCD_UPDATE CVFD::getInstance()->showProgressBar(global, "read metadata..."); CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR); #endif // LCD_UPDATE } if ( (files->getType() == CFile::FILE_CDR) || (files->getType() == CFile::FILE_OGG) || (files->getType() == CFile::FILE_MP3) || (files->getType() == CFile::FILE_WAV) #ifdef ENABLE_FFMPEGDEC || (files->getType() == CFile::FILE_AAC) #endif || (files->getType() == CFile::FILE_FLAC) || (files->getType() == CFile::FILE_FLV) ) { CAudiofileExt audiofile(files->Name, files->getType()); addToPlaylist(audiofile); } if (files->getType() == CFile::STREAM_AUDIO) { std::string filename = files->Name; FILE *fd = fopen(filename.c_str(), "r"); if (fd) { char buf[512]; unsigned int len = fread(buf, sizeof(char), 512, fd); fclose(fd); if (len && (strstr(buf, ".m3u") || strstr(buf, ".pls"))) { printf("m3u/pls Playlist found: %s\n", buf); filename = buf; processPlaylistUrl(buf); } else { addUrl2Playlist(filename.c_str()); } } } else if (files->getType() == CFile::FILE_PLAYLIST) { std::string sPath = files->Name.substr(0, files->Name.rfind('/')); std::ifstream infile; char cLine[256]; char name[255] = { 0 }; infile.open(files->Name.c_str(), std::ifstream::in); while (infile.good()) { infile.getline(cLine, 255); int duration; sscanf(cLine, "#EXTINF:%d,%[^\n]\n", &duration, name); if (strlen(cLine) > 0 && cLine[0]!='#') { // remove CR if (cLine[strlen(cLine)-1]=='\r') cLine[strlen(cLine)-1]=0; char *url = strstr(cLine, "http://"); if (url != NULL) { if (strstr(url, ".m3u") || strstr(url, ".pls")) processPlaylistUrl(url); else addUrl2Playlist(url, name, NULL, duration); } else if ((url = strstr(cLine, "icy://")) != NULL) { addUrl2Playlist(url); } else if ((url = strstr(cLine, "scast:://")) != NULL) { addUrl2Playlist(url); } else { std::string filename = sPath + '/' + cLine; std::string::size_type pos; while ((pos=filename.find('\\'))!=std::string::npos) filename[pos]='/'; std::ifstream testfile; testfile.open(filename.c_str(), std::ifstream::in); if (testfile.good()) { #ifdef AUDIOPLAYER_CHECK_FOR_DUPLICATES // Check for duplicates and remove (new entry has higher prio) // this really needs some time :( for (unsigned long i=0; igetType() == CFile::FILE_XML) { if (!files->Name.empty()) scanXmlFile(files->Name); } } if (m_select_title_by_name) buildSearchTree(); #ifdef AUDIOPLAYER_TIME_DEBUG timeval end; gettimeofday(&end,NULL); printf("adding %ld files took: ",maxProgress+1); printTimevalDiff(start,end); #endif //store last dir if (g_settings.network_nfs_audioplayerdir.size() > m_Path.size() && g_settings.network_nfs_audioplayerdir != m_Path.c_str()) g_settings.network_nfs_audioplayerdir = m_Path; result = true; } CScreenSaver::getInstance()->resetIdleTime(); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); // if playlist is turned off -> start playing immediately if (!m_show_playlist && !m_playlist.empty()) play(m_selected); return result; } bool CAudioPlayerGui::openSCbrowser(void) { bool result = false; //shoutcast const char *sc_base_dir = "http://api.shoutcast.com"; CFileBrowser filebrowser(sc_base_dir, CFileBrowser::ModeSC); filebrowser.Multi_Select = true; filebrowser.Dirs_Selectable = true; filebrowser.Filter = NULL;//&audiofilefilter; hide(); if (filebrowser.exec(filebrowser.sc_init_dir.c_str())) { #ifdef AUDIOPLAYER_TIME_DEBUG timeval start; gettimeofday(&start,NULL); #endif CProgressWindow progress; long maxProgress = (filebrowser.getSelectedFiles().size() > 1) ? filebrowser.getSelectedFiles().size() - 1: 1; long currentProgress = -1; //if (maxProgress > SHOW_FILE_LOAD_LIMIT) { progress.setTitle(LOCALE_AUDIOPLAYER_READING_FILES); progress.exec(this,""); } m_Path = filebrowser.getCurrentDir(); CFileList::const_iterator files = filebrowser.getSelectedFiles().begin(); neutrino_msg_t msg; neutrino_msg_data_t data; g_RCInput->getMsg(&msg, &data, 0); for (; (files != filebrowser.getSelectedFiles().end()) && (msg != CRCInput::RC_home); ++files) { //if (maxProgress > SHOW_FILE_LOAD_LIMIT) { currentProgress++; // show progress int global = 100*currentProgress/maxProgress; progress.showStatus(global); progress.showStatusMessageUTF(files->Name); #ifdef LCD_UPDATE CVFD::getInstance()->showProgressBar(global, "read metadata..."); CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR); #endif // LCD_UPDATE } //printf("processPlaylistUrl(%s, %s)\n", files->Url.c_str(), files->Name.c_str()); processPlaylistUrl(files->Url.c_str(), files->Name.c_str(), NULL, files->Time); g_RCInput->getMsg(&msg, &data, 0); if( ( msg>= CRCInput::RC_WithData ) && ( msg< CRCInput::RC_WithData+ 0x10000000 ) ) delete[] (unsigned char*) data; } if (m_select_title_by_name) buildSearchTree(); #ifdef AUDIOPLAYER_TIME_DEBUG timeval end; gettimeofday(&end,NULL); printf("adding %ld files took: ",maxProgress+1); printTimevalDiff(start,end); #endif result = true; } CScreenSaver::getInstance()->resetIdleTime(); CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); paintLCD(); // if playlist is turned off -> start playing immediately if (!m_show_playlist && !m_playlist.empty()) play(m_selected); return result; } void CAudioPlayerGui::hide() { // printf("hide(){\n"); if (m_visible) { clearDetailsLine(); m_frameBuffer->paintBackgroundBoxRel(m_x, m_y, m_width + OFFSET_SHADOW, m_height + OFFSET_SHADOW); m_visible = false; } } void CAudioPlayerGui::paintItem(int pos) { if (!m_show_playlist) return; int ypos = m_y + m_title_height + OFFSET_SHADOW + OFFSET_INTER + m_header_height + pos*m_item_height; unsigned int currpos = m_liststart + pos; bool i_selected = currpos == m_selected; bool i_marked = currpos == (unsigned) m_current; bool i_switch = false; //(currpos < m_playlist.size()) && (pos & 1); int i_radius = RADIUS_NONE; fb_pixel_t color; fb_pixel_t bgcolor; getItemColors(color, bgcolor, i_selected, i_marked, i_switch); if (i_selected || i_marked) i_radius = RADIUS_LARGE; if (i_selected) paintDetailsLine(pos); if (i_radius) m_frameBuffer->paintBoxRel(m_x, ypos, m_width - SCROLLBAR_WIDTH, m_item_height, COL_MENUCONTENT_PLUS_0); m_frameBuffer->paintBoxRel(m_x, ypos, m_width - SCROLLBAR_WIDTH, m_item_height, bgcolor, i_radius); if (currpos < m_playlist.size()) { char sNr[20]; sprintf(sNr, (currpos + 1) < 10 ? "%02d: " : "%d: ", currpos + 1); std::string tmp = sNr; getFileInfoToDisplay(tmp, m_playlist[currpos]); char dura[14] = {0}; if (m_inetmode) { if (m_playlist[currpos].MetaData.total_time != 0) snprintf(dura, sizeof(dura), "%ldk", m_playlist[currpos].MetaData.total_time); } else snprintf(dura, sizeof(dura), "%ld:%02ld", m_playlist[currpos].MetaData.total_time / 60, m_playlist[currpos].MetaData.total_time % 60); int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(dura); g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + OFFSET_INNER_MID, ypos + m_item_height, m_width - SCROLLBAR_WIDTH - 3*OFFSET_INNER_MID - w, tmp, color, m_item_height); g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - SCROLLBAR_WIDTH - OFFSET_INNER_MID - w, ypos + m_item_height, w, dura, color, m_item_height); if (currpos == m_selected) { if (m_state == CAudioPlayerGui::STOP) CVFD::getInstance()->showAudioTrack(m_playlist[currpos].MetaData.artist, m_playlist[currpos].MetaData.title, m_playlist[currpos].MetaData.album); } } } void CAudioPlayerGui::paintHead() { if (!m_show_playlist || CScreenSaver::getInstance()->isActive()) return; CComponentsHeader header(m_x, m_y + m_title_height + OFFSET_SHADOW + OFFSET_INTER, m_width, m_header_height, LOCALE_AUDIOPLAYER_HEAD, NEUTRINO_ICON_AUDIO); header.enableShadow( CC_SHADOW_RIGHT | CC_SHADOW_CORNER_TOP_RIGHT | CC_SHADOW_CORNER_BOTTOM_RIGHT, -1, true); if (m_inetmode) header.setCaption(LOCALE_INETRADIO_NAME); #ifdef ENABLE_GUI_MOUNT if (!m_inetmode) header.setContextButton(NEUTRINO_ICON_BUTTON_MENU); #endif header.paint(CC_SAVE_SCREEN_NO); } #if 0 #define BUTTON_LABEL_COUNT 3 const struct button_label SecondLineButtons[BUTTON_LABEL_COUNT] = { { NEUTRINO_ICON_BUTTON_OKAY, LOCALE_AUDIOPLAYER_PLAY }, { NEUTRINO_ICON_BUTTON_HELP, LOCALE_AUDIOPLAYER_KEYLEVEL }, { NEUTRINO_ICON_BUTTON_INFO, LOCALE_PICTUREVIEWER_HEAD } }; #else #define BUTTON_LABEL_COUNT 2 const struct button_label SecondLineButtons[BUTTON_LABEL_COUNT] = { { NEUTRINO_ICON_BUTTON_OKAY, LOCALE_AUDIOPLAYER_PLAY }, { NEUTRINO_ICON_BUTTON_HELP, LOCALE_AUDIOPLAYER_KEYLEVEL } }; #endif void CAudioPlayerGui::paintFoot() { if (CScreenSaver::getInstance()->isActive()) return; int radius = RADIUS_LARGE; int button_y = m_y + m_height - OFFSET_SHADOW - m_info_height - OFFSET_INTER - OFFSET_SHADOW - 2*m_button_height; int button_x = m_x; int button_width = m_width; // ensure to get round corners in footer if (!m_show_playlist && radius) { button_x += radius; button_width -= 2*radius; } // shadow m_frameBuffer->paintBoxRel(m_x + OFFSET_SHADOW, button_y + OFFSET_SHADOW, m_width, 2*m_button_height, COL_SHADOW_PLUS_0, radius, (m_show_playlist ? CORNER_BOTTOM : CORNER_ALL)); m_frameBuffer->paintBoxRel(m_x, button_y, m_width, 2*m_button_height, COL_MENUFOOT_PLUS_0, radius, (m_show_playlist ? CORNER_BOTTOM : CORNER_ALL)); if (!m_playlist.empty()) ::paintButtons(button_x, button_y + m_button_height, button_width, BUTTON_LABEL_COUNT, SecondLineButtons, button_width, m_button_height); if (m_key_level == 0) { if (m_playlist.empty()) { if (m_inetmode) ::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[7], button_width, m_button_height); else ::paintButtons(button_x, button_y, button_width, 1, &(AudioPlayerButtons[7][0]), button_width, m_button_height); } else if (m_inetmode) ::paintButtons(button_x, button_y, button_width, 4, AudioPlayerButtons[8], button_width, m_button_height); else ::paintButtons(button_x, button_y, button_width, 4, AudioPlayerButtons[1], button_width, m_button_height); } else if (m_key_level == 1) { if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO) ::paintButtons(button_x, button_y, button_width, 4, AudioPlayerButtons[0], button_width, m_button_height); else { int b = 2; if (m_streamripper_available) { b = 3; if (m_streamripper_active) AudioPlayerButtons[6][2].locale = LOCALE_AUDIOPLAYER_STREAMRIPPER_STOP; else AudioPlayerButtons[6][2].locale = LOCALE_AUDIOPLAYER_STREAMRIPPER_START; } ::paintButtons(button_x, button_y, button_width, b, AudioPlayerButtons[6], button_width, m_button_height); } } else // key_level == 2 { if (m_state == CAudioPlayerGui::STOP) { if (m_select_title_by_name) ::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[5], button_width, m_button_height); else ::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[4], button_width, m_button_height); } else { if (m_select_title_by_name) ::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[3], button_width, m_button_height); else ::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[2], button_width, m_button_height); } } } void CAudioPlayerGui::paintCover() { const CAudioMetaData meta = CAudioPlayer::getInstance()->getMetaData(); // try folder.jpg first m_cover = m_curr_audiofile.Filename.substr(0, m_curr_audiofile.Filename.rfind('/')) + "/folder.jpg"; m_stationlogo = false; // try cover from tag if (!meta.cover.empty()) m_cover = meta.cover; // try station logo else if (!meta.logo.empty()) { std::size_t found_url = meta.logo.find("://"); if (found_url != std::string::npos) { mkdir(COVERDIR_TMP, 0755); std::string filename(meta.logo); const size_t last_slash_idx = filename.find_last_of("/"); if (last_slash_idx != std::string::npos) filename.erase(0, last_slash_idx + 1); std::string fullname(COVERDIR_TMP); fullname += "/" + filename; CHTTPTool httptool; if (httptool.downloadFile(meta.logo, fullname.c_str())) { m_cover = fullname; m_stationlogo = true; } else m_cover.clear(); } } if (access(m_cover.c_str(), F_OK) == 0) { int cover_x = m_x + OFFSET_INNER_MID; int cover_y = m_y + OFFSET_INNER_SMALL; m_cover_width = 0; CComponentsPicture *cover_object = new CComponentsPicture(cover_x, cover_y, m_cover); if (cover_object) { cover_object->doPaintBg(false); // cover_object->SetTransparent(CFrameBuffer::TM_BLACK); cover_object->setHeight(m_title_height - 2*OFFSET_INNER_SMALL, true); cover_object->paint(); m_cover_width = cover_object->getWidth() + OFFSET_INNER_MID; delete cover_object; } } } void CAudioPlayerGui::paintTitleBox() { if (CScreenSaver::getInstance()->isActive()) return; if (m_state == CAudioPlayerGui::STOP && m_show_playlist) { if (m_titlebox) { m_titlebox->kill(); delete m_titlebox; m_titlebox = NULL; } } else { // title box if (!m_titlebox) { m_titlebox = new CComponentsShapeSquare(m_x, m_y, m_width, m_title_height, NULL, CC_SHADOW_ON); m_titlebox->enableFrame(true, FRAME_WIDTH_MIN); m_titlebox->setCorner(RADIUS_LARGE); } m_titlebox->paint(false); paintCover(); // first line (Track number) std::string tmp; if (m_inetmode) { tmp = m_curr_audiofile.MetaData.album; } else { char sNr[20]; sprintf(sNr, ": %2d", m_current + 1); tmp = g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYING); tmp += sNr ; } int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp); int xstart = (m_width - w)/2; if (xstart < OFFSET_INNER_MID + m_cover_width) xstart = OFFSET_INNER_MID + m_cover_width; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + OFFSET_INNER_SMALL + 1*m_item_height, m_width - OFFSET_INNER_MID - xstart, tmp, COL_MENUHEAD_TEXT); //caption "current track" // second line (Artist/Title...) GetMetaData(m_curr_audiofile); if (m_curr_audiofile.MetaData.title.empty()) tmp = m_curr_audiofile.MetaData.artist; else if (m_curr_audiofile.MetaData.artist.empty()) tmp = m_curr_audiofile.MetaData.title; else if (g_settings.audioplayer_display == TITLE_ARTIST) { tmp = m_curr_audiofile.MetaData.title; tmp += " - "; tmp += m_curr_audiofile.MetaData.artist; } else //if (g_settings.audioplayer_display == ARTIST_TITLE) { tmp = m_curr_audiofile.MetaData.artist; tmp += " - "; tmp += m_curr_audiofile.MetaData.title; } w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp); xstart = (m_width - w)/2; if (xstart < OFFSET_INNER_MID + m_cover_width) xstart = OFFSET_INNER_MID + m_cover_width; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + OFFSET_INNER_SMALL + 2*m_item_height, m_width - OFFSET_INNER_MID - xstart, tmp, COL_MENUHEAD_TEXT); //artist - title // reset so fields get painted always m_metainfo.clear(); m_time_total = 0; m_time_played = 0; updateMetaData(); updateTimes(true); } } void CAudioPlayerGui::paint() { if (m_show_playlist) { unsigned int tmp_max = m_listmaxshow; if (!tmp_max) tmp_max = 1; m_liststart = (m_selected / tmp_max) * m_listmaxshow; paintHead(); for (unsigned int count=0; countkill(); delete m_detailsline; m_detailsline = NULL; } // paint Line if detail info (and not valid list pos) and info box if (!m_playlist.empty() && (pos >= 0)) { //details line if (m_detailsline == NULL) m_detailsline = new CComponentsDetailsLine(xpos, ypos1a, ypos2a, m_item_height/2, m_info_height - RADIUS_LARGE*2); m_detailsline->paint(false); // paint id3 infobox if (m_infobox == NULL) { m_infobox = new CComponentsInfoBox(m_x, ypos2, m_width, m_info_height); m_infobox->setFrameThickness(FRAME_WIDTH_MIN); m_infobox->setCorner(RADIUS_LARGE); m_infobox->setColorFrame(COL_FRAME_PLUS_0); m_infobox->setColorBody(COL_MENUCONTENTDARK_PLUS_0); m_infobox->enableShadow(CC_SHADOW_ON, -1, true); m_infobox->forceTextPaint(false); } // first line std::string text_info(""); getFileInfoToDisplay(text_info, m_playlist[m_selected]); text_info += "\n"; // second line; url or date and genre if (m_inetmode) { if (!m_playlist[m_selected].MetaData.url.empty()) { text_info += m_playlist[m_selected].MetaData.url; } else text_info += " "; } else { bool got_date = false; if (!m_playlist[m_selected].MetaData.date.empty()) { got_date = true; text_info += m_playlist[m_selected].MetaData.date; } bool got_genre = false; if (!m_playlist[m_selected].MetaData.genre.empty()) { got_genre = true; if (got_date) text_info += " / "; text_info += m_playlist[m_selected].MetaData.genre; } if (!got_date && !got_genre) text_info += " "; } m_infobox->setText(text_info, CTextBox::AUTO_WIDTH, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO], COL_MENUCONTENTDARK_TEXT); m_infobox->paint(false); } else { if (m_detailsline != NULL) m_detailsline->kill(); if (m_infobox != NULL) m_infobox->kill(); } } void CAudioPlayerGui::stop() { m_state = CAudioPlayerGui::STOP; m_current = 0; if (!pictureviewer) { //LCD paintLCD(); //Display paintTitleBox(); m_key_level = 0; paintFoot(); } if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) CAudioPlayer::getInstance()->stop(); cleanupCovers(); if (m_streamripper_active) { ShowHint(LOCALE_MESSAGEBOX_INFO, LOCALE_AUDIOPLAYER_STREAMRIPPER_STOP, HINTBOX_MIN_WIDTH, 2); my_system(2, "streamripper.sh", "stop"); m_streamripper_active = false; } } void CAudioPlayerGui::pause() { if ( m_state == CAudioPlayerGui::PLAY || m_state == CAudioPlayerGui::FF || m_state == CAudioPlayerGui::REV ) { m_state = CAudioPlayerGui::PAUSE; CAudioPlayer::getInstance()->pause(); } else if (m_state == CAudioPlayerGui::PAUSE) { m_state = CAudioPlayerGui::PLAY; CAudioPlayer::getInstance()->pause(); } paintLCD(); } void CAudioPlayerGui::ff(unsigned int seconds) { if (m_state == CAudioPlayerGui::FF) { m_state = CAudioPlayerGui::PLAY; CAudioPlayer::getInstance()->ff(seconds); } else if ( m_state == CAudioPlayerGui::PLAY || m_state == CAudioPlayerGui::PAUSE || m_state == CAudioPlayerGui::REV ) { m_state = CAudioPlayerGui::FF; CAudioPlayer::getInstance()->ff(seconds); } paintLCD(); } void CAudioPlayerGui::rev(unsigned int seconds) { if (m_state == CAudioPlayerGui::REV) { m_state = CAudioPlayerGui::PLAY; CAudioPlayer::getInstance()->rev(seconds); } else if ( m_state == CAudioPlayerGui::PLAY || m_state == CAudioPlayerGui::PAUSE || m_state == CAudioPlayerGui::FF ) { m_state = CAudioPlayerGui::REV; CAudioPlayer::getInstance()->rev(seconds); } paintLCD(); } void CAudioPlayerGui::play(unsigned int pos) { //printf("AudioPlaylist: play %d/%d\n",pos,playlist.size()); unsigned int old_current = m_current; unsigned int old_selected = m_selected; cleanupCovers(); m_current = pos; if (g_settings.audioplayer_follow) m_selected = pos; if (m_selected - m_liststart >= m_listmaxshow && g_settings.audioplayer_follow) { m_liststart = m_selected; if (!CScreenSaver::getInstance()->isActive() && !pictureviewer) paint(); } else if (m_liststart < m_selected && g_settings.audioplayer_follow) { m_liststart = m_selected - m_listmaxshow + 1; if (!CScreenSaver::getInstance()->isActive() && !pictureviewer) paint(); } else { if (old_current >= m_liststart && old_current - m_liststart < m_listmaxshow) { if (!CScreenSaver::getInstance()->isActive() && !pictureviewer) paintItem(old_current - m_liststart); } if (pos >= m_liststart && pos - m_liststart < m_listmaxshow) { if (!CScreenSaver::getInstance()->isActive() && !pictureviewer) paintItem(pos - m_liststart); } if (g_settings.audioplayer_follow) { if (old_selected >= m_liststart && old_selected - m_liststart < m_listmaxshow) if (!CScreenSaver::getInstance()->isActive() && !pictureviewer) paintItem(old_selected - m_liststart); } } GetMetaData(m_playlist[pos]); m_metainfo.clear(); m_time_played = 0; m_time_total = m_playlist[m_current].MetaData.total_time; m_state = CAudioPlayerGui::PLAY; m_curr_audiofile = m_playlist[m_current]; if (CScreenSaver::getInstance()->isActive() && g_settings.audioplayer_cover_as_screensaver) CScreenSaver::getInstance()->forceRefresh(); // Play CAudioPlayer::getInstance()->play(&m_curr_audiofile, g_settings.audioplayer_highprio == 1); if (!pictureviewer) { //LCD paintLCD(); // Display paintTitleBox(); m_key_level = 1; paintFoot(); } } int CAudioPlayerGui::getNext() { int ret= m_current + 1; if (m_playlist.empty()) return -1; if ((unsigned)ret >= m_playlist.size()) { if (g_settings.audioplayer_repeat_on == 1) ret = 0; else ret = -1; } return ret; } void CAudioPlayerGui::updateMetaData() { bool updateMeta = false; bool updateLcd = false; bool updateScreen = false; if (m_state == CAudioPlayerGui::STOP) return; if (CAudioPlayer::getInstance()->hasMetaDataChanged() || m_metainfo.empty()) { const CAudioMetaData meta = CAudioPlayer::getInstance()->getMetaData(); std::stringstream info; info.precision(3); if (meta.bitrate > 0) { info << " / "; if (meta.vbr) info << "VBR "; info << meta.bitrate/1000 << "kbps"; } if (meta.samplerate > 0) info << " / " << meta.samplerate/1000 << "." << (meta.samplerate/100)%10 <<"kHz"; m_metainfo = meta.type_info + info.str(); updateMeta = !CScreenSaver::getInstance()->isActive(); if (!meta.artist.empty() && meta.artist != m_curr_audiofile.MetaData.artist) { m_curr_audiofile.MetaData.artist = meta.artist; if (!CScreenSaver::getInstance()->isActive()) updateScreen = true; updateLcd = true; } if (!meta.title.empty() && meta.title != m_curr_audiofile.MetaData.title) { m_curr_audiofile.MetaData.title = meta.title; if (!CScreenSaver::getInstance()->isActive()) updateScreen = true; updateLcd = true; } if (!meta.sc_station.empty() && meta.sc_station != m_curr_audiofile.MetaData.album) { m_curr_audiofile.MetaData.album = meta.sc_station; updateLcd = true; } if (!CScreenSaver::getInstance()->isActive()) paintCover(); } if (CAudioPlayer::getInstance()->hasMetaDataChanged() != 0) updateLcd = true; //printf("CAudioPlayerGui::updateMetaData: updateLcd %d\n", updateLcd); if (updateLcd) paintLCD(); if (updateScreen) paintTitleBox(); if (updateMeta || updateScreen) { m_frameBuffer->paintBoxRel(m_x + OFFSET_INNER_MID + m_cover_width, m_y + OFFSET_INNER_SMALL + 2*m_item_height + OFFSET_INNER_SMALL, m_width - 2*OFFSET_INNER_MID - m_cover_width, m_meta_height, m_titlebox->getColorBody()); int w = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(m_metainfo); int xstart = (m_width - w)/2; if (xstart < OFFSET_INNER_MID) xstart = OFFSET_INNER_MID; g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(m_x + xstart, m_y + OFFSET_INNER_SMALL + 2*m_item_height + OFFSET_INNER_SMALL + m_meta_height, m_width - 2*xstart, m_metainfo, COL_MENUHEAD_TEXT); } } void CAudioPlayerGui::updateTimes(const bool force) { if (m_state != CAudioPlayerGui::STOP) { bool updateTotal = force; bool updatePlayed = force; if (m_time_total != CAudioPlayer::getInstance()->getTimeTotal()) { m_time_total = CAudioPlayer::getInstance()->getTimeTotal(); if (m_curr_audiofile.MetaData.total_time != CAudioPlayer::getInstance()->getTimeTotal()) { m_curr_audiofile.MetaData.total_time = CAudioPlayer::getInstance()->getTimeTotal(); if (m_current >= 0) m_playlist[m_current].MetaData.total_time = CAudioPlayer::getInstance()->getTimeTotal(); } updateTotal = true; } if ((m_time_played != CAudioPlayer::getInstance()->getTimePlayed())) { m_time_played = CAudioPlayer::getInstance()->getTimePlayed(); updatePlayed = true; } if (!CScreenSaver::getInstance()->isActive()) { char total_time[17]; snprintf(total_time, sizeof(total_time), " / %ld:%02ld", m_time_total / 60, m_time_total % 60); char played_time[14]; snprintf(played_time, sizeof(played_time), "%ld:%02ld", m_time_played / 60, m_time_played % 60); int w_total_time = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(total_time); int w_faked_time = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth("000:00"); int w_played_time = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(played_time); // in inetmode we havn't a total_time if (m_inetmode) w_total_time = 0; int x_total_time = m_x + m_width - OFFSET_INNER_MID - w_total_time - 2*m_titlebox->getFrameThickness(); // played time offset to align this value on the right side int o_played_time = std::max(w_faked_time - w_played_time, 0); int x_faked_time = x_total_time - w_faked_time; int x_played_time = x_faked_time + o_played_time; int y_times = m_y + OFFSET_INNER_SMALL; if (updateTotal && !m_inetmode) { m_frameBuffer->paintBoxRel(x_total_time, y_times, w_total_time, m_item_height, m_titlebox->getColorBody()); if (m_time_total > 0) { g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x_total_time, y_times + m_item_height, w_total_time, total_time, COL_MENUHEAD_TEXT); //total time } } if (updatePlayed || (m_state == CAudioPlayerGui::PAUSE)) { m_frameBuffer->paintBoxRel(x_faked_time, y_times, w_faked_time, m_item_height, m_titlebox->getColorBody()); struct timeval tv; gettimeofday(&tv, NULL); if ((m_state != CAudioPlayerGui::PAUSE) || (tv.tv_sec & 1)) { g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x_played_time, y_times + m_item_height, w_played_time, played_time, COL_MENUHEAD_TEXT); //elapsed time } } } if ((updatePlayed || updateTotal) && m_curr_audiofile.FileType != CFile::STREAM_AUDIO && m_time_total != 0) { CVFD::getInstance()->showAudioProgress(uint8_t(100 * m_time_played / m_time_total)); } } } void CAudioPlayerGui::paintLCD() { switch (m_state) { case CAudioPlayerGui::STOP: CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_STOP); CVFD::getInstance()->showAudioProgress(0); break; case CAudioPlayerGui::PLAY: CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_PLAY); CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album); if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO && m_time_total != 0) CVFD::getInstance()->showAudioProgress(uint8_t(100 * m_time_played / m_time_total)); break; case CAudioPlayerGui::PAUSE: CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_PAUSE); CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album); break; case CAudioPlayerGui::FF: CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_FF); CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album); break; case CAudioPlayerGui::REV: CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_REV); CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album); break; } } void CAudioPlayerGui::GetMetaData(CAudiofileExt &File) { bool ret = 1; if (File.FileType != CFile::STREAM_AUDIO && !File.MetaData.bitrate) ret = CAudioPlayer::getInstance()->readMetaData(&File, m_state != CAudioPlayerGui::STOP && !g_settings.audioplayer_highprio); if (!ret || (File.MetaData.artist.empty() && File.MetaData.title.empty())) { //Set from Filename std::string tmp = File.Filename.substr(File.Filename.rfind('/') + 1); tmp = tmp.substr(0,tmp.length() - 4); //remove extension (.mp3) std::string::size_type i = tmp.rfind(" - "); if (i != std::string::npos) { // Trennzeichen " - " gefunden File.MetaData.artist = tmp.substr(0, i); File.MetaData.title = tmp.substr(i + 3); } else { i = tmp.rfind('-'); if (i != std::string::npos) { //Trennzeichen "-" File.MetaData.artist = tmp.substr(0, i); File.MetaData.title = tmp.substr(i + 1); } else File.MetaData.title = tmp; } File.MetaData.artist = FILESYSTEM_ENCODING_TO_UTF8_STRING(File.MetaData.artist); File.MetaData.title = FILESYSTEM_ENCODING_TO_UTF8_STRING(File.MetaData.title); } } bool CAudioPlayerGui::getNumericInput(neutrino_msg_t& msg, int& val) { //FIXME - remove fixed values neutrino_msg_data_t data; int x1 = (g_settings.screen_EndX - g_settings.screen_StartX) / 2 + g_settings.screen_StartX - 50; int y1 = (g_settings.screen_EndY - g_settings.screen_StartY) / 2 + g_settings.screen_StartY; char str[11]; do { val = val * 10 + CRCInput::getNumericValue(msg); sprintf(str, "%d", val); int w = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getRenderWidth(str); int h = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight(); m_frameBuffer->paintBoxRel(x1 - 7, y1 - h - 5, w + 14, h + 10, COL_FRAME_PLUS_0); m_frameBuffer->paintBoxRel(x1 - 6, y1 - h - 4, w + 12, h + 8, COL_MENUCONTENTSELECTED_PLUS_0); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(x1, y1, w + 1, str, COL_MENUCONTENTSELECTED_TEXT); while (true) { g_RCInput->getMsg(&msg, &data, 100); if (msg > CRCInput::RC_MaxRC && msg != CRCInput::RC_timeout) { // not a key event CNeutrinoApp::getInstance()->handleMsg(msg, data); continue; } if (msg & (CRCInput::RC_Repeat|CRCInput::RC_Release)) // repeat / release continue; break; } } while (g_RCInput->isNumeric(msg) && val < 1000000); return (msg == CRCInput::RC_ok); } void CAudioPlayerGui::getFileInfoToDisplay(std::string &fileInfo, CAudiofileExt &file) { //std::string fileInfo; std::string artist; std::string title; if (!m_inetmode) { artist ="Artist?"; title = "Title?"; } GetMetaData(file); if (!file.MetaData.artist.empty()) artist = file.MetaData.artist; if (!file.MetaData.title.empty()) title = file.MetaData.title; if (g_settings.audioplayer_display == TITLE_ARTIST) { fileInfo += title; if (!title.empty() && !artist.empty()) fileInfo += " - "; fileInfo += artist; } else //if (g_settings.audioplayer_display == ARTIST_TITLE) { fileInfo += artist; if (!title.empty() && !artist.empty()) fileInfo += " - "; fileInfo += title; } if (!file.MetaData.album.empty()) { fileInfo += " - "; fileInfo += file.MetaData.album; } if (fileInfo.empty()) { fileInfo += "Unknown"; } file.firstChar = (char)tolower(fileInfo[0]); //info += fileInfo; } void CAudioPlayerGui::addToPlaylist(CAudiofileExt &file) { //printf("add2Playlist: %s\n", file.Filename.c_str()); if (m_select_title_by_name) { std::string t(""); getFileInfoToDisplay(t,file); } else GetMetaData(file); m_playlist.push_back(file); m_playlistHasChanged = true; } void CAudioPlayerGui::removeFromPlaylist(long pos) { unsigned char firstChar = ' '; // must be called before m_playlist.erase() if (m_select_title_by_name) firstChar = getFirstChar(m_playlist[pos]); //unlink(m_playlist[pos].MetaData.cover.c_str()); m_playlist.erase(m_playlist.begin() + pos); m_playlistHasChanged = true; if (m_select_title_by_name) { #ifdef AUDIOPLAYER_TIME_DEBUG timeval start; gettimeofday(&start,NULL); #endif //printf("searching for key: %c val: %ld\n",firstChar,pos); CTitle2Pos::iterator item = m_title2Pos.find(firstChar); if (item != m_title2Pos.end()) { item->second.erase(pos); // delete empty entries if (item->second.empty()) m_title2Pos.erase(item); } else { printf("could not find key: %c pos: %ld\n",firstChar,pos); } // decrease position information for all titles with a position // behind item to delete long p = 0; for (CTitle2Pos::iterator title=m_title2Pos.begin(); title!=m_title2Pos.end(); ++title) { CPosList newList; for (CPosList::iterator posIt=title->second.begin(); posIt!=title->second.end(); ++posIt) { p = *(posIt); if (*posIt > pos) p--; // old list is sorted so we can give a hint to insert at the end newList.insert(newList.end(), p); } title->second = newList; } #ifdef AUDIOPLAYER_TIME_DEBUG timeval end; gettimeofday(&end,NULL); printf("delete took: "); printTimevalDiff(start,end); #endif } } void CAudioPlayerGui::selectTitle(unsigned char selectionChar) { unsigned long i; //printf("fastLookup: key %c\n",selectionChar); CTitle2Pos::iterator it = m_title2Pos.find(selectionChar); if (it!=m_title2Pos.end()) { // search for the next greater id // if nothing found take the first CPosList::iterator posIt = it->second.upper_bound(m_selected); if (posIt != it->second.end()) { i = *posIt; //printf("upper bound i: %ld\n",i); } else { if (!it->second.empty()) { i = *(it->second.begin()); //printf("using begin i: %ld\n",i); } else { //printf("no title with that key\n"); return; } } } else { //printf("no title with that key\n"); return; } int prevselected = m_selected; m_selected = i; unsigned int oldliststart = m_liststart; m_liststart = (m_selected / m_listmaxshow)*m_listmaxshow; //printf("before paint\n"); if (oldliststart != m_liststart) { paint(); } else { paintItem(prevselected - m_liststart); paintItem(m_selected - m_liststart); } } void CAudioPlayerGui::printSearchTree() { for (CTitle2Pos::iterator it=m_title2Pos.begin(); it!=m_title2Pos.end(); ++it) { printf("key: %c\n",it->first); long pos=-1; for (CPosList::iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { pos++; printf(" val: %ld ",*it2); if (pos % 5 == 4) printf("\n"); } printf("\n"); } } void CAudioPlayerGui::buildSearchTree() { //printf("before\n"); //printSearchTree(); #ifdef AUDIOPLAYER_TIME_DEBUG timeval start; gettimeofday(&start,NULL); #endif CProgressWindow progress; progress.setTitle(LOCALE_AUDIOPLAYER_BUILDING_SEARCH_INDEX); progress.exec(this, ""); long maxProgress = (m_playlist.size() > 1) ? m_playlist.size() - 1 : 1; m_title2Pos.clear(); long listPos = -1; for (CAudioPlayList::iterator it=m_playlist.begin(); it!=m_playlist.end(); ++it) { listPos++; progress.showStatus(100*listPos / maxProgress); progress.showStatusMessageUTF(it->Filename); unsigned char firstChar = getFirstChar(*it); const std::pair item = m_title2Pos.insert(CTitle2PosItem(firstChar,CPosList())); item.first->second.insert(listPos); } progress.hide(); m_playlistHasChanged = false; #ifdef AUDIOPLAYER_TIME_DEBUG timeval end; gettimeofday(&end,NULL); printf("searchtree took: "); printTimevalDiff(start,end); #endif //printf("after:\n"); //printSearchTree(); } unsigned char CAudioPlayerGui::getFirstChar(CAudiofileExt &file) { if (file.firstChar == '\0') { std::string info(""); getFileInfoToDisplay(info, file); } //printf("getFirstChar: %c\n",file.firstChar); return file.firstChar; } #ifdef AUDIOPLAYER_TIME_DEBUG void CAudioPlayerGui::printTimevalDiff(timeval &start, timeval &end) { long secs = end.tv_sec - start.tv_sec; long usecs = end.tv_usec -start.tv_usec; if (usecs < 0) { usecs = 1000000 + usecs; secs--; } printf("%ld:%ld\n",secs,usecs); } #endif void CAudioPlayerGui::savePlaylist() { const char *path; // .m3u playlist // http://hanna.pyxidis.org/tech/m3u.html CFileBrowser browser; browser.Multi_Select = false; browser.Dir_Mode = true; CFileFilter dirFilter; dirFilter.addFilter("m3u"); browser.Filter = &dirFilter; // select preferred directory if exists if (!g_settings.network_nfs_audioplayerdir.empty()) path = g_settings.network_nfs_audioplayerdir.c_str(); else path = "/"; // let user select target directory this->hide(); if (browser.exec(path)) { // refresh view this->paint(); CFile *file = browser.getSelectedFile(); std::string absPlaylistDir = file->getPath(); // add a trailing slash if necessary if ((absPlaylistDir.empty()) || ((*(absPlaylistDir.rbegin()) != '/'))) absPlaylistDir += '/'; absPlaylistDir += file->getFileName(); const int filenamesize = 30; std::string filename = "playlist"; if (file->getType() == CFile::FILE_PLAYLIST) { // file is playlist so we should ask if we can overwrite it std::string name = file->getPath(); name += '/'; name += file->getFileName(); bool overwrite = askToOverwriteFile(name); if (!overwrite) return; filename = name; } else if (file->getType() == CFile::FILE_DIR) { // query for filename this->hide(); CKeyboardInput filenameInput(LOCALE_AUDIOPLAYER_PLAYLIST_NAME, &filename, filenamesize - 1, NULL, NULL, LOCALE_AUDIOPLAYER_PLAYLIST_NAME_HINT1, LOCALE_AUDIOPLAYER_PLAYLIST_NAME_HINT2); filenameInput.exec(NULL, ""); // refresh view this->paint(); std::string name = absPlaylistDir; name += '/'; name += filename; name += ".m3u"; std::ifstream input(name.c_str()); // test if file exists and query for overwriting it or not if (input.is_open()) { bool overwrite = askToOverwriteFile(name); if (!overwrite) return; } input.close(); } else { std::cout << "CAudioPlayerGui: neither .m3u nor directory selected, abort" << std::endl; return; } std::string absPlaylistFilename = absPlaylistDir; absPlaylistFilename += '/'; absPlaylistFilename += filename; absPlaylistFilename += ".m3u"; std::ofstream playlistFile(absPlaylistFilename.c_str()); std::cout << "CAudioPlayerGui: writing playlist to " << absPlaylistFilename << std::endl; if (!playlistFile) { // an error occured const int msgsize = 255; char msg[msgsize] = ""; snprintf(msg, msgsize, "%s\n%s", g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYLIST_FILEERROR_MSG), absPlaylistFilename.c_str()); DisplayErrorMessage(msg); // refresh view this->paint(); std::cout << "CAudioPlayerGui: could not create play list file " << absPlaylistFilename << std::endl; return; } // writing .m3u file playlistFile << "#EXTM3U" << std::endl; CAudioPlayList::const_iterator it; for (it = m_playlist.begin(); it!=m_playlist.end(); ++it) { playlistFile << "#EXTINF:" << it->MetaData.total_time << "," << it->MetaData.artist << " - " << it->MetaData.title << std::endl; if (m_inetmode) playlistFile << it->Filename << std::endl; else playlistFile << absPath2Rel(absPlaylistDir, it->Filename) << std::endl; } playlistFile.close(); } this->paint(); } bool CAudioPlayerGui::askToOverwriteFile(const std::string& filename) { char msg[filename.length() + 127]; snprintf(msg, filename.length() + 126, "%s\n%s", g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYLIST_FILEOVERWRITE_MSG), filename.c_str()); bool res = (ShowMsg(LOCALE_AUDIOPLAYER_PLAYLIST_FILEOVERWRITE_TITLE, msg, CMsgBox::mbrYes, CMsgBox::mbYes | CMsgBox::mbNo) == CMsgBox::mbrYes); this->paint(); return res; } std::string CAudioPlayerGui::absPath2Rel(const std::string& fromDir, const std::string& absFilename) { std::string res = ""; int length = fromDir.length() < absFilename.length() ? fromDir.length() : absFilename.length(); int lastSlash = 0; // find common prefix for both paths // fromDir: /foo/bar/angle/1 (length: 16) // absFilename: /foo/bar/devil/2/fire.mp3 (length: 19) // -> /foo/bar/ is prefix, lastSlash will be 8 for (int i=0; i -1) { while (n--) { const char *coverfile = coverlist[n]->d_name; if (strcmp(coverfile, ".") != 0 && strcmp(coverfile, "..") != 0) { printf("[audioplayer] removing cover %s/%s\n", COVERDIR_TMP, coverfile); unlink(((std::string)COVERDIR_TMP + "/" + coverfile).c_str()); } free(coverlist[n]); } free(coverlist); } } m_cover.clear(); m_stationlogo = false; }