nathan@0: /* nathan@0: * MP3/MPlayer plugin to VDR (C++) nathan@0: * nathan@0: * (C) 2001-2007 Stefan Huelswitt nathan@0: * nathan@0: * This code is free software; you can redistribute it and/or nathan@0: * modify it under the terms of the GNU General Public License nathan@0: * as published by the Free Software Foundation; either version 2 nathan@0: * of the License, or (at your option) any later version. nathan@0: * nathan@0: * This code is distributed in the hope that it will be useful, nathan@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of nathan@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nathan@0: * GNU General Public License for more details. nathan@0: * nathan@0: * You should have received a copy of the GNU General Public License nathan@0: * along with this program; if not, write to the Free Software nathan@0: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. nathan@0: * Or, point your browser to http://www.gnu.org/copyleft/gpl.html nathan@0: */ nathan@0: nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: nathan@0: #include "common.h" nathan@0: nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #if APIVERSNUM >= 10307 nathan@0: #include nathan@0: #include nathan@0: #endif nathan@0: nathan@0: #include "setup.h" nathan@0: #include "setup-mp3.h" nathan@0: #include "data-mp3.h" nathan@0: #include "data-src.h" nathan@0: #include "player-mp3.h" nathan@0: #include "menu.h" nathan@0: #include "menu-async.h" nathan@0: #include "decoder.h" nathan@0: #include "i18n.h" nathan@0: #include "version.h" nathan@0: #include "service.h" nathan@0: nathan@0: #ifdef DEBUG nathan@0: #include nathan@0: #endif nathan@0: nathan@0: const char *sourcesSub=0; nathan@0: cFileSources MP3Sources; nathan@0: nathan@2: static const char *plugin_name=0; nathan@2: nathan@0: // --- cMenuSetupMP3 -------------------------------------------------------- nathan@0: nathan@0: class cMenuSetupMP3 : public cMenuSetupPage { nathan@0: private: nathan@0: cMP3Setup data; nathan@0: // nathan@0: const char *cddb[3], *disp[2], *scan[3], *bgr[3]; nathan@0: const char *aout[AUDIOOUTMODES]; nathan@0: int amode, amodes[AUDIOOUTMODES]; nathan@0: protected: nathan@0: virtual void Store(void); nathan@0: public: nathan@0: cMenuSetupMP3(void); nathan@0: }; nathan@0: nathan@0: cMenuSetupMP3::cMenuSetupMP3(void) nathan@0: { nathan@0: static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789-_" }; nathan@0: int numModes=0; nathan@2: aout[numModes]=trVDR("DVB"); amodes[numModes]=AUDIOOUTMODE_DVB; numModes++; nathan@0: #ifdef WITH_OSS nathan@0: aout[numModes]=tr("OSS"); amodes[numModes]=AUDIOOUTMODE_OSS; numModes++; nathan@0: #endif nathan@0: data=MP3Setup; nathan@0: amode=0; nathan@0: for(int i=0; i= 10307 nathan@0: disp[0]=tr("classic"); nathan@0: disp[1]=tr("via skin"); nathan@0: Add(new cMenuEditStraItem(tr("Setup.MP3$Replay display"), &data.ReplayDisplay, 2, disp)); nathan@0: #endif nathan@0: Add(new cMenuEditIntItem( tr("Setup.MP3$Display mode"), &data.DisplayMode, 1, 3)); nathan@0: bgr[0]=tr("Black"); nathan@0: bgr[1]=tr("Live"); nathan@0: bgr[2]=tr("Images"); nathan@0: Add(new cMenuEditStraItem(tr("Setup.MP3$Background mode"), &data.BackgrMode, 3, bgr)); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MP3$Initial loop mode"), &data.InitLoopMode)); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MP3$Initial shuffle mode"), &data.InitShuffleMode)); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MP3$Abort player at end of list"),&data.AbortAtEOL)); nathan@0: scan[0]=tr("disabled"); nathan@0: scan[1]=tr("ID3 only"); nathan@0: scan[2]=tr("ID3 & Level"); nathan@0: Add(new cMenuEditStraItem(tr("Setup.MP3$Background scan"), &data.BgrScan, 3, scan)); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MP3$Editor display mode"), &data.EditorMode, tr("Filenames"), tr("ID3 names"))); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MP3$Mainmenu mode"), &data.MenuMode, tr("Playlists"), tr("Browser"))); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MP3$Keep selection menu"), &data.KeepSelect)); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MP3$Title/Artist order"), &data.TitleArtistOrder, tr("Normal"), tr("Reversed"))); nathan@0: Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &data.HideMainMenu)); nathan@0: Add(new cMenuEditIntItem( tr("Setup.MP3$Normalizer level"), &data.TargetLevel, 0, MAX_TARGET_LEVEL)); nathan@0: Add(new cMenuEditIntItem( tr("Setup.MP3$Limiter level"), &data.LimiterLevel, MIN_LIMITER_LEVEL, 100)); nathan@0: Add(new cMenuEditBoolItem(tr("Setup.MP3$Use HTTP proxy"), &data.UseProxy)); nathan@0: Add(new cMenuEditStrItem( tr("Setup.MP3$HTTP proxy host"), data.ProxyHost,MAX_HOSTNAME,allowed)); nathan@0: Add(new cMenuEditIntItem( tr("Setup.MP3$HTTP proxy port"), &data.ProxyPort,1,65535)); nathan@0: cddb[0]=tr("disabled"); nathan@0: cddb[1]=tr("local only"); nathan@0: cddb[2]=tr("local&remote"); nathan@0: Add(new cMenuEditStraItem(tr("Setup.MP3$CDDB for CD-Audio"), &data.UseCddb,3,cddb)); nathan@0: Add(new cMenuEditStrItem( tr("Setup.MP3$CDDB server"), data.CddbHost,MAX_HOSTNAME,allowed)); nathan@0: Add(new cMenuEditIntItem( tr("Setup.MP3$CDDB port"), &data.CddbPort,1,65535)); nathan@0: } nathan@0: nathan@0: void cMenuSetupMP3::Store(void) nathan@0: { nathan@0: data.AudioOutMode=amodes[amode]; nathan@0: nathan@0: MP3Setup=data; nathan@0: SetupStore("InitLoopMode", MP3Setup.InitLoopMode ); nathan@0: SetupStore("InitShuffleMode", MP3Setup.InitShuffleMode); nathan@0: SetupStore("AudioMode", MP3Setup.AudioMode ); nathan@0: SetupStore("AudioOutMode", MP3Setup.AudioOutMode ); nathan@0: SetupStore("BgrScan", MP3Setup.BgrScan ); nathan@0: SetupStore("EditorMode", MP3Setup.EditorMode ); nathan@0: SetupStore("DisplayMode", MP3Setup.DisplayMode ); nathan@0: SetupStore("BackgrMode", MP3Setup.BackgrMode ); nathan@0: SetupStore("MenuMode", MP3Setup.MenuMode ); nathan@0: SetupStore("TargetLevel", MP3Setup.TargetLevel ); nathan@0: SetupStore("LimiterLevel", MP3Setup.LimiterLevel ); nathan@0: SetupStore("Only48kHz", MP3Setup.Only48kHz ); nathan@0: SetupStore("UseProxy", MP3Setup.UseProxy ); nathan@0: SetupStore("ProxyHost", MP3Setup.ProxyHost ); nathan@0: SetupStore("ProxyPort", MP3Setup.ProxyPort ); nathan@0: SetupStore("UseCddb", MP3Setup.UseCddb ); nathan@0: SetupStore("CddbHost", MP3Setup.CddbHost ); nathan@0: SetupStore("CddbPort", MP3Setup.CddbPort ); nathan@0: SetupStore("AbortAtEOL", MP3Setup.AbortAtEOL ); nathan@0: #if APIVERSNUM >= 10307 nathan@0: SetupStore("ReplayDisplay", MP3Setup.ReplayDisplay ); nathan@0: #endif nathan@0: SetupStore("HideMainMenu", MP3Setup.HideMainMenu ); nathan@0: SetupStore("KeepSelect", MP3Setup.KeepSelect ); nathan@0: SetupStore("TitleArtistOrder", MP3Setup.TitleArtistOrder); nathan@0: } nathan@0: nathan@0: // --- cAsyncStatus ------------------------------------------------------------ nathan@0: nathan@0: cAsyncStatus asyncStatus; nathan@0: nathan@0: cAsyncStatus::cAsyncStatus(void) nathan@0: { nathan@0: text=0; nathan@0: changed=false; nathan@0: } nathan@0: nathan@0: cAsyncStatus::~cAsyncStatus() nathan@0: { nathan@0: free((void *)text); nathan@0: } nathan@0: nathan@0: void cAsyncStatus::Set(const char *Text) nathan@0: { nathan@0: Lock(); nathan@0: free((void *)text); nathan@0: text=Text ? strdup(Text) : 0; nathan@0: changed=true; nathan@0: Unlock(); nathan@0: } nathan@0: nathan@0: const char *cAsyncStatus::Begin(void) nathan@0: { nathan@0: Lock(); nathan@0: return text; nathan@0: } nathan@0: nathan@0: void cAsyncStatus::Finish(void) nathan@0: { nathan@0: changed=false; nathan@0: Unlock(); nathan@0: } nathan@0: nathan@0: // --- -------------------------------------------------------------------- nathan@0: nathan@0: static const char *TitleArtist(const char *title, const char *artist) nathan@0: { nathan@0: static char buf[256]; // clearly not multi-thread save! nathan@0: char *fmt; nathan@0: if(artist && artist[0]) { nathan@0: if(MP3Setup.TitleArtistOrder) fmt="%2$s - %1$s"; nathan@0: else fmt="%s - %s"; nathan@0: } nathan@0: else fmt="%s"; nathan@0: snprintf(buf,sizeof(buf),fmt,title,artist); nathan@0: return buf; nathan@0: } nathan@0: nathan@0: // --- cMP3Control -------------------------------------------------------- nathan@0: nathan@0: #if APIVERSNUM >= 10307 nathan@0: #define clrBackground clrGray50 nathan@0: #define eDvbColor int nathan@0: #define MAXROWS 120 nathan@0: #define INLINE nathan@0: #else nathan@0: #define MAXROWS MAXOSDHEIGHT nathan@0: #define INLINE inline nathan@0: #endif nathan@0: nathan@0: class cMP3Control : public cControl { nathan@0: private: nathan@0: #if APIVERSNUM >= 10307 nathan@0: cOsd *osd; nathan@0: const cFont *font; nathan@0: cSkinDisplayReplay *disp; nathan@0: #else nathan@0: bool statusInterfaceOpen; nathan@0: #endif nathan@0: int bw, bh, bwc, fw, fh; nathan@0: // nathan@0: cMP3Player *player; nathan@0: bool visible, shown, bigwin, statusActive; nathan@0: time_t timeoutShow, greentime, oktime; nathan@0: int lastkeytime, number; nathan@0: bool selecting, selecthide; nathan@0: // nathan@0: cMP3PlayInfo *lastMode; nathan@0: time_t fliptime, listtime; nathan@0: int hashlist[MAXROWS]; nathan@0: int flip, flipint, top, rows; nathan@0: int lastIndex, lastTotal, lastTop; nathan@0: int framesPerSecond; nathan@0: // nathan@0: bool jumpactive, jumphide, jumpsecs; nathan@0: int jumpmm; nathan@0: // nathan@0: void ShowTimed(int Seconds=0); nathan@0: void ShowProgress(bool open=false, bool bigWin=false); nathan@0: void ShowStatus(bool force); nathan@0: void HideStatus(void); nathan@0: void DisplayInfo(const char *s=0); nathan@0: void JumpDisplay(void); nathan@0: void JumpProcess(eKeys Key); nathan@0: void Jump(void); nathan@0: void Stop(void); nathan@0: INLINE void Write(int x, int y, int w, const char *text, eDvbColor fg=clrWhite, eDvbColor bg=clrBackground); nathan@0: INLINE void Fill(int x, int y, int w, int h, eDvbColor fg); nathan@0: inline void Flush(void); nathan@0: public: nathan@0: cMP3Control(void); nathan@0: virtual ~cMP3Control(); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: virtual void Show(void) { ShowTimed(); } nathan@0: virtual void Hide(void); nathan@0: bool Visible(void) { return visible; } nathan@0: static bool SetPlayList(cPlayList *plist); nathan@0: }; nathan@0: nathan@0: cMP3Control::cMP3Control(void) nathan@0: :cControl(player=new cMP3Player) nathan@0: { nathan@0: visible=shown=bigwin=selecting=selecthide=jumpactive=jumphide=statusActive=false; nathan@0: timeoutShow=greentime=oktime=0; nathan@0: lastkeytime=number=0; nathan@0: lastMode=0; nathan@0: framesPerSecond=SecondsToFrames(1); nathan@0: #if APIVERSNUM >= 10307 nathan@0: osd=0; disp=0; nathan@0: font=cFont::GetFont(fontOsd); nathan@0: #else nathan@0: statusInterfaceOpen=false; nathan@0: #endif nathan@0: #if APIVERSNUM >= 10338 nathan@0: cStatus::MsgReplaying(this,"MP3",0,true); nathan@0: #else nathan@0: cStatus::MsgReplaying(this,"MP3"); nathan@0: #endif nathan@0: } nathan@0: nathan@0: cMP3Control::~cMP3Control() nathan@0: { nathan@0: delete lastMode; nathan@0: Hide(); nathan@0: Stop(); nathan@0: } nathan@0: nathan@0: void cMP3Control::Stop(void) nathan@0: { nathan@0: #if APIVERSNUM >= 10338 nathan@0: cStatus::MsgReplaying(this,0,0,false); nathan@0: #else nathan@0: cStatus::MsgReplaying(this,0); nathan@0: #endif nathan@0: delete player; player=0; nathan@0: mgr->Halt(); nathan@0: mgr->Flush(); //XXX remove later nathan@0: } nathan@0: nathan@0: bool cMP3Control::SetPlayList(cPlayList *plist) nathan@0: { nathan@0: bool res; nathan@0: cControl *control=cControl::Control(); nathan@0: // is there a running MP3 player? nathan@0: if(control && typeid(*control)==typeid(cMP3Control)) { nathan@0: // add songs to running playlist nathan@0: mgr->Add(plist); nathan@0: res=true; nathan@0: } nathan@0: else { nathan@0: mgr->Flush(); nathan@0: mgr->Add(plist); nathan@0: cControl::Launch(new cMP3Control); nathan@0: res=false; nathan@0: } nathan@0: delete plist; nathan@0: return res; nathan@0: } nathan@0: nathan@0: void cMP3Control::ShowTimed(int Seconds) nathan@0: { nathan@0: if(!visible) { nathan@0: ShowProgress(true); nathan@0: if(Seconds>0) timeoutShow=time(0)+Seconds; nathan@0: } nathan@0: } nathan@0: nathan@0: void cMP3Control::Hide(void) nathan@0: { nathan@0: HideStatus(); nathan@0: if(visible) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: delete osd; osd=0; nathan@0: delete disp; disp=0; nathan@0: #else nathan@0: Interface->Close(); nathan@0: #endif nathan@0: visible=bigwin=false; nathan@0: #if APIVERSNUM >= 10500 nathan@0: SetNeedsFastResponse(false); nathan@0: #else nathan@0: needsFastResponse=false; nathan@0: #endif nathan@0: } nathan@0: } nathan@0: nathan@0: void cMP3Control::ShowStatus(bool force) nathan@0: { nathan@0: if((asyncStatus.Changed() || (force && !statusActive)) && !jumpactive) { nathan@0: const char *text=asyncStatus.Begin(); nathan@0: if(text) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay || !osd) { nathan@0: if(statusActive) Skins.Message(mtStatus,0); nathan@0: Skins.Message(mtStatus,text); nathan@0: } nathan@0: else { nathan@0: if(!statusActive) osd->SaveRegion(0,bh-2*fh,bw-1,bh-fh-1); nathan@0: osd->DrawText(0,bh-2*fh,text,clrBlack,clrCyan,font,bw,fh,taCenter); nathan@0: osd->Flush(); nathan@0: } nathan@0: #else nathan@0: if(!Interface->IsOpen()) { nathan@0: Interface->Open(0,-1); nathan@0: statusInterfaceOpen=true; nathan@0: } nathan@0: Interface->Status(text); nathan@0: Interface->Flush(); nathan@0: #endif nathan@0: statusActive=true; nathan@0: } nathan@0: else nathan@0: HideStatus(); nathan@0: asyncStatus.Finish(); nathan@0: } nathan@0: } nathan@0: nathan@0: void cMP3Control::HideStatus(void) nathan@0: { nathan@0: if(statusActive) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay || !osd) nathan@0: Skins.Message(mtStatus,0); nathan@0: else { nathan@0: osd->RestoreRegion(); nathan@0: osd->Flush(); nathan@0: } nathan@0: #else nathan@0: if(statusInterfaceOpen) { nathan@0: Interface->Close(); nathan@0: statusInterfaceOpen=false; nathan@0: } nathan@0: else { nathan@0: Interface->Status(0); nathan@0: Interface->Flush(); nathan@0: } nathan@0: #endif nathan@0: } nathan@0: statusActive=false; nathan@0: } nathan@0: nathan@0: #define CTAB 11 // some tabbing values for the progress display nathan@0: #define CTAB2 5 nathan@0: nathan@0: void cMP3Control::Write(int x, int y, int w, const char *text, eDvbColor fg, eDvbColor bg) nathan@0: { nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(osd) { nathan@0: //d(printf("write x=%d y=%d w=%d ->",x,y,w)) nathan@0: x*=fw; if(x<0) x+=bw; nathan@0: y*=fh; if(y<0) y+=bh; nathan@0: osd->DrawText(x,y,text,fg,bg,font,w*fw); nathan@0: //d(printf(" x=%d y=%d w=%d\n",x,y,w*fw)) nathan@0: } nathan@0: #else nathan@0: if(w>0) Fill(x,y,w,1,bg); nathan@0: Interface->Write(x,y,text,fg,bg); nathan@0: #endif nathan@0: } nathan@0: nathan@0: void cMP3Control::Fill(int x, int y, int w, int h, eDvbColor fg) nathan@0: { nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(osd) { nathan@0: //d(printf("fill x=%d y=%d w=%d h=%d ->",x,y,w,h)) nathan@0: x*=fw; if(x<0) x+=bw; nathan@0: y*=fh; if(y<0) y+=bh; nathan@0: osd->DrawRectangle(x,y,x+w*fw-1,y+h*fh-1,fg); nathan@0: //d(printf(" x=%d y=%d x2=%d y2=%d\n",x,y,x+h*fh-1,y+w*fw-1)) nathan@0: } nathan@0: #else nathan@0: Interface->Fill(x,y,w,h,fg); nathan@0: #endif nathan@0: } nathan@0: nathan@0: void cMP3Control::Flush(void) nathan@0: { nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay) Skins.Flush(); nathan@0: else if(osd) osd->Flush(); nathan@0: #else nathan@0: Interface->Flush(); nathan@0: #endif nathan@0: } nathan@0: nathan@0: void cMP3Control::ShowProgress(bool open, bool bigWin) nathan@0: { nathan@0: int index, total; nathan@0: nathan@0: if(player->GetIndex(index,total) && total>=0) { nathan@0: if(!visible && open) { nathan@0: HideStatus(); nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay) { nathan@0: disp=Skins.Current()->DisplayReplay(false); nathan@0: if(!disp) return; nathan@0: bigWin=false; nathan@0: } nathan@0: else { nathan@0: int bt, bp; nathan@0: fw=font->Width(' ')*2; nathan@0: fh=font->Height(); nathan@0: if(bigWin) { nathan@0: bw=Setup.OSDWidth; nathan@0: bh=Setup.OSDHeight; nathan@0: bt=0; nathan@0: bp=2*fh; nathan@0: rows=(bh-bp-fh/3)/fh; nathan@0: } nathan@0: else { nathan@0: bw=Setup.OSDWidth; nathan@0: bh=bp=2*fh; nathan@0: bt=Setup.OSDHeight-bh; nathan@0: rows=0; nathan@0: } nathan@0: bwc=bw/fw+1; nathan@0: //d(printf("mp3: bw=%d bh=%d bt=%d bp=%d bwc=%d rows=%d fw=%d fh=%d\n", nathan@0: // bw,bh,bt,bp,bwc,rows,fw,fh)) nathan@0: osd=cOsdProvider::NewOsd(Setup.OSDLeft,Setup.OSDTop+bt); nathan@0: if(!osd) return; nathan@0: if(bigWin) { nathan@0: tArea Areas[] = { { 0,0,bw-1,bh-bp-1,2 }, { 0,bh-bp,bw-1,bh-1,4 } }; nathan@0: osd->SetAreas(Areas,sizeof(Areas)/sizeof(tArea)); nathan@0: } nathan@0: else { nathan@0: tArea Areas[] = { { 0,0,bw-1,bh-1,4 } }; nathan@0: osd->SetAreas(Areas,sizeof(Areas)/sizeof(tArea)); nathan@0: } nathan@0: osd->DrawRectangle(0,0,bw-1,bh-1,clrGray50); nathan@0: osd->Flush(); nathan@0: } nathan@0: #else nathan@0: fw=cOsd::CellWidth(); nathan@0: fh=cOsd::LineHeight(); nathan@0: bh=bigWin ? Setup.OSDheight : -2; nathan@0: bw=bwc=Setup.OSDwidth; nathan@0: rows=Setup.OSDheight-3; nathan@0: Interface->Open(bw,bh); nathan@0: Interface->Clear(); nathan@0: #endif nathan@0: ShowStatus(true); nathan@0: bigwin=bigWin; nathan@0: visible=true; nathan@0: #if APIVERSNUM >= 10500 nathan@0: SetNeedsFastResponse(true); nathan@0: #else nathan@0: needsFastResponse=true; nathan@0: #endif nathan@0: fliptime=listtime=0; flipint=0; flip=-1; top=lastTop=-1; lastIndex=lastTotal=-1; nathan@0: delete lastMode; lastMode=0; nathan@0: } nathan@0: nathan@0: cMP3PlayInfo *mode=new cMP3PlayInfo; nathan@0: bool valid=mgr->Info(-1,mode); nathan@0: bool changed=(!lastMode || mode->Hash!=lastMode->Hash); nathan@0: char buf[256]; nathan@0: if(changed) { d(printf("mp3-ctrl: mode change detected\n")) } nathan@0: nathan@0: if(valid) { // send progress to status monitor nathan@0: if(changed || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle) { nathan@0: snprintf(buf,sizeof(buf),"[%c%c] (%d/%d) %s", nathan@0: mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,TitleArtist(mode->Title,mode->Artist)); nathan@0: #if APIVERSNUM >= 10338 nathan@0: cStatus::MsgReplaying(this,buf,mode->Filename[0]?mode->Filename:0,true); nathan@0: #else nathan@0: cStatus::MsgReplaying(this,buf); nathan@0: #endif nathan@0: } nathan@0: } nathan@0: nathan@0: if(visible) { // refresh the OSD progress display nathan@0: bool flush=false; nathan@0: nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay) { nathan@0: if(!statusActive) { nathan@0: if(total>0) disp->SetProgress(index,total); nathan@0: disp->SetCurrent(IndexToHMSF(index)); nathan@0: disp->SetTotal(IndexToHMSF(total)); nathan@0: bool Play, Forward; nathan@0: int Speed; nathan@0: if(GetReplayMode(Play,Forward,Speed)) nathan@0: disp->SetMode(Play, Forward, Speed); nathan@0: flush=true; nathan@0: } nathan@0: } nathan@0: else { nathan@0: #endif nathan@0: if(!selecting && changed && !statusActive) { nathan@0: snprintf(buf,sizeof(buf),"(%d/%d)",mode->Num,mode->MaxNum); nathan@0: Write(0,-2,CTAB,buf); nathan@0: flush=true; nathan@0: } nathan@0: nathan@0: if(!lastMode || mode->Loop!=lastMode->Loop) { nathan@0: if(mode->Loop) Write(-4,-1,0,"L",clrBlack,clrYellow); nathan@0: else Fill(-4,-1,2,1,clrBackground); nathan@0: flush=true; nathan@0: } nathan@0: if(!lastMode || mode->Shuffle!=lastMode->Shuffle) { nathan@0: if(mode->Shuffle) Write(-2,-1,0,"S",clrWhite,clrRed); nathan@0: else Fill(-2,-1,2,1,clrBackground); nathan@0: flush=true; nathan@0: } nathan@0: nathan@0: index/=framesPerSecond; total/=framesPerSecond; nathan@0: if(index!=lastIndex || total!=lastTotal) { nathan@0: if(total>0) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: cProgressBar ProgressBar(bw-(CTAB+CTAB2)*fw,fh,index,total); nathan@0: osd->DrawBitmap(CTAB*fw,bh-fh,ProgressBar); nathan@0: #else nathan@0: cProgressBar ProgressBar((bw-CTAB-CTAB2)*fw,fh,index,total); nathan@0: Interface->SetBitmap(CTAB*fw,(abs(bh)-1)*fh,ProgressBar); nathan@0: #endif nathan@0: } nathan@0: snprintf(buf,sizeof(buf),total?"%02d:%02d/%02d:%02d":"%02d:%02d",index/60,index%60,total/60,total%60); nathan@0: Write(0,-1,11,buf); nathan@0: flush=true; nathan@0: } nathan@0: #if APIVERSNUM >= 10307 nathan@0: } nathan@0: #endif nathan@0: nathan@0: if(!jumpactive) { nathan@0: bool doflip=false; nathan@0: if(MP3Setup.ReplayDisplay && (!lastMode || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle)) nathan@0: doflip=true; nathan@0: if(!valid || changed) { nathan@0: fliptime=time(0); flip=0; nathan@0: doflip=true; nathan@0: } nathan@0: else if(time(0)>fliptime+flipint) { nathan@0: fliptime=time(0); nathan@0: flip++; if(flip>=MP3Setup.DisplayMode) flip=0; nathan@0: doflip=true; nathan@0: } nathan@0: if(doflip) { nathan@0: buf[0]=0; nathan@0: switch(flip) { nathan@0: default: nathan@0: flip=0; nathan@0: // fall through nathan@0: case 0: nathan@0: snprintf(buf,sizeof(buf),"%s",TitleArtist(mode->Title,mode->Artist)); nathan@0: flipint=6; nathan@0: break; nathan@0: case 1: nathan@0: if(mode->Album[0]) { nathan@0: snprintf(buf,sizeof(buf),mode->Year>0?"from: %s (%d)":"from: %s",mode->Album,mode->Year); nathan@0: flipint=4; nathan@0: } nathan@0: else fliptime=0; nathan@0: break; nathan@0: case 2: nathan@0: if(mode->MaxBitrate>0) nathan@0: snprintf(buf,sizeof(buf),"%.1f kHz, %d-%d kbps, %s",mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->MaxBitrate/1000,mode->SMode); nathan@0: else nathan@0: snprintf(buf,sizeof(buf),"%.1f kHz, %d kbps, %s",mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->SMode); nathan@0: flipint=3; nathan@0: break; nathan@0: } nathan@0: if(buf[0]) { nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay) { nathan@0: char buf2[256]; nathan@0: snprintf(buf2,sizeof(buf2),"[%c%c] (%d/%d) %s", nathan@0: mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,buf); nathan@0: disp->SetTitle(buf2); nathan@0: flush=true; nathan@0: } nathan@0: else { nathan@0: #endif nathan@0: if(!statusActive) { nathan@0: DisplayInfo(buf); nathan@0: flush=true; nathan@0: } nathan@0: else { d(printf("mp3-ctrl: display info skip due to status active\n")) } nathan@0: #if APIVERSNUM >= 10307 nathan@0: } nathan@0: #endif nathan@0: } nathan@0: } nathan@0: } nathan@0: nathan@0: if(bigwin) { nathan@0: bool all=(top!=lastTop || changed); nathan@0: if(all || time(0)>listtime+2) { nathan@0: int num=(top>0 && mode->Num==lastMode->Num) ? top : mode->Num - rows/2; nathan@0: if(num+rows>mode->MaxNum) num=mode->MaxNum-rows+1; nathan@0: if(num<1) num=1; nathan@0: top=num; nathan@0: for(int i=0 ; iMaxNum ; i++,num++) { nathan@0: cMP3PlayInfo pi; nathan@0: mgr->Info(num,&pi); if(!pi.Title[0]) break; nathan@0: snprintf(buf,sizeof(buf),"%d.\t%s",num,TitleArtist(pi.Title,pi.Artist)); nathan@0: eDvbColor fg=clrWhite, bg=clrBackground; nathan@0: int hash=MakeHash(buf); nathan@0: if(num==mode->Num) { fg=clrBlack; bg=clrCyan; hash=(hash^77) + 23; } nathan@0: if(all || hash!=hashlist[i]) { nathan@0: char *s=rindex(buf,'\t'); nathan@0: if(s) { nathan@0: *s++=0; nathan@0: Write(0,i,5,buf,fg,bg); nathan@0: Write(5,i,bwc-5,s,fg,bg); nathan@0: } nathan@0: else nathan@0: Write(0,i,bwc,buf,fg,bg); nathan@0: flush=true; nathan@0: hashlist[i]=hash; nathan@0: } nathan@0: } nathan@0: listtime=time(0); lastTop=top; nathan@0: } nathan@0: } nathan@0: nathan@0: if(flush) Flush(); nathan@0: } nathan@0: nathan@0: lastIndex=index; lastTotal=total; nathan@0: delete lastMode; lastMode=mode; nathan@0: } nathan@0: } nathan@0: nathan@0: void cMP3Control::DisplayInfo(const char *s) nathan@0: { nathan@0: if(s) Write(CTAB,-2,bwc-CTAB,s); nathan@0: else Fill(CTAB,-2,bwc-CTAB,1,clrBackground); nathan@0: } nathan@0: nathan@0: void cMP3Control::JumpDisplay(void) nathan@0: { nathan@0: char buf[64]; nathan@2: const char *j=trVDR("Jump: "), u=jumpsecs?'s':'m'; nathan@0: if(!jumpmm) sprintf(buf,"%s- %c", j,u); nathan@0: else sprintf(buf,"%s%d- %c",j,jumpmm,u); nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay) { nathan@0: disp->SetJump(buf); nathan@0: } nathan@0: else { nathan@0: #endif nathan@0: DisplayInfo(buf); nathan@0: #if APIVERSNUM >= 10307 nathan@0: } nathan@0: #endif nathan@0: } nathan@0: nathan@0: void cMP3Control::JumpProcess(eKeys Key) nathan@0: { nathan@0: int n=Key-k0, d=jumpsecs?1:60; nathan@0: switch (Key) { nathan@0: case k0 ... k9: nathan@0: if(jumpmm*10+n <= lastTotal/d) jumpmm=jumpmm*10+n; nathan@0: JumpDisplay(); nathan@0: break; nathan@0: case kBlue: nathan@0: jumpsecs=!jumpsecs; nathan@0: JumpDisplay(); nathan@0: break; nathan@0: case kPlay: nathan@0: case kUp: nathan@0: jumpmm-=lastIndex/d; nathan@0: // fall through nathan@0: case kFastRew: nathan@0: case kFastFwd: nathan@0: case kLeft: nathan@0: case kRight: nathan@0: player->SkipSeconds(jumpmm*d * ((Key==kLeft || Key==kFastRew) ? -1:1)); nathan@0: // fall through nathan@0: default: nathan@0: jumpactive=false; nathan@0: break; nathan@0: } nathan@0: nathan@0: if(!jumpactive) { nathan@0: if(jumphide) Hide(); nathan@0: #if APIVERSNUM >= 10307 nathan@0: else if(MP3Setup.ReplayDisplay) disp->SetJump(0); nathan@0: #endif nathan@0: } nathan@0: } nathan@0: nathan@0: void cMP3Control::Jump(void) nathan@0: { nathan@0: jumpmm=0; jumphide=jumpsecs=false; nathan@0: if(!visible) { nathan@0: ShowTimed(); if(!visible) return; nathan@0: jumphide=true; nathan@0: } nathan@0: JumpDisplay(); nathan@0: jumpactive=true; fliptime=0; flip=-1; nathan@0: } nathan@0: nathan@0: eOSState cMP3Control::ProcessKey(eKeys Key) nathan@0: { nathan@0: if(!player->Active()) return osEnd; nathan@0: nathan@0: if(visible && timeoutShow && time(0)>timeoutShow) { Hide(); timeoutShow=0; } nathan@0: ShowProgress(); nathan@0: #if APIVERSNUM >= 10307 nathan@0: ShowStatus(Key==kNone && !Skins.IsOpen()); nathan@0: #else nathan@0: ShowStatus(Key==kNone && !Interface->IsOpen()); nathan@0: #endif nathan@0: nathan@0: if(jumpactive && Key!=kNone) { JumpProcess(Key); return osContinue; } nathan@0: nathan@0: switch(Key) { nathan@0: case kUp: nathan@0: case kUp|k_Repeat: nathan@0: #if APIVERSNUM >= 10347 nathan@0: case kNext: nathan@0: case kNext|k_Repeat: nathan@0: #endif nathan@0: mgr->Next(); player->Play(); nathan@0: break; nathan@0: case kDown: nathan@0: case kDown|k_Repeat: nathan@0: #if APIVERSNUM >= 10347 nathan@0: case kPrev: nathan@0: case kPrev|k_Repeat: nathan@0: #endif nathan@0: if(!player->PrevCheck()) mgr->Prev(); nathan@0: player->Play(); nathan@0: break; nathan@0: case kLeft: nathan@0: case kLeft|k_Repeat: nathan@0: if(bigwin) { nathan@0: if(top>0) { top-=rows; if(top<1) top=1; } nathan@0: break; nathan@0: } nathan@0: // fall through nathan@0: case kFastRew: nathan@0: case kFastRew|k_Repeat: nathan@0: if(!player->IsStream()) player->SkipSeconds(-JUMPSIZE); nathan@0: break; nathan@0: case kRight: nathan@0: case kRight|k_Repeat: nathan@0: if(bigwin) { nathan@0: if(top>0) top+=rows; nathan@0: break; nathan@0: } nathan@0: // fall through nathan@0: case kFastFwd: nathan@0: case kFastFwd|k_Repeat: nathan@0: if(!player->IsStream()) player->SkipSeconds(JUMPSIZE); nathan@0: break; nathan@0: case kRed: nathan@0: if(!player->IsStream()) Jump(); nathan@0: break; nathan@0: case kGreen: nathan@0: if(lastMode) { nathan@0: if(time(0)>greentime) { nathan@0: if(lastMode->Loop || (!lastMode->Loop && !lastMode->Shuffle)) mgr->ToggleLoop(); nathan@0: if(lastMode->Shuffle) mgr->ToggleShuffle(); nathan@0: } nathan@0: else { nathan@0: if(!lastMode->Loop) mgr->ToggleLoop(); nathan@0: else if(!lastMode->Shuffle) mgr->ToggleShuffle(); nathan@0: else mgr->ToggleLoop(); nathan@0: } nathan@0: greentime=time(0)+MULTI_TIMEOUT; nathan@0: } nathan@0: break; nathan@0: case kPlay: nathan@0: player->Play(); nathan@0: break; nathan@0: case kPause: nathan@0: case kYellow: nathan@0: if(!player->IsStream()) player->Pause(); nathan@0: break; nathan@0: case kStop: nathan@0: case kBlue: nathan@0: Hide(); nathan@0: Stop(); nathan@0: return osEnd; nathan@0: case kBack: nathan@0: Hide(); nathan@0: #if APIVERSNUM >= 10332 nathan@2: cRemote::CallPlugin(plugin_name); nathan@0: return osBack; nathan@0: #else nathan@0: return osEnd; nathan@0: #endif nathan@0: nathan@0: case k0 ... k9: nathan@0: number=number*10+Key-k0; nathan@0: if(lastMode && number>0 && number<=lastMode->MaxNum) { nathan@0: if(!visible) { ShowTimed(); selecthide=true; } nathan@0: selecting=true; lastkeytime=time_ms(); nathan@0: char buf[32]; nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay) { nathan@2: snprintf(buf,sizeof(buf),"%s%d-/%d",trVDR("Jump: "),number,lastMode->MaxNum); nathan@0: disp->SetJump(buf); nathan@0: } nathan@0: else { nathan@0: #endif nathan@0: snprintf(buf,sizeof(buf),"(%d-/%d)",number,lastMode->MaxNum); nathan@0: Write(0,-2,CTAB,buf); nathan@0: #if APIVERSNUM >= 10307 nathan@0: } nathan@0: #endif nathan@0: Flush(); nathan@0: break; nathan@0: } nathan@0: number=0; lastkeytime=0; nathan@0: // fall through nathan@0: case kNone: nathan@0: if(selecting && time_ms()-lastkeytime>SELECT_TIMEOUT) { nathan@0: if(number>0) { mgr->Goto(number); player->Play(); } nathan@0: if(selecthide) timeoutShow=time(0)+SELECTHIDE_TIMEOUT; nathan@0: if(lastMode) lastMode->Hash=-1; nathan@0: number=0; selecting=selecthide=false; nathan@0: #if APIVERSNUM >= 10307 nathan@0: if(MP3Setup.ReplayDisplay) disp->SetJump(0); nathan@0: #endif nathan@0: } nathan@0: break; nathan@0: case kOk: nathan@0: if(time(0)>oktime || MP3Setup.ReplayDisplay) { nathan@0: visible ? Hide() : ShowTimed(); nathan@0: } nathan@0: else { nathan@0: if(visible && !bigwin) { Hide(); ShowProgress(true,true); } nathan@0: else { Hide(); ShowTimed(); } nathan@0: } nathan@0: oktime=time(0)+MULTI_TIMEOUT; nathan@0: ShowStatus(true); nathan@0: break; nathan@0: default: nathan@0: return osUnknown; nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: // --- cMenuID3Info ------------------------------------------------------------ nathan@0: nathan@0: class cMenuID3Info : public cOsdMenu { nathan@0: private: nathan@0: cOsdItem *Item(const char *name, const char *text); nathan@0: cOsdItem *Item(const char *name, const char *format, const float num); nathan@0: void Build(cSongInfo *info, const char *name); nathan@0: public: nathan@0: cMenuID3Info(cSong *song); nathan@0: cMenuID3Info(cSongInfo *si, const char *name); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: nathan@0: cMenuID3Info::cMenuID3Info(cSong *song) nathan@0: :cOsdMenu(tr("ID3 information"),12) nathan@0: { nathan@0: Build(song->Info(),song->Name()); nathan@0: } nathan@0: nathan@0: cMenuID3Info::cMenuID3Info(cSongInfo *si, const char *name) nathan@0: :cOsdMenu(tr("ID3 information"),12) nathan@0: { nathan@0: Build(si,name); nathan@0: } nathan@0: nathan@0: void cMenuID3Info::Build(cSongInfo *si, const char *name) nathan@0: { nathan@0: if(si) { nathan@0: Item(tr("Filename"),name); nathan@0: if(si->HasInfo() && si->Total>0) { nathan@0: char *buf=0; nathan@0: asprintf(&buf,"%02d:%02d",si->Total/60,si->Total%60); nathan@0: Item(tr("Length"),buf); nathan@0: free(buf); nathan@0: Item(tr("Title"),si->Title); nathan@0: Item(tr("Artist"),si->Artist); nathan@0: Item(tr("Album"),si->Album); nathan@0: Item(tr("Year"),0,(float)si->Year); nathan@0: Item(tr("Samplerate"),"%.1f kHz",si->SampleFreq/1000.0); nathan@0: Item(tr("Bitrate"),"%.f kbit/s",si->Bitrate/1000.0); nathan@2: Item(trVDR("Channels"),0,(float)si->Channels); nathan@0: } nathan@0: Display(); nathan@0: } nathan@0: } nathan@0: nathan@0: cOsdItem *cMenuID3Info::Item(const char *name, const char *format, const float num) nathan@0: { nathan@0: cOsdItem *item; nathan@0: if(num>=0.0) { nathan@0: char *buf=0; nathan@0: asprintf(&buf,format?format:"%.f",num); nathan@0: item=Item(name,buf); nathan@0: free(buf); nathan@0: } nathan@0: else item=Item(name,""); nathan@0: return item; nathan@0: } nathan@0: nathan@0: cOsdItem *cMenuID3Info::Item(const char *name, const char *text) nathan@0: { nathan@0: char *buf=0; nathan@0: asprintf(&buf,"%s:\t%s",name,text?text:""); nathan@0: cOsdItem *item = new cOsdItem(buf,osBack); nathan@0: #if APIVERSNUM >= 10307 nathan@0: item->SetSelectable(false); nathan@0: #else nathan@0: item->SetColor(clrWhite, clrBackground); nathan@0: #endif nathan@0: free(buf); nathan@0: Add(item); return item; nathan@0: } nathan@0: nathan@0: eOSState cMenuID3Info::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state = cOsdMenu::ProcessKey(Key); nathan@0: nathan@0: if(state==osUnknown) { nathan@0: switch(Key) { nathan@0: case kRed: nathan@0: case kGreen: nathan@0: case kYellow: nathan@0: case kBlue: return osContinue; nathan@0: case kMenu: return osEnd; nathan@0: default: break; nathan@0: } nathan@0: } nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- cMenuInstantBrowse ------------------------------------------------------- nathan@0: nathan@0: class cMenuInstantBrowse : public cMenuBrowse { nathan@0: private: nathan@0: const char *selecttext, *alltext; nathan@0: virtual void SetButtons(void); nathan@0: virtual eOSState ID3Info(void); nathan@0: public: nathan@0: cMenuInstantBrowse(cFileSource *Source, const char *Selecttext, const char *Alltext); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: nathan@0: cMenuInstantBrowse::cMenuInstantBrowse(cFileSource *Source, const char *Selecttext, const char *Alltext) nathan@0: :cMenuBrowse(Source,true,true,tr("Directory browser"),excl_br) nathan@0: { nathan@0: selecttext=Selecttext; alltext=Alltext; nathan@0: SetButtons(); nathan@0: } nathan@0: nathan@0: void cMenuInstantBrowse::SetButtons(void) nathan@0: { nathan@0: SetHelp(selecttext, currentdir?tr("Parent"):0, currentdir?0:alltext, tr("ID3 info")); nathan@0: Display(); nathan@0: } nathan@0: nathan@0: eOSState cMenuInstantBrowse::ID3Info(void) nathan@0: { nathan@0: cFileObj *item=CurrentItem(); nathan@0: if(item && item->Type()==otFile) { nathan@0: cSong *song=new cSong(item); nathan@0: cSongInfo *si; nathan@0: if(song && (si=song->Info())) { nathan@0: AddSubMenu(new cMenuID3Info(si,item->Path())); nathan@0: } nathan@0: delete song; nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuInstantBrowse::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state=cOsdMenu::ProcessKey(Key); nathan@0: if(state==osUnknown) { nathan@0: switch (Key) { nathan@0: case kYellow: lastselect=new cFileObj(source,0,0,otBase); nathan@0: return osBack; nathan@0: default: break; nathan@0: } nathan@0: } nathan@0: if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state); nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- cMenuPlayListItem ------------------------------------------------------- nathan@0: nathan@0: class cMenuPlayListItem : public cOsdItem { nathan@0: private: nathan@0: bool showID3; nathan@0: cSong *song; nathan@0: public: nathan@0: cMenuPlayListItem(cSong *Song, bool showid3); nathan@0: cSong *Song(void) { return song; } nathan@0: virtual void Set(void); nathan@0: void Set(bool showid3); nathan@0: }; nathan@0: nathan@0: cMenuPlayListItem::cMenuPlayListItem(cSong *Song, bool showid3) nathan@0: { nathan@0: song=Song; nathan@0: Set(showid3); nathan@0: } nathan@0: nathan@0: void cMenuPlayListItem::Set(bool showid3) nathan@0: { nathan@0: showID3=showid3; nathan@0: Set(); nathan@0: } nathan@0: nathan@0: void cMenuPlayListItem::Set(void) nathan@0: { nathan@0: char *buffer=0; nathan@0: cSongInfo *si=song->Info(false); nathan@0: if(showID3 && !si) si=song->Info(); nathan@0: if(showID3 && si && si->Title) nathan@0: asprintf(&buffer, "%d.\t%s",song->Index()+1,TitleArtist(si->Title,si->Artist)); nathan@0: else nathan@0: asprintf(&buffer, "%d.\t<%s>",song->Index()+1,song->Name()); nathan@0: SetText(buffer,false); nathan@0: } nathan@0: nathan@0: // --- cMenuPlayList ------------------------------------------------------ nathan@0: nathan@0: class cMenuPlayList : public cOsdMenu { nathan@0: private: nathan@0: cPlayList *playlist; nathan@0: bool browsing, showid3; nathan@0: void Buttons(void); nathan@0: void Refresh(bool all = false); nathan@0: void Add(void); nathan@0: virtual void Move(int From, int To); nathan@0: eOSState Remove(void); nathan@0: eOSState ShowID3(void); nathan@0: eOSState ID3Info(void); nathan@0: public: nathan@0: cMenuPlayList(cPlayList *Playlist); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: nathan@0: cMenuPlayList::cMenuPlayList(cPlayList *Playlist) nathan@0: :cOsdMenu(tr("Playlist editor"),4) nathan@0: { nathan@0: browsing=showid3=false; nathan@0: playlist=Playlist; nathan@0: if(MP3Setup.EditorMode) showid3=true; nathan@0: nathan@0: cSong *mp3 = playlist->First(); nathan@0: while(mp3) { nathan@0: cOsdMenu::Add(new cMenuPlayListItem(mp3,showid3)); nathan@0: mp3 = playlist->cList::Next(mp3); nathan@0: } nathan@0: Buttons(); Display(); nathan@0: } nathan@0: nathan@0: void cMenuPlayList::Buttons(void) nathan@0: { nathan@2: SetHelp(tr("Add"), showid3?tr("Filenames"):tr("ID3 names"), tr("Remove"), trVDR(BUTTON"Mark")); nathan@0: } nathan@0: nathan@0: void cMenuPlayList::Refresh(bool all) nathan@0: { nathan@0: cMenuPlayListItem *cur=(cMenuPlayListItem *)((all || Count()<2) ? First() : Get(Current())); nathan@0: while(cur) { nathan@0: cur->Set(showid3); nathan@0: cur=(cMenuPlayListItem *)Next(cur); nathan@0: } nathan@0: } nathan@0: nathan@0: void cMenuPlayList::Add(void) nathan@0: { nathan@0: cFileObj *item=cMenuInstantBrowse::GetSelected(); nathan@0: if(item) { nathan@0: Status(tr("Scanning directory...")); nathan@0: cInstantPlayList *newpl=new cInstantPlayList(item); nathan@0: if(newpl->Load()) { nathan@0: if(newpl->Count()) { nathan@0: if(newpl->Count()==1 || Interface->Confirm(tr("Add recursivly?"))) { nathan@0: cSong *mp3=newpl->First(); nathan@0: while(mp3) { nathan@0: cSong *n=new cSong(mp3); nathan@0: if(Count()>0) { nathan@0: cMenuPlayListItem *current=(cMenuPlayListItem *)Get(Current()); nathan@0: playlist->Add(n,current->Song()); nathan@0: cOsdMenu::Add(new cMenuPlayListItem(n,showid3),true,current); nathan@0: } nathan@0: else { nathan@0: playlist->Add(n); nathan@0: cOsdMenu::Add(new cMenuPlayListItem(n,showid3),true); nathan@0: } nathan@0: mp3=newpl->cList::Next(mp3); nathan@0: } nathan@0: playlist->Save(); nathan@0: Refresh(); Display(); nathan@0: } nathan@0: } nathan@0: else Error(tr("Empty directory!")); nathan@0: } nathan@0: else Error(tr("Error scanning directory!")); nathan@0: delete newpl; nathan@0: Status(0); nathan@0: } nathan@0: } nathan@0: nathan@0: void cMenuPlayList::Move(int From, int To) nathan@0: { nathan@0: playlist->Move(From,To); playlist->Save(); nathan@0: cOsdMenu::Move(From,To); nathan@0: Refresh(true); Display(); nathan@0: } nathan@0: nathan@0: eOSState cMenuPlayList::ShowID3(void) nathan@0: { nathan@0: showid3=!showid3; nathan@0: Buttons(); Refresh(true); Display(); nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuPlayList::ID3Info(void) nathan@0: { nathan@0: if(Count()>0) { nathan@0: cMenuPlayListItem *current = (cMenuPlayListItem *)Get(Current()); nathan@0: AddSubMenu(new cMenuID3Info(current->Song())); nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuPlayList::Remove(void) nathan@0: { nathan@0: if(Count()>0) { nathan@0: cMenuPlayListItem *current = (cMenuPlayListItem *)Get(Current()); nathan@0: if(Interface->Confirm(tr("Remove entry?"))) { nathan@0: playlist->Del(current->Song()); playlist->Save(); nathan@0: cOsdMenu::Del(Current()); nathan@0: Refresh(); Display(); nathan@0: } nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuPlayList::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state = cOsdMenu::ProcessKey(Key); nathan@0: nathan@0: if(browsing && !HasSubMenu() && state==osContinue) { Add(); browsing=false; } nathan@0: nathan@0: if(state==osUnknown) { nathan@0: switch(Key) { nathan@0: case kOk: return ID3Info(); nathan@0: case kRed: browsing=true; nathan@0: return AddSubMenu(new cMenuInstantBrowse(MP3Sources.GetSource(),tr("Add"),tr("Add all"))); nathan@0: case kGreen: return ShowID3(); nathan@0: case kYellow: return Remove(); nathan@0: case kBlue: Mark(); return osContinue; nathan@0: case kMenu: return osEnd; nathan@0: default: break; nathan@0: } nathan@0: } nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- cPlaylistRename -------------------------------------------------------- nathan@0: nathan@0: class cPlaylistRename : public cOsdMenu { nathan@0: private: nathan@0: static char *newname; nathan@0: const char *oldname; nathan@0: char data[64]; nathan@0: public: nathan@0: cPlaylistRename(const char *Oldname); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: static const char *GetNewname(void) { return newname; } nathan@0: }; nathan@0: nathan@0: char *cPlaylistRename::newname = NULL; nathan@0: nathan@0: cPlaylistRename::cPlaylistRename(const char *Oldname) nathan@0: :cOsdMenu(tr("Rename playlist"), 15) nathan@0: { nathan@0: free(newname); newname=0; nathan@0: nathan@0: oldname=Oldname; nathan@0: char *buf=NULL; nathan@0: asprintf(&buf,"%s\t%s",tr("Old name:"),oldname); nathan@0: cOsdItem *old = new cOsdItem(buf,osContinue); nathan@0: #if APIVERSNUM >= 10307 nathan@0: old->SetSelectable(false); nathan@0: #else nathan@0: old->SetColor(clrWhite, clrBackground); nathan@0: #endif nathan@0: Add(old); nathan@0: free(buf); nathan@0: nathan@0: data[0]=0; nathan@0: Add(new cMenuEditStrItem( tr("New name"), data, sizeof(data)-1, tr(FileNameChars)),true); nathan@0: } nathan@0: nathan@0: eOSState cPlaylistRename::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state = cOsdMenu::ProcessKey(Key); nathan@0: nathan@0: if (state == osUnknown) { nathan@0: switch (Key) { nathan@0: case kOk: if(data[0] && strcmp(data,oldname)) newname=strdup(data); nathan@0: return osBack; nathan@0: case kRed: nathan@0: case kGreen: nathan@0: case kYellow: nathan@0: case kBlue: return osContinue; nathan@0: default: break; nathan@0: } nathan@0: } nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- cMenuMP3Item ----------------------------------------------------- nathan@0: nathan@0: class cMenuMP3Item : public cOsdItem { nathan@0: private: nathan@0: cPlayList *playlist; nathan@0: virtual void Set(void); nathan@0: public: nathan@0: cMenuMP3Item(cPlayList *PlayList); nathan@0: cPlayList *List(void) { return playlist; } nathan@0: }; nathan@0: nathan@0: cMenuMP3Item::cMenuMP3Item(cPlayList *PlayList) nathan@0: { nathan@0: playlist=PlayList; nathan@0: Set(); nathan@0: } nathan@0: nathan@0: void cMenuMP3Item::Set(void) nathan@0: { nathan@0: char *buffer=0; nathan@0: asprintf(&buffer," %s",playlist->BaseName()); nathan@0: SetText(buffer,false); nathan@0: } nathan@0: nathan@0: // --- cMenuMP3 -------------------------------------------------------- nathan@0: nathan@0: class cMenuMP3 : public cOsdMenu { nathan@0: private: nathan@0: cPlayLists *lists; nathan@0: bool renaming, sourcing, instanting; nathan@0: int buttonnum; nathan@0: eOSState Play(void); nathan@0: eOSState Edit(void); nathan@0: eOSState New(void); nathan@0: eOSState Delete(void); nathan@0: eOSState Rename(bool second); nathan@0: eOSState Source(bool second); nathan@0: eOSState Instant(bool second); nathan@0: void ScanLists(void); nathan@0: eOSState SetButtons(int num); nathan@0: public: nathan@0: cMenuMP3(void); nathan@0: ~cMenuMP3(void); nathan@0: virtual eOSState ProcessKey(eKeys Key); nathan@0: }; nathan@0: nathan@0: cMenuMP3::cMenuMP3(void) nathan@0: :cOsdMenu(tr("MP3")) nathan@0: { nathan@0: renaming=sourcing=instanting=false; nathan@0: lists=new cPlayLists; nathan@0: ScanLists(); SetButtons(1); nathan@0: if(MP3Setup.MenuMode) Instant(false); nathan@0: } nathan@0: nathan@0: cMenuMP3::~cMenuMP3(void) nathan@0: { nathan@0: delete lists; nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::SetButtons(int num) nathan@0: { nathan@0: switch(num) { nathan@0: case 1: nathan@2: SetHelp(trVDR(BUTTON"Edit"), tr("Source"), tr("Browse"), ">>"); nathan@0: break; nathan@0: case 2: nathan@2: SetHelp("<<", trVDR(BUTTON"New"), trVDR(BUTTON"Delete"), tr("Rename")); nathan@0: break; nathan@0: } nathan@0: buttonnum=num; Display(); nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: void cMenuMP3::ScanLists(void) nathan@0: { nathan@0: Clear(); nathan@0: Status(tr("Scanning playlists...")); nathan@0: bool res=lists->Load(MP3Sources.GetSource()); nathan@0: Status(0); nathan@0: if(res) { nathan@0: cPlayList *plist=lists->First(); nathan@0: while(plist) { nathan@0: Add(new cMenuMP3Item(plist)); nathan@0: plist=lists->Next(plist); nathan@0: } nathan@0: } nathan@0: else Error(tr("Error scanning playlists!")); nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::Delete(void) nathan@0: { nathan@0: if(Count()>0) { nathan@0: if(Interface->Confirm(tr("Delete playlist?")) && nathan@0: Interface->Confirm(tr("Are you sure?")) ) { nathan@0: cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); nathan@0: if(plist->Delete()) { nathan@0: lists->Del(plist); nathan@0: cOsdMenu::Del(Current()); nathan@0: Display(); nathan@0: } nathan@0: else Error(tr("Error deleting playlist!")); nathan@0: } nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::New(void) nathan@0: { nathan@0: cPlayList *plist=new cPlayList(MP3Sources.GetSource(),0,0); nathan@0: char name[32]; nathan@0: int i=0; nathan@0: do { nathan@0: if(i) sprintf(name,"%s%d",tr("unnamed"),i++); nathan@0: else { strcpy(name,tr("unnamed")); i++; } nathan@0: } while(plist->TestName(name)); nathan@0: nathan@0: if(plist->Create(name)) { nathan@0: lists->Add(plist); nathan@0: Add(new cMenuMP3Item(plist), true); nathan@0: nathan@0: isyslog("MP3: playlist %s added", plist->Name()); nathan@0: return AddSubMenu(new cMenuPlayList(plist)); nathan@0: } nathan@0: Error(tr("Error creating playlist!")); nathan@0: delete plist; nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::Rename(bool second) nathan@0: { nathan@0: if(HasSubMenu() || Count() == 0) return osContinue; nathan@0: nathan@0: cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); nathan@0: if(!second) { nathan@0: renaming=true; nathan@0: return AddSubMenu(new cPlaylistRename(plist->BaseName())); nathan@0: } nathan@0: renaming=false; nathan@0: const char *newname=cPlaylistRename::GetNewname(); nathan@0: if(newname) { nathan@0: if(plist->Rename(newname)) { nathan@0: RefreshCurrent(); nathan@0: DisplayCurrent(true); nathan@0: } nathan@0: else Error(tr("Error renaming playlist!")); nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::Edit(void) nathan@0: { nathan@0: if(HasSubMenu() || Count() == 0) return osContinue; nathan@0: nathan@0: cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); nathan@0: if(!plist->Load()) Error(tr("Error loading playlist!")); nathan@0: else if(!plist->IsWinAmp()) { nathan@0: isyslog("MP3: editing playlist %s", plist->Name()); nathan@0: return AddSubMenu(new cMenuPlayList(plist)); nathan@0: } nathan@0: else Error(tr("Can't edit a WinAmp playlist!")); nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::Play(void) nathan@0: { nathan@0: if(HasSubMenu() || Count() == 0) return osContinue; nathan@0: nathan@0: Status(tr("Loading playlist...")); nathan@0: cPlayList *newpl=new cPlayList(((cMenuMP3Item *)Get(Current()))->List()); nathan@0: if(newpl->Load() && newpl->Count()) { nathan@0: isyslog("mp3: playback started with playlist %s", newpl->Name()); nathan@0: cMP3Control::SetPlayList(newpl); nathan@0: if(MP3Setup.KeepSelect) { Status(0); return osContinue; } nathan@0: return osEnd; nathan@0: } nathan@0: Status(0); nathan@0: delete newpl; nathan@0: Error(tr("Error loading playlist!")); nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::Source(bool second) nathan@0: { nathan@0: if(HasSubMenu()) return osContinue; nathan@0: nathan@0: if(!second) { nathan@0: sourcing=true; nathan@0: return AddSubMenu(new cMenuSource(&MP3Sources,tr("MP3 source"))); nathan@0: } nathan@0: sourcing=false; nathan@0: cFileSource *src=cMenuSource::GetSelected(); nathan@0: if(src) { nathan@0: MP3Sources.SetSource(src); nathan@0: ScanLists(); nathan@0: Display(); nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::Instant(bool second) nathan@0: { nathan@0: if(HasSubMenu()) return osContinue; nathan@0: nathan@0: if(!second) { nathan@0: instanting=true; nathan@2: return AddSubMenu(new cMenuInstantBrowse(MP3Sources.GetSource(),trVDR(BUTTON"Play"),tr("Play all"))); nathan@0: } nathan@0: instanting=false; nathan@0: cFileObj *item=cMenuInstantBrowse::GetSelected(); nathan@0: if(item) { nathan@0: Status(tr("Building playlist...")); nathan@0: cInstantPlayList *newpl = new cInstantPlayList(item); nathan@0: if(newpl->Load() && newpl->Count()) { nathan@0: isyslog("mp3: playback started with instant playlist %s", newpl->Name()); nathan@0: cMP3Control::SetPlayList(newpl); nathan@0: if(MP3Setup.KeepSelect) { Status(0); return Instant(false); } nathan@0: return osEnd; nathan@0: } nathan@0: Status(0); nathan@0: delete newpl; nathan@0: Error(tr("Error building playlist!")); nathan@0: } nathan@0: return osContinue; nathan@0: } nathan@0: nathan@0: eOSState cMenuMP3::ProcessKey(eKeys Key) nathan@0: { nathan@0: eOSState state = cOsdMenu::ProcessKey(Key); nathan@0: nathan@0: if(!HasSubMenu() && state==osContinue) { // eval the return value from submenus nathan@0: if(renaming) return Rename(true); nathan@0: if(sourcing) return Source(true); nathan@0: if(instanting) return Instant(true); nathan@0: } nathan@0: nathan@0: if(state == osUnknown) { nathan@0: switch(Key) { nathan@0: case kOk: return Play(); nathan@0: case kRed: return (buttonnum==1 ? Edit() : SetButtons(1)); nathan@0: case kGreen: return (buttonnum==1 ? Source(false) : New()); nathan@0: case kYellow: return (buttonnum==1 ? Instant(false) : Delete()); nathan@0: case kBlue: return (buttonnum==1 ? SetButtons(2) : Rename(false)); nathan@0: case kMenu: return osEnd; nathan@0: default: break; nathan@0: } nathan@0: } nathan@0: return state; nathan@0: } nathan@0: nathan@0: // --- PropagateImage ---------------------------------------------------------- nathan@0: nathan@0: void PropagateImage(const char *image) nathan@0: { nathan@0: cPlugin *graphtft=cPluginManager::GetPlugin("graphtft"); nathan@0: if(graphtft) graphtft->SetupParse("CoverImage",image ? image:""); nathan@0: } nathan@0: nathan@0: // --- cPluginMP3 -------------------------------------------------------------- nathan@0: nathan@0: static const char *VERSION = PLUGIN_VERSION; nathan@2: static const char *DESCRIPTION = trNOOP("A versatile audio player"); nathan@0: static const char *MAINMENUENTRY = "MP3"; nathan@0: nathan@0: class cPluginMp3 : public cPlugin { nathan@0: private: nathan@0: #if APIVERSNUM >= 10330 nathan@0: bool ExternalPlay(const char *path, bool test); nathan@0: #endif nathan@0: public: nathan@0: cPluginMp3(void); nathan@0: virtual ~cPluginMp3(); nathan@0: virtual const char *Version(void) { return VERSION; } nathan@0: virtual const char *Description(void) { return tr(DESCRIPTION); } nathan@0: virtual const char *CommandLineHelp(void); nathan@0: virtual bool ProcessArgs(int argc, char *argv[]); nathan@0: #if APIVERSNUM >= 10131 nathan@0: virtual bool Initialize(void); nathan@0: #else nathan@0: virtual bool Start(void); nathan@0: #endif nathan@0: virtual void Housekeeping(void); nathan@0: virtual const char *MainMenuEntry(void); nathan@0: virtual cOsdObject *MainMenuAction(void); nathan@0: virtual cMenuSetupPage *SetupMenu(void); nathan@0: virtual bool SetupParse(const char *Name, const char *Value); nathan@0: #if APIVERSNUM >= 10330 nathan@0: virtual bool Service(const char *Id, void *Data); nathan@0: #if APIVERSNUM >= 10331 nathan@0: virtual const char **SVDRPHelpPages(void); nathan@0: virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); nathan@0: #endif nathan@0: #endif nathan@0: }; nathan@0: nathan@0: cPluginMp3::cPluginMp3(void) nathan@0: { nathan@0: // Initialize any member varaiables here. nathan@0: // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL nathan@0: // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! nathan@0: } nathan@0: nathan@0: cPluginMp3::~cPluginMp3() nathan@0: { nathan@2: InfoCache.Shutdown(); nathan@0: delete mgr; nathan@0: } nathan@0: nathan@0: const char *cPluginMp3::CommandLineHelp(void) nathan@0: { nathan@0: static char *help_str=0; nathan@0: nathan@0: free(help_str); // for easier orientation, this is column 80| nathan@0: asprintf(&help_str," -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n" nathan@0: " (default: %s)\n" nathan@0: " -n CMD, --network=CMD execute CMD before & after network access\n" nathan@0: " (default: %s)\n" nathan@0: " -C DIR, --cache=DIR store ID3 cache file in DIR\n" nathan@0: " (default: %s)\n" nathan@0: " -B DIR, --cddb=DIR search CDDB files in DIR\n" nathan@0: " (default: %s)\n" nathan@0: " -D DEV, --dsp=DEV device for OSS output\n" nathan@0: " (default: %s)\n" nathan@0: " -i CMD, --iconv=CMD use CMD to convert background images\n" nathan@0: " (default: %s)\n" nathan@0: " -c DIR, --icache=DIR cache converted images in DIR\n" nathan@0: " (default: %s)\n" nathan@0: " -S SUB, --sources=SUB search sources config in SUB subdirectory\n" nathan@0: " (default: %s)\n", nathan@0: nathan@0: mountscript, nathan@0: netscript ? netscript:"none", nathan@0: cachedir ? cachedir:"video dir", nathan@0: #ifdef HAVE_SNDFILE nathan@0: cddbpath, nathan@0: #else nathan@0: "none", nathan@0: #endif nathan@0: #ifdef WITH_OSS nathan@0: dspdevice, nathan@0: #else nathan@0: "none", nathan@0: #endif nathan@0: imageconv, nathan@0: imagecache, nathan@0: sourcesSub ? sourcesSub:"empty" nathan@0: ); nathan@0: return help_str; nathan@0: } nathan@0: nathan@0: bool cPluginMp3::ProcessArgs(int argc, char *argv[]) nathan@0: { nathan@0: static struct option long_options[] = { nathan@0: { "mount", required_argument, NULL, 'm' }, nathan@0: { "network", required_argument, NULL, 'n' }, nathan@0: { "cddb", required_argument, NULL, 'B' }, nathan@0: { "dsp", required_argument, NULL, 'D' }, nathan@0: { "cache", required_argument, NULL, 'C' }, nathan@0: { "icache", required_argument, NULL, 'c' }, nathan@0: { "iconv", required_argument, NULL, 'i' }, nathan@0: { "sources", required_argument, NULL, 'S' }, nathan@0: { NULL } nathan@0: }; nathan@0: nathan@0: int c, option_index = 0; nathan@0: while((c=getopt_long(argc,argv,"c:i:m:n:B:C:D:S:",long_options,&option_index))!=-1) { nathan@0: switch (c) { nathan@0: case 'i': imageconv=optarg; break; nathan@0: case 'c': imagecache=optarg; break; nathan@0: case 'm': mountscript=optarg; break; nathan@0: case 'n': netscript=optarg; break; nathan@0: case 'C': cachedir=optarg; break; nathan@0: case 'S': sourcesSub=optarg; break; nathan@0: case 'B': nathan@0: #ifdef HAVE_SNDFILE nathan@0: cddbpath=optarg; break; nathan@0: #else nathan@0: fprintf(stderr, "mp3: libsndfile support has not been compiled in!\n"); return false; nathan@0: #endif nathan@0: case 'D': nathan@0: #ifdef WITH_OSS nathan@0: dspdevice=optarg; break; nathan@0: #else nathan@0: fprintf(stderr, "mp3: OSS output has not been compiled in!\n"); return false; nathan@0: #endif nathan@0: default: return false; nathan@0: } nathan@0: } nathan@0: return true; nathan@0: } nathan@0: nathan@0: #if APIVERSNUM >= 10131 nathan@0: bool cPluginMp3::Initialize(void) nathan@0: #else nathan@0: bool cPluginMp3::Start(void) nathan@0: #endif nathan@0: { nathan@0: if(!CheckVDRVersion(1,1,29,"mp3")) return false; nathan@2: plugin_name="mp3"; nathan@2: #if APIVERSNUM < 10507 nathan@2: i18n_name="mp3"; nathan@2: #else nathan@2: i18n_name="vdr-mp3"; nathan@2: #endif nathan@0: MP3Sources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mp3sources.conf")); nathan@0: if(MP3Sources.Count()<1) { nathan@0: esyslog("ERROR: you should have defined at least one source in mp3sources.conf"); nathan@0: fprintf(stderr,"No source(s) defined in mp3sources.conf\n"); nathan@0: return false; nathan@0: } nathan@0: InfoCache.Load(); nathan@2: #if APIVERSNUM < 10507 nathan@0: RegisterI18n(Phrases); nathan@2: #endif nathan@0: mgr=new cPlayManager; nathan@0: if(!mgr) { nathan@0: esyslog("ERROR: creating playmanager failed"); nathan@0: fprintf(stderr,"Creating playmanager failed\n"); nathan@0: return false; nathan@0: } nathan@0: d(printf("mp3: using %s\n",mad_version)) nathan@0: d(printf("mp3: compiled with %s\n",MAD_VERSION)) nathan@0: return true; nathan@0: } nathan@0: nathan@0: void cPluginMp3::Housekeeping(void) nathan@0: { nathan@0: InfoCache.Save(); nathan@0: } nathan@0: nathan@0: const char *cPluginMp3::MainMenuEntry(void) nathan@0: { nathan@0: return MP3Setup.HideMainMenu ? 0 : tr(MAINMENUENTRY); nathan@0: } nathan@0: nathan@0: cOsdObject *cPluginMp3::MainMenuAction(void) nathan@0: { nathan@0: return new cMenuMP3; nathan@0: } nathan@0: nathan@0: cMenuSetupPage *cPluginMp3::SetupMenu(void) nathan@0: { nathan@0: return new cMenuSetupMP3; nathan@0: } nathan@0: nathan@0: bool cPluginMp3::SetupParse(const char *Name, const char *Value) nathan@0: { nathan@0: if (!strcasecmp(Name, "InitLoopMode")) MP3Setup.InitLoopMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "InitShuffleMode")) MP3Setup.InitShuffleMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "AudioMode")) MP3Setup.AudioMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "BgrScan")) MP3Setup.BgrScan = atoi(Value); nathan@0: else if (!strcasecmp(Name, "EditorMode")) MP3Setup.EditorMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "DisplayMode")) MP3Setup.DisplayMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "BackgrMode")) MP3Setup.BackgrMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "MenuMode")) MP3Setup.MenuMode = atoi(Value); nathan@0: else if (!strcasecmp(Name, "TargetLevel")) MP3Setup.TargetLevel = atoi(Value); nathan@0: else if (!strcasecmp(Name, "LimiterLevel")) MP3Setup.LimiterLevel = atoi(Value); nathan@0: else if (!strcasecmp(Name, "Only48kHz")) MP3Setup.Only48kHz = atoi(Value); nathan@0: else if (!strcasecmp(Name, "UseProxy")) MP3Setup.UseProxy = atoi(Value); nathan@0: else if (!strcasecmp(Name, "ProxyHost")) strn0cpy(MP3Setup.ProxyHost,Value,MAX_HOSTNAME); nathan@0: else if (!strcasecmp(Name, "ProxyPort")) MP3Setup.ProxyPort = atoi(Value); nathan@0: else if (!strcasecmp(Name, "UseCddb")) MP3Setup.UseCddb = atoi(Value); nathan@0: else if (!strcasecmp(Name, "CddbHost")) strn0cpy(MP3Setup.CddbHost,Value,MAX_HOSTNAME); nathan@0: else if (!strcasecmp(Name, "CddbPort")) MP3Setup.CddbPort = atoi(Value); nathan@0: else if (!strcasecmp(Name, "AbortAtEOL")) MP3Setup.AbortAtEOL = atoi(Value); nathan@0: else if (!strcasecmp(Name, "AudioOutMode")) { nathan@0: MP3Setup.AudioOutMode = atoi(Value); nathan@0: #ifndef WITH_OSS nathan@0: if(MP3Setup.AudioOutMode==AUDIOOUTMODE_OSS) { nathan@0: esyslog("WARNING: AudioOutMode OSS not supported, falling back to DVB"); nathan@0: MP3Setup.AudioOutMode=AUDIOOUTMODE_DVB; nathan@0: } nathan@0: #endif nathan@0: } nathan@0: #if APIVERSNUM >= 10307 nathan@0: else if (!strcasecmp(Name, "ReplayDisplay")) MP3Setup.ReplayDisplay = atoi(Value); nathan@0: #endif nathan@0: else if (!strcasecmp(Name, "HideMainMenu")) MP3Setup.HideMainMenu = atoi(Value); nathan@0: else if (!strcasecmp(Name, "KeepSelect")) MP3Setup.KeepSelect = atoi(Value); nathan@0: else if (!strcasecmp(Name, "TitleArtistOrder")) MP3Setup.TitleArtistOrder = atoi(Value); nathan@0: else return false; nathan@0: return true; nathan@0: } nathan@0: nathan@0: #if APIVERSNUM >= 10330 nathan@0: nathan@0: bool cPluginMp3::ExternalPlay(const char *path, bool test) nathan@0: { nathan@0: char real[PATH_MAX+1]; nathan@0: if(realpath(path,real)) { nathan@0: cFileSource *src=MP3Sources.FindSource(real); nathan@0: if(src) { nathan@0: cFileObj *item=new cFileObj(src,0,0,otFile); nathan@0: if(item) { nathan@0: item->SplitAndSet(real); nathan@0: if(item->GuessType()) { nathan@0: if(item->Exists()) { nathan@0: cInstantPlayList *pl=new cInstantPlayList(item); nathan@0: if(pl && pl->Load() && pl->Count()) { nathan@0: if(!test) cMP3Control::SetPlayList(pl); nathan@0: else delete pl; nathan@0: delete item; nathan@0: return true; nathan@0: } nathan@0: else dsyslog("MP3 service: error building playlist"); nathan@0: delete pl; nathan@0: } nathan@0: else dsyslog("MP3 service: cannot play '%s'",path); nathan@0: } nathan@0: else dsyslog("MP3 service: GuessType() failed for '%s'",path); nathan@0: delete item; nathan@0: } nathan@0: } nathan@0: else dsyslog("MP3 service: cannot find source for '%s', real '%s'",path,real); nathan@0: } nathan@0: else if(errno!=ENOENT && errno!=ENOTDIR) nathan@0: esyslog("ERROR: realpath: %s: %s",path,strerror(errno)); nathan@0: return false; nathan@0: } nathan@0: nathan@0: bool cPluginMp3::Service(const char *Id, void *Data) nathan@0: { nathan@0: if(!strcasecmp(Id,"MP3-Play-v1")) { nathan@0: if(Data) { nathan@0: struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; nathan@0: msd->result=ExternalPlay(msd->data.filename,false); nathan@0: } nathan@0: return true; nathan@0: } nathan@0: else if(!strcasecmp(Id,"MP3-Test-v1")) { nathan@0: if(Data) { nathan@0: struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; nathan@0: msd->result=ExternalPlay(msd->data.filename,true); nathan@0: } nathan@0: return true; nathan@0: } nathan@0: return false; nathan@0: } nathan@0: nathan@0: #if APIVERSNUM >= 10331 nathan@0: nathan@0: const char **cPluginMp3::SVDRPHelpPages(void) nathan@0: { nathan@0: static const char *HelpPages[] = { nathan@0: "PLAY \n" nathan@0: " Triggers playback of file 'filename'.", nathan@0: "TEST \n" nathan@0: " Tests is playback of file 'filename' is possible.", nathan@0: "CURR\n" nathan@0: " Returns filename of song currently being replayed.", nathan@0: NULL nathan@0: }; nathan@0: return HelpPages; nathan@0: } nathan@0: nathan@0: cString cPluginMp3::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) nathan@0: { nathan@0: if(!strcasecmp(Command,"PLAY")) { nathan@0: if(*Option) { nathan@0: if(ExternalPlay(Option,false)) return "Playback triggered"; nathan@0: else { ReplyCode=550; return "Playback failed"; } nathan@0: } nathan@0: else { ReplyCode=501; return "Missing filename"; } nathan@0: } nathan@0: else if(!strcasecmp(Command,"TEST")) { nathan@0: if(*Option) { nathan@0: if(ExternalPlay(Option,true)) return "Playback possible"; nathan@0: else { ReplyCode=550; return "Playback not possible"; } nathan@0: } nathan@0: else { ReplyCode=501; return "Missing filename"; } nathan@0: } nathan@0: else if(!strcasecmp(Command,"CURR")) { nathan@0: cControl *control=cControl::Control(); nathan@0: if(control && typeid(*control)==typeid(cMP3Control)) { nathan@0: cMP3PlayInfo mode; nathan@0: if(mgr->Info(-1,&mode)) return mode.Filename; nathan@0: else return ""; nathan@0: } nathan@0: else { ReplyCode=550; return "No running playback"; } nathan@0: } nathan@0: return NULL; nathan@0: } nathan@0: nathan@0: #endif // 1.3.31 nathan@0: #endif // 1.3.30 nathan@0: nathan@0: VDRPLUGINCREATOR(cPluginMp3); // Don't touch this!