2 * MP3/MPlayer plugin to VDR (C++)
4 * (C) 2001-2006 Stefan Huelswitt <s.huelswitt@gmx.de>
6 * This code is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This code is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
34 #define di(x) { (x); }
39 const char *imagecache = "/var/cache/images/mp3";
40 const char *imageconv = "image_convert.sh";
42 // image suffixes to search
43 const char *img_suff[] = { "jpg","png","gif",0 };
44 // exclude list for instant playlist creation
45 const char *excl_pl[] = { "*"PLAYLISTEXT,"*.jpg","*.gif","*.png",0 };
46 // exclude list for song browser
47 const char *excl_br[] = { ".*","*.jpg","*.gif","*.png",0 };
49 // --- cImageConvert -----------------------------------------------------------
51 class cImageConvert : private cThread {
54 enum eStatus { stNone, stRun, stFin };
57 virtual void Action(void);
61 bool Convert(const char *Image);
65 cImageConvert::cImageConvert(void)
67 image=0; status=stNone;
70 cImageConvert::~cImageConvert()
72 if(status==stRun) Cancel(10);
76 bool cImageConvert::Convert(const char *Image)
87 bool cImageConvert::Status(void)
89 if(status==stRun && !Active()) status=stFin;
93 void cImageConvert::Action(void)
96 char *m, *cmd, *qp, *qm;
97 asprintf(&m,"%s%s.mpg",imagecache,image);
98 di(printf("image: convert started %s -> %s\n",image,m))
99 asprintf(&cmd,"%s \"%s\" \"%s\"",imageconv,qp=Quote(image),qm=Quote(m));
101 if(r!=0) di(printf("image: convert returned with code %d. Failed?\n",r))
102 free(cmd); free(qp); free(qm); free(m);
103 di(printf("image: convert finished\n"))
107 // --- cSong -------------------------------------------------------------------
109 cSong::cSong(cFileObj *Obj)
111 obj=new cFileObj(Obj);
115 cSong::cSong(cFileSource *Source, const char *Subdir, const char *Name)
117 obj=new cFileObj(Source,Subdir,Name,otFile);
121 cSong::cSong(cSong *Song)
123 obj=new cFileObj(Song->obj);
131 obj->Source()->Unblock();
136 void cSong::Init(void)
138 decoder=0; user=0; image=0; conv=0; queueStat=0;
139 fromDOS=decoderFailed=false;
140 obj->Source()->Block();
143 #if APIVERSNUM >= 10315
144 int cSong::Compare(const cListObject &ListObject) const
146 bool cSong::operator<(const cListObject &ListObject)
149 cSong *song=(cSong *)&ListObject;
150 #if APIVERSNUM >= 10315
151 return strcasecmp(obj->Path(),song->obj->Path());
153 return strcasecmp(obj->Path(),song->obj->Path())<0;
157 cSongInfo *cSong::Info(bool get)
161 if(decoder) si=decoder->SongInfo(get);
165 cDecoder *cSong::Decoder(void)
168 if(!decoder && !decoderFailed) {
169 decoder=cDecoders::FindDecoder(obj);
170 if(!decoder) decoderFailed=true;
176 void cSong::Convert(void)
178 char *Name=Convert2Unix(obj->Name());
184 char *cSong::Convert2Unix(const char *name) const
186 char *Name=strdup(name);
197 char *cSong::Convert2Dos(const char *name)
199 char *Name=strdup(name);
210 bool cSong::Parse(char *s, const char *reldir) const
212 s=skipspace(stripspace(s));
214 if(s[0]=='/' || !reldir)
226 bool cSong::Save(FILE *f, const char *reldir) const
228 const char *path=obj->Path();
230 int l=strlen(reldir);
231 if(!strncasecmp(path,reldir,l)) path+=l+1;
233 return fprintf(f,"%s\n",path)>0;
236 bool cSong::FindImage(void)
238 if(image) return true;
240 char base[strlen(obj->Path())+32];
241 strcpy(base,obj->Path());
242 di(printf("image: checking image for %s\n",obj->Path()))
244 // song specific image
245 char *m=rindex(base,'.');
247 if((image=CheckImage(base))) return true;
249 // album specific image in song directory
250 if(!(m=rindex(base,'/'))) m=base-1;
252 if((image=CheckImage(base))) return true;
254 // artist specific image in parent directory
255 if((m=rindex(base,'/'))) {
257 if(!(m=rindex(base,'/'))) m=base-1;
258 strcpy(m+1,"artist");
259 if((image=CheckImage(base))) return true;
262 // default image in source basedir
263 if((image=CheckImage("background"))) return true;
265 di(printf("image: no image for %s\n",obj->Path()))
269 const char *cSong::CheckImage(const char *base) const
273 asprintf(&p,"%s/%s.%n ",obj->Source()->BaseDir(),base,&n);
274 for(const char **s=img_suff; *s; s++) {
276 if(strlen(*s)>5) printf("ERROR: buffer overflow in CheckImage ext=%s\n",*s);
279 di(printf("image: check %s\n",p))
280 if(!access(p,R_OK)) {
281 di(printf("image: found\n"))
289 #include "data-mp3-image.c"
290 extern void PropagateImage(const char *image);
292 bool cSong::Image(unsigned char * &mem, int &len)
296 if(!conv->Status()) {
297 di(printf("image: still queued\n"))
305 if(image || FindImage()) {
306 di(printf("image: loading image %s\n",image))
308 asprintf(&m,"%s%s.mpg",imagecache,image);
310 di(printf("image: not cached\n"))
312 di(printf("image: obviously convert failed...\n"))
315 if(!conv) conv=new cImageConvert;
316 if(conv && conv->Convert(image)) {
317 di(printf("image: convert queued\n"))
322 di(printf("image: queueing failed\n"))
328 di(printf("image: cached\n"))
329 int f=open(m,O_RDONLY);
334 mem=MALLOC(unsigned char,len);
336 if(read(f,mem,len)==len) res=1;
345 PropagateImage(res==1 ? image : 0);
348 di(printf("image: using static default image\n"))
349 len=sizeof(defaultImage);
350 mem=MALLOC(unsigned char,len);
352 memcpy(mem,defaultImage,len);
358 // -- cPlayList --------------------------------------------------------------
360 cPlayList::cPlayList(cFileObj *Obj)
362 obj=new cFileObj(Obj);
366 cPlayList::cPlayList(cFileSource *Source, const char *Subdir, const char *Name)
368 obj=new cFileObj(Source,Subdir,Name,otFile);
372 cPlayList::cPlayList(cPlayList *List)
374 obj=new cFileObj(List->obj);
378 cPlayList::~cPlayList()
382 obj->Source()->Unblock();
386 void cPlayList::Init(void)
388 extbuffer=basename=0;
390 obj->Source()->Block();
394 void cPlayList::Set(void)
396 free(basename); basename=0;
398 basename=strdup(obj->Name());
399 int l=strlen(basename)-strlen(PLAYLISTEXT);
400 if(l>0 && !strcasecmp(basename+l,PLAYLISTEXT)) basename[l]=0;
404 #if APIVERSNUM >= 10315
405 int cPlayList::Compare(const cListObject &ListObject) const
407 bool cPlayList::operator<(const cListObject &ListObject)
410 cPlayList *list=(cPlayList *)&ListObject;
411 #if APIVERSNUM >= 10315
412 return strcasecmp(obj->Name(),list->obj->Name());
414 return strcasecmp(obj->Name(),list->obj->Name())<0;
418 bool cPlayList::Load(void)
422 FILE *f=fopen(obj->FullPath(),"r");
426 while(fgets(buffer,sizeof(buffer),f)>0) {
428 if(!strncmp(buffer,WINAMPEXT,strlen(WINAMPEXT))) {
429 d(printf("mp3: detected WinAmp style playlist\n"))
434 if(!isempty(buffer)) {
435 cSong *song=new cSong(obj->Source(),0,0);
436 if(song->Parse(buffer,obj->Subdir())) Add(song);
438 esyslog("error loading playlist %s\n",obj->FullPath());
447 else LOG_ERROR_STR(obj->FullPath());
449 if(result && isWinAmp) {
451 while(song) { // if this is a WinAmp playlist, convert \ to /
453 song=cList<cSong>::Next(song);
459 bool cPlayList::Save(void)
462 cSafeFile f(obj->FullPath());
466 if(!song->Save(f,obj->Subdir())) {
470 song=cList<cSong>::Next(song);
472 if(!f.Close()) result=false;
478 bool cPlayList::Exists(void)
480 return obj->Exists();
483 bool cPlayList::TestName(const char *newName)
485 return obj->TestName(AddExt(newName,PLAYLISTEXT));
488 bool cPlayList::Rename(const char *newName)
490 bool r=obj->Rename(AddExt(newName,PLAYLISTEXT));
495 bool cPlayList::Create(const char *newName)
497 bool r=obj->Create(AddExt(newName,PLAYLISTEXT));
505 bool cPlayList::Delete(void)
507 return obj->Delete();
510 const char *cPlayList::AddExt(const char *FileName, const char *Ext)
512 free(extbuffer); extbuffer=0;
513 asprintf(&extbuffer,"%s%s",FileName,Ext);
517 // -- cInstantPlayList ------------------------------------------------------
519 cInstantPlayList::cInstantPlayList(cFileObj *Obj)
522 if(!Obj->Name()) Obj->SetName("instant");
525 bool cInstantPlayList::Load(void)
529 switch(obj->Type()) {
531 d(printf("instant: file %s\n",obj->Name()))
532 if(strcasecmp(obj->Name(),basename)) {
533 d(printf("instant: detected as playlist\n"))
534 res=cPlayList::Load();
543 d(printf("instant: dir %s\n",obj->Name()))
544 res=ScanDir(obj->Source(),obj->Path(),stFile,obj->Source()->Include(),excl_pl,true);
549 d(printf("instant: base\n"))
550 res=ScanDir(obj->Source(),0,stFile,obj->Source()->Include(),excl_pl,true);
558 void cInstantPlayList::DoItem(cFileSource *src, const char *subdir, const char *name)
560 Add(new cSong(src,subdir,name));
563 // -- cPlayLists --------------------------------------------------------------
565 bool cPlayLists::Load(cFileSource *Source)
567 static const char *spec[] = { "*"PLAYLISTEXT,0 };
569 bool res=ScanDir(Source,0,stFile,spec,0,false);
574 void cPlayLists::DoItem(cFileSource *src, const char *subdir, const char *name)
576 Add(new cPlayList(src,subdir,name));