diff options
Diffstat (limited to 'plugins/Watrack/stat')
-rw-r--r-- | plugins/Watrack/stat/default.tmpl | 89 | ||||
-rw-r--r-- | plugins/Watrack/stat/report.inc | 315 | ||||
-rw-r--r-- | plugins/Watrack/stat/stat.rc | 50 | ||||
-rw-r--r-- | plugins/Watrack/stat/stat.res | bin | 0 -> 3320 bytes | |||
-rw-r--r-- | plugins/Watrack/stat/stat_data.inc | 16 | ||||
-rw-r--r-- | plugins/Watrack/stat/stat_dlg.inc | 223 | ||||
-rw-r--r-- | plugins/Watrack/stat/stat_opt.inc | 62 | ||||
-rw-r--r-- | plugins/Watrack/stat/stat_rc.inc | 29 | ||||
-rw-r--r-- | plugins/Watrack/stat/stat_vars.inc | 21 | ||||
-rw-r--r-- | plugins/Watrack/stat/statlog.pas | 650 | ||||
-rw-r--r-- | plugins/Watrack/stat/wat_report.ico | bin | 0 -> 1406 bytes |
11 files changed, 1455 insertions, 0 deletions
diff --git a/plugins/Watrack/stat/default.tmpl b/plugins/Watrack/stat/default.tmpl new file mode 100644 index 0000000000..0e1920fc5d --- /dev/null +++ b/plugins/Watrack/stat/default.tmpl @@ -0,0 +1,89 @@ +const
+ IntTmpl:PAnsiChar=
+'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'#13#10+
+'<HTML>'#13#10+
+'<HEAD>'#13#10+
+'<TITLE>Report on %currenttime%</TITLE>'#13#10+
+'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />'#13#10+
+'<style>'#13#10+
+'table {background:#E0E0E0;padding:4}'#13#10+
+'* {padding:2; margin:0;font-family: arial}'#13#10+
+'td, div {font-size:10pt;border:1 solid black}'#13#10+
+'h2 {padding: 26 0 10}'#13#10+
+'.label, .num, .time {background:#C0C0C0;padding-left:4}'#13#10+
+'.tdbar {width:50%;padding:0 4 0 0;border-width:0}'#13#10+
+'.bar {background:#9BA298;padding-left:4;margin:0 4 0 0}'#13#10+
+'.num {padding:0 10; width:20px}'#13#10+
+'.time {text-align:center;width:20%}'#13#10+
+'</style>'#13#10+
+'</HEAD>'#13#10+
+'<BODY>'#13#10+
+'<center><h1>Report</h1><br/><h3>created %currenttime%</h3>'#13#10+
+'%block_freqartist%'#13#10+
+'<h2>Most popular artists:</h2><table style="width:90%">'#13#10+
+'%start%'#13#10+
+'<tr><td class="num">%num%.</td>'#13#10+
+'<td class="label">%artist%</td>'#13#10+
+'<td class="tdbar"><div class="bar" style="width:%percent%%;">%count%</div></td>'#13#10+
+'</tr>'#13#10+
+'%end%'#13#10+
+'</table>'#13#10+
+'%block_end%'#13#10+
+'%block_freqsongs%'#13#10+
+'<h2>Most frequently played songs:</h2><table style="width:90%">'#13#10+
+'%start%'#13#10+
+'<tr><td class="num">%num%.</td>'#13#10+
+'<td class="label">%artist% - %title% (%album%)</td>'#13#10+
+'<td class="tdbar"><div class="bar" style="width:%percent%%;">%count%</div></td>'#13#10+
+'</tr>'#13#10+
+'%end%'#13#10+
+'</table>'#13#10+
+'%block_end%'#13#10+
+'%block_freqalbum%'#13#10+
+'<h2>Most frequently played albums:</h2><table style="width:90%">'#13#10+
+'%start%'#13#10+
+'<tr><td class="num">%num%.</td>'#13#10+
+'<td class="label">%album%</td>'#13#10+
+'<td class="tdbar"><div class="bar" style="width:%percent%%;">%count%</div></td>'#13#10+
+'</tr>'#13#10+
+'%end%'#13#10+
+'</table>'#13#10+
+'%block_end%'#13#10+
+'%block_lastsongs%'#13#10+
+'<h2>Last played songs:</h2><table style="width:90%">'#13#10+
+'%start%'#13#10+
+'<tr><td class="num">%num%.</td>'#13#10+
+'<td class="time">[%date%]</td>'#13#10+
+'<td class="label">%artist% - %title%</td>'#13#10+
+'</tr>'#13#10+
+'%end%'#13#10+
+'</table>'#13#10+
+'%block_end%'#13#10+
+'%block_songtime%'#13#10+
+'<h2>Longest songs:</h2><table style="width:90%">'#13#10+
+'%start%'#13#10+
+'<tr><td class="num">%num%.</td>'#13#10+
+'<td class="label">%artist% - %title%</td>'#13#10+
+'<td class="tdbar"><div class="bar" style="width:%percent%%;">%length%</div></td>'#13#10+
+'</tr>'#13#10+
+'%end%'#13#10+
+'</table>'#13#10+
+'%block_end%'#13#10+
+'%block_freqpath%'#13#10+
+'<h2>Most frequently used paths:</h2><table style="width:90%">'#13#10+
+'%start%'#13#10+
+'<tr><td class="num">%num%.</td>'#13#10+
+'<td class="label">%path%</td>'#13#10+
+'<td class="tdbar"><div class="bar" style="width:%percent%%;">%count%</div></td>'#13#10+
+'</tr>'#13#10+
+'%end%'#13#10+
+'</table>'#13#10+
+'%block_end%'#13#10+
+'<h2>Total played time is:</h2><table style="width:90%">'#13#10+
+'<tr><td class="label">Total logged music time - %totaltime%</td>'#13#10+
+'<td class="label">Total logged music files - %totalfiles%</td>'#13#10+
+'</tr></table>'#13#10+
+''#13#10+
+'</center>'#13#10+
+'</BODY>'#13#10+
+'</HTML>'#13#10;
diff --git a/plugins/Watrack/stat/report.inc b/plugins/Watrack/stat/report.inc new file mode 100644 index 0000000000..0cd4fcfb22 --- /dev/null +++ b/plugins/Watrack/stat/report.inc @@ -0,0 +1,315 @@ +{$include default.tmpl}
+function ReadTemplate(fname:PAnsiChar;var buf:PAnsiChar):integer;
+var
+ f:THANDLE;
+ size:integer;
+begin
+ if (fname=nil) or (fname^=#0) then
+ f:=INVALID_HANDLE_VALUE
+ else
+ f:=Reset(fname);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ result:=0
+ else
+ begin
+ size:=FileSize(f);
+ mGetMem(buf,size+1);
+ buf[size+1]:=#0;
+ BlockRead(f,buf^,size);
+ CloseHandle(f);
+ result:=size;
+ end;
+end;
+
+function StatOut(report,log,template:PAnsiChar):boolean;
+
+const
+ bufsize = 16384;
+var
+ fout:THANDLE;
+ tt,tf:array [0..15] of AnsiChar;
+ timebuf:array [0..17] of AnsiChar; // for current date / time
+ outbuf:PAnsiChar;
+ outpos:PAnsiChar;
+
+ procedure OutChar(var pc:PAnsiChar);
+ begin
+ outpos^:=pc^;
+ inc(pc);
+ inc(outpos);
+ if (outpos-outbuf)=bufsize then
+ begin
+ BlockWrite(fout,outbuf^,bufsize);
+ outpos:=outbuf;
+ end;
+ end;
+
+ procedure OutStr(pc:PAnsiChar);
+ begin
+ while pc^<>#0 do
+ OutChar(pc);
+ end;
+
+ procedure OutputBlock(var start:PAnsiChar;var Root:pCells;asortmode:integer);
+ const
+ blocksize = 8192;
+ var
+ i,max,cnt,len:integer;
+ items:cardinal;
+ Cell:pStatCell;
+ ls,ls1:array [0..511] of AnsiChar;
+ block:array [0..blocksize-1] of AnsiChar;
+ begin
+ len:=StrIndex(start,'%end%');
+ if len=0 then
+ len:=StrLen(start)
+ else
+ dec(len);
+ if len>6143 then
+ err('Template block too large');
+
+ Resort(Root,asortmode);
+
+ case asortmode of
+ stArtist,stAlbum,stPath: begin
+
+ Cell:=Root^.Cells[0];
+ max:=Cell^.Count;
+ if asortmode=stPath then OnlyPath(ls,Cell^.MFile); // speed optimization
+
+ for i:=0 to Root^.Count-1 do
+ begin
+ with Root^.Cells[i]^ do
+ begin
+ AltCount:=0;
+ if asortmode=stArtist then cnt:=lstrcmpia(Cell^.Artist,Artist)
+ else if asortmode=stAlbum then cnt:=lstrcmpia(Cell^.Album,Album)
+ else cnt:=lstrcmpia(ls,OnlyPath(ls1,MFile));
+ if cnt=0 then
+ inc(max,Count)
+ else
+ begin
+ Cell^.AltCount:=max;
+ Cell:=Root^.Cells[i];
+ if asortmode=stPath then OnlyPath(ls,Cell^.MFile); // speed optimization
+ max:=Count;
+ end;
+ end;
+ end;
+ Cell^.AltCount:=max;
+
+ Resort(Root,stAltCount);
+ if (asortmode=stAlbum) and (Root^.Cells[0]^.Album^=#0) then
+ begin
+ if Root^.Count>1 then
+ max:=Root^.Cells[1]^.AltCount
+ else
+ max:=0;
+ end
+ else
+ max:=Root^.Cells[0]^.AltCount;
+ end;
+ stCount: begin
+ max:=Root^.Cells[0]^.Count;
+ end;
+ stLength: begin
+ max:=Root^.Cells[0]^.Length;
+ end;
+ else
+ max:=1;
+ end;
+
+ items:=1;
+ if ReportItems>0 then
+ for i:=0 to Root^.Count-1 do
+ begin
+ with Root^.Cells[i]^ do
+ begin
+ if (asortmode=stAlbum) and (Album^=#0) then continue;
+ case asortmode of
+ stArtist,
+ stAlbum,
+ stPath : cnt:=AltCount;
+ stCount : cnt:=Count;
+ stLength: cnt:=Length;
+ else
+ cnt:=1;
+ end;
+ if cnt=0 then break;
+ move(start^,block,len);
+ block[len]:=#0;
+ StrReplace(block,'%date%' ,ShowTime(ls,LastTime));
+ StrReplace(block,'%length%' ,IntToTime(ls,Length));
+ StrReplace(block,'%artist%' ,Artist);
+ StrReplace(block,'%title%' ,Title);
+ StrReplace(block,'%album%' ,Album);
+ StrReplace(block,'%file%' ,MFile);
+ StrReplace(block,'%path%' ,OnlyPath(ls,MFile));
+ StrReplace(block,'%num%' ,IntToStr(ls,items));
+ StrReplace(block,'%currenttime%',timebuf);
+ StrReplace(block,'%totaltime%' ,tt);
+ StrReplace(block,'%totalfiles%' ,tf);
+ StrReplace(block,'%percent%' ,IntToStr(ls,round(cnt*100/max)));
+ StrReplace(block,'%count%' ,IntToStr(ls,cnt));
+ OutStr(block);
+ end;
+ if items=ReportItems then break;
+ inc(items);
+ end;
+ inc(start,len+5);
+ end;
+
+var
+ TmplBuf:PAnsiChar;
+ ptr:PAnsiChar;
+ i,j,k:integer;
+ size:integer;
+ lsortmode:integer;
+ MyTime:TSYSTEMTIME;
+ Root:pCells;
+ b1,tmp:PAnsiChar;
+begin
+ result:=false;
+ GetLocalTime(MyTime);
+ ShowTime(timebuf,PackTime(MyTime));
+
+ Lock:=true;
+ Root:=BuildTree(log,b1);
+ if Root<>nil then
+ begin
+ Resort(Root,stArtist);
+ Lock:=false;
+ size:=ReadTemplate(template,TmplBuf);
+ if size=0 then
+ begin
+ StrDup(TmplBuf,IntTmpl);
+ size:=StrLen(IntTmpl);
+ end;
+ ptr:=TmplBuf;
+ fout:=Rewrite(report);
+ if fout=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ mGetMem(outbuf,bufsize);
+ outpos:=outbuf;
+
+ i:=0;
+ k:=0;
+ for j:=0 to Root^.Count-1 do
+ begin
+ inc(k);
+ with Root^.Cells[j]^ do
+ inc(i,Length*Count);
+ end;
+ IntToTime(tt,i); // total time
+ IntToStr(tf,k); // total files
+
+ lsortmode:=stDate;
+ while (ptr-TmplBuf)<size do
+ begin
+ while (ptr^<>'%') and (ptr^<>#0) do
+ OutChar(ptr);
+ if ptr^=#0 then break;
+ if StrCmp(ptr,'%block_',7)=0 then
+ begin
+ if ptr>@TmplBuf then
+ begin
+ if (ptr-1)^<' ' then
+ k:=-1;
+ end;
+ inc(ptr,7);
+ if StrCmp(ptr,'end%',4)=0 then
+ begin
+ i:=4;
+ end
+ else if StrCmp(ptr,'freqartist%',11)=0 then
+ begin
+ lsortmode:=stArtist;
+ i:=11;
+ end
+ else if StrCmp(ptr,'freqsongs%',10)=0 then
+ begin
+ lsortmode:=stCount;
+ i:=10;
+ end
+ else if StrCmp(ptr,'freqalbum%',10)=0 then
+ begin
+ lsortmode:=stAlbum;
+ i:=10;
+ end
+ else if StrCmp(ptr,'lastsongs%',10)=0 then
+ begin
+ lsortmode:=stDate;
+ i:=10;
+ end
+ else if StrCmp(ptr,'songtime%',9)=0 then
+ begin
+ lsortmode:=stLength;
+ i:=9;
+ end
+ else if StrCmp(ptr,'freqpath%',9)=0 then
+ begin
+ lsortmode:=stPath;
+ i:=9;
+ end
+ else
+ begin
+ OutChar(ptr);
+ continue;
+ end;
+ inc(ptr,i);
+ if k<0 then
+ begin
+ while (ptr^<' ') and (ptr^<>#0) do inc(ptr);
+ k:=0;
+ end;
+ if (ReportMask and lsortmode)=0 then
+ begin
+ tmp:=StrPos(ptr,'%block_end%');
+ if tmp<>nil then
+ ptr:=tmp+11
+ else
+ break;
+ end;
+ end
+ else if StrCmp(ptr,'%start%',7)=0 then
+ begin
+ if ptr>@TmplBuf then
+ begin
+ if (ptr-1)^<' ' then
+ k:=-1;
+ end;
+ inc(ptr,7);
+ if k<0 then
+ begin
+ while (ptr^<' ') and (ptr^<>#0) do inc(ptr);
+ k:=0;
+ end;
+ OutputBlock(ptr,Root,lsortmode);
+ end
+ else if StrCmp(ptr,'%currenttime%',13)=0 then
+ begin
+ inc(ptr,13);
+ OutStr(timebuf);
+ end
+ else if StrCmp(ptr,'%totalfiles%',12)=0 then
+ begin
+ inc(ptr,12);
+ OutStr(tf);
+ end
+ else if StrCmp(ptr,'%totaltime%',11)=0 then
+ begin
+ inc(ptr,11);
+ OutStr(tt);
+ end
+ else
+ OutChar(ptr);
+ end;
+ BlockWrite(fout,outbuf^,outpos-outbuf);
+ CloseHandle(fout);
+ mFreeMem(outbuf);
+ mFreeMem(TmplBuf);
+ ClearStatCells(Root);
+ result:=true;
+ end;
+ mFreeMem(b1);
+end;
diff --git a/plugins/Watrack/stat/stat.rc b/plugins/Watrack/stat/stat.rc new file mode 100644 index 0000000000..9bedcabf3d --- /dev/null +++ b/plugins/Watrack/stat/stat.rc @@ -0,0 +1,50 @@ +#include "stat_rc.inc"
+
+LANGUAGE 0,0
+
+STATS DIALOGEX 0, 0, 304, 226, 0
+STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ PUSHBUTTON "Delete", IDC_CLEAR , 242, 11, 56, 14
+ LTEXT "Statistic log file", -1 , 16, 17, 148, 12
+ EDITTEXT IDC_STATNAME , 6, 29, 214, 14
+ PUSHBUTTON "...", IDC_SNBUTTON , 222, 29, 16, 14
+ PUSHBUTTON "Sort", IDC_SORTFILE , 242, 29, 56, 14
+ RTEXT "Autosort period, days",-1 , 124, 45, 142, 12, SS_CENTERIMAGE
+ EDITTEXT IDC_AUTOSORT , 270, 45, 28, 12, ES_RIGHT | ES_NUMBER
+ LTEXT "Report file", -1 , 16, 47, 148, 12
+ EDITTEXT IDC_REPNAME , 6, 59, 214, 14
+ PUSHBUTTON "...", IDC_RNBUTTON , 222, 59, 16, 14
+ PUSHBUTTON "Report", IDC_REPORT , 242, 59, 56, 14
+ LTEXT "Template file", -1 , 16, 77, 148, 12
+ EDITTEXT IDC_TMPLNAME , 6, 89, 214, 14
+ PUSHBUTTON "...", IDC_TNBUTTON , 222, 89, 16, 14
+ PUSHBUTTON "Export default", IDC_EXPORTDEF, 242, 89, 56, 14
+
+ CONTROL "", -1, "STATIC", SS_ETCHEDHORZ, 4, 107, 296, 2
+
+ GROUPBOX "Show in report", -1, 6, 111, 144, 84
+ AUTOCHECKBOX "Freq. songs" , IDC_FREQART , 12, 121, 136, 12, BS_VCENTER
+ AUTOCHECKBOX "Freq. artists" , IDC_FREQSONG , 12, 133, 136, 12, BS_VCENTER
+ AUTOCHECKBOX "Freq. album" , IDC_FREQALBUM, 12, 145, 136, 12, BS_VCENTER
+ AUTOCHECKBOX "Freq. paths" , IDC_FREQPATH , 12, 157, 136, 12, BS_VCENTER
+ AUTOCHECKBOX "Last played songs", IDC_LASTSONG , 12, 169, 136, 12, BS_VCENTER
+ AUTOCHECKBOX "Song time" , IDC_SONGTIME , 12, 181, 136, 12, BS_VCENTER
+
+ GROUPBOX "Sort log file", -1, 154, 111, 144, 84
+ AUTORADIOBUTTON "by Title" , IDC_BYTITLE , 158, 121, 136, 12, NOT WS_TABSTOP
+ AUTORADIOBUTTON "by Date" , IDC_BYDATE , 158, 133, 136, 12, NOT WS_TABSTOP
+ AUTORADIOBUTTON "by Count" , IDC_BYCOUNT , 158, 145, 136, 12, NOT WS_TABSTOP
+ AUTORADIOBUTTON "by Path" , IDC_BYPATH , 158, 157, 136, 12, NOT WS_TABSTOP
+ AUTORADIOBUTTON "by Length" , IDC_BYLENGTH , 158, 169, 136, 12, NOT WS_TABSTOP
+ AUTOCHECKBOX "Reverse order", IDC_DIRECTION, 158, 181, 136, 12, BS_VCENTER | BS_MULTILINE
+
+ LTEXT "Report Items", -1, 38, 208, 112, 12, SS_CENTERIMAGE
+ EDITTEXT IDC_ITEMS, 6, 208, 28, 12, ES_RIGHT | ES_NUMBER
+ AUTOCHECKBOX "Open report" , IDC_RUNREPORT, 154, 196, 146, 12, BS_VCENTER
+ AUTOCHECKBOX "Add report file ext.", IDC_ADDEXT , 154, 208, 146, 12, BS_VCENTER | BS_MULTILINE
+}
+
+BTN_REPORT ICON "wat_report.ico"
diff --git a/plugins/Watrack/stat/stat.res b/plugins/Watrack/stat/stat.res Binary files differnew file mode 100644 index 0000000000..eca192d5ba --- /dev/null +++ b/plugins/Watrack/stat/stat.res diff --git a/plugins/Watrack/stat/stat_data.inc b/plugins/Watrack/stat/stat_data.inc new file mode 100644 index 0000000000..ec539a3ecd --- /dev/null +++ b/plugins/Watrack/stat/stat_data.inc @@ -0,0 +1,16 @@ +{statistic data}
+const
+ MenuReportPos = 500050001;
+
+const
+ smDirect = 1;
+ smReverse = 2;
+
+const
+ stArtist = $0001;
+ stCount = $0002;
+ stPath = $0004;
+ stDate = $0008;
+ stLength = $0010;
+ stAltCount = $0020;
+ stAlbum = $0040;
diff --git a/plugins/Watrack/stat/stat_dlg.inc b/plugins/Watrack/stat/stat_dlg.inc new file mode 100644 index 0000000000..64a9b97f7c --- /dev/null +++ b/plugins/Watrack/stat/stat_dlg.inc @@ -0,0 +1,223 @@ +{Statistic Dialog}
+
+{$include stat_rc.inc}
+
+procedure SetReportMask(Dlg:hwnd);
+begin
+ ReportMask:=0;
+ if IsDlgButtonChecked(Dlg,IDC_FREQART)=BST_CHECKED then
+ ReportMask:=ReportMask or stArtist;
+ if IsDlgButtonChecked(Dlg,IDC_FREQSONG)=BST_CHECKED then
+ ReportMask:=ReportMask or stCount;
+ if IsDlgButtonChecked(Dlg,IDC_FREQPATH)=BST_CHECKED then
+ ReportMask:=ReportMask or stPath;
+ if IsDlgButtonChecked(Dlg,IDC_LASTSONG)=BST_CHECKED then
+ ReportMask:=ReportMask or stDate;
+ if IsDlgButtonChecked(Dlg,IDC_SONGTIME)=BST_CHECKED then
+ ReportMask:=ReportMask or stLength;
+ if IsDlgButtonChecked(Dlg,IDC_FREQALBUM)=BST_CHECKED then
+ ReportMask:=ReportMask or stAlbum;
+end;
+
+procedure EnableItems(Dlg:hwnd;enable:boolean);
+begin
+ EnableWindow(GetDlgItem(Dlg,IDC_STATNAME) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_SNBUTTON) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_SORTFILE) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_REPORT) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_CLEAR) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_BYTITLE) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_BYDATE) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_BYCOUNT) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_BYPATH) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_BYLENGTH) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_DIRECTION),enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_REPNAME) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_RNBUTTON) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_ITEMS) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_FREQART) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_FREQSONG) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_FREQALBUM),enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_FREQPATH) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_LASTSONG) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_SONGTIME) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_RUNREPORT),enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_ADDEXT) ,enable);
+ EnableWindow(GetDlgItem(Dlg,IDC_AUTOSORT) ,enable);
+end;
+
+function DlgProcOptions(Dialog:HWnd; hMessage:dword;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
+const
+ changed:boolean=false;
+var
+ buf,buf1:array [0..511] of AnsiChar;
+ tmp:longbool;
+ p:PAnsiChar;
+ f:THANDLE;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ SetDlgItemInt(Dialog,IDC_ITEMS,ReportItems,false);
+ if ReportName=nil then
+ p:=''
+ else
+ p:=ReportName;
+ SetDlgItemTextA(Dialog,IDC_REPNAME,p);
+ if StatName=nil then
+ p:=''
+ else
+ p:=StatName;
+ SetDlgItemTextA(Dialog,IDC_STATNAME,p);
+ if TmplName=nil then
+ p:=''
+ else
+ p:=TmplName;
+ SetDlgItemTextA(Dialog,IDC_TMPLNAME,p);
+ SetDlgItemInt(Dialog,IDC_AUTOSORT,AutoSort,false);
+ CheckDlgButton(Dialog,IDC_RUNREPORT,RunReport);
+ CheckDlgButton(Dialog,IDC_ADDEXT,DoAddExt);
+
+ CheckDlgButton(Dialog,IDC_BYTITLE ,ord(SortMode=stArtist));
+ CheckDlgButton(Dialog,IDC_BYDATE ,ord(SortMode=stDate));
+ CheckDlgButton(Dialog,IDC_BYCOUNT ,ord(SortMode=stCount));
+ CheckDlgButton(Dialog,IDC_BYPATH ,ord(SortMode=stPath));
+ CheckDlgButton(Dialog,IDC_BYLENGTH,ord(SortMode=stLength));
+
+ if Direction=smReverse then
+ CheckDlgButton(Dialog,IDC_DIRECTION,BST_CHECKED);
+
+ if (ReportMask and stArtist)<>0 then
+ CheckDlgButton(Dialog,IDC_FREQART,BST_CHECKED);
+ if (ReportMask and stAlbum)<>0 then
+ CheckDlgButton(Dialog,IDC_FREQALBUM,BST_CHECKED);
+ if (ReportMask and stCount)<>0 then
+ CheckDlgButton(Dialog,IDC_FREQSONG,BST_CHECKED);
+ if (ReportMask and stPath)<>0 then
+ CheckDlgButton(Dialog,IDC_FREQPATH,BST_CHECKED);
+ if (ReportMask and stDate)<>0 then
+ CheckDlgButton(Dialog,IDC_LASTSONG,BST_CHECKED);
+ if (ReportMask and stLength)<>0 then
+ CheckDlgButton(Dialog,IDC_SONGTIME,BST_CHECKED);
+ result:=0;
+ changed:=false;
+ end;
+
+ WM_COMMAND: begin
+ if (wParam shr 16)=BN_CLICKED then
+ begin
+ case loword(wParam) of
+ IDC_BYTITLE : SortMode:=stArtist;
+ IDC_BYDATE : SortMode:=stDate;
+ IDC_BYCOUNT : SortMode:=stCount;
+ IDC_BYPATH : SortMode:=stPath;
+ IDC_BYLENGTH: SortMode:=stLength;
+ IDC_RUNREPORT: RunReport :=IsDlgButtonChecked(Dialog,IDC_RUNREPORT);
+ IDC_ADDEXT: DoAddExt :=IsDlgButtonChecked(Dialog,IDC_ADDEXT);
+ IDC_DIRECTION: begin
+ if IsDlgButtonChecked(Dialog,IDC_DIRECTION)=BST_CHECKED then
+ Direction:=smReverse
+ else
+ Direction:=smDirect;
+ end;
+
+ IDC_CLEAR: begin
+ DeleteFileA(StatName);
+ exit;
+ end;
+ IDC_SNBUTTON: begin
+ if ShowDlg(buf,StatName) then
+ SetDlgItemTextA(Dialog,IDC_STATNAME,buf);
+ end;
+ IDC_TNBUTTON: begin
+ if ShowDlg(buf,TmplName) then
+ SetDlgItemTextA(Dialog,IDC_TMPLNAME,buf);
+ end;
+ IDC_RNBUTTON: begin
+ if ShowDlg(buf,ReportName) then
+ SetDlgItemTextA(Dialog,IDC_REPNAME,buf);
+ end;
+ IDC_SORTFILE: begin
+ GetDlgItemTextA(Dialog,IDC_STATNAME,buf,511);
+ if buf[0]<>#0 then
+ SortFile(buf,SortMode,Direction);
+ exit;
+ end;
+ IDC_EXPORTDEF: begin
+ if ShowDlg(buf,TmplName) then
+ begin
+ f:=Rewrite(buf);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ err('Can''t create file')
+ else
+ begin
+ BlockWrite(f,IntTmpl^,StrLen(IntTmpl));
+ CloseHandle(f);
+ end;
+ end;
+ exit;
+ end;
+ IDC_REPORT: begin
+ ReportItems:=GetDlgItemInt(Dialog,IDC_ITEMS,tmp,false);
+ if ReportItems=0 then
+ ReportItems:=1;
+ GetDlgItemTextA(Dialog,IDC_REPNAME,buf1,511);
+ GetDlgItemTextA(Dialog,IDC_TMPLNAME,buf,511);
+ SetReportMask(Dialog);
+ CallService(MS_WAT_MAKEREPORT,TWPARAM(@buf),TLPARAM(@buf1));
+ end;
+ end;
+ end;
+ if ((wParam shr 16)=EN_CHANGE) or ((wParam shr 16)=BN_CLICKED) then
+ begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ changed:=true;
+ end;
+ result:=1;
+ end;
+
+ WM_NOTIFY: begin
+ if (integer(PNMHdr(lParam)^.code)=PSN_APPLY) and changed then
+ begin
+ GetDlgItemTextA(Dialog,IDC_STATNAME,buf,511);
+ mFreeMem(StatName);
+ if buf[0]<>#0 then
+ begin
+ buf1[0]:=#0;
+ CallService(MS_UTILS_PATHTORELATIVE,TWPARAM(@buf),TLPARAM(@buf1));
+ StrDup(StatName,buf1);
+ end;
+
+ GetDlgItemTextA(Dialog,IDC_REPNAME,buf,511);
+ mFreeMem(ReportName);
+ if buf[0]<>#0 then
+ begin
+ buf1[0]:=#0;
+ CallService(MS_UTILS_PATHTORELATIVE,TWPARAM(@buf),TLPARAM(@buf1));
+ StrDup(ReportName,buf1);
+ end;
+
+ GetDlgItemTextA(Dialog,IDC_TMPLNAME,buf,511);
+ mFreeMem(TmplName);
+ if buf[0]<>#0 then
+ begin
+ buf1[0]:=#0;
+ CallService(MS_UTILS_PATHTORELATIVE,TWPARAM(@buf),TLPARAM(@buf1));
+ StrDup(TmplName,buf1);
+ end;
+
+ AutoSort:=GetDlgItemInt(Dialog,IDC_AUTOSORT,tmp,false);
+ ReportItems:=GetDlgItemInt(Dialog,IDC_ITEMS,tmp,false);
+ if ReportItems=0 then
+ ReportItems:=1;
+ SetReportMask(Dialog);
+ result:=1;
+ savestat;
+ changed:=false;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/stat/stat_opt.inc b/plugins/Watrack/stat/stat_opt.inc new file mode 100644 index 0000000000..8d8bed6bb5 --- /dev/null +++ b/plugins/Watrack/stat/stat_opt.inc @@ -0,0 +1,62 @@ +{statistic load/save options}
+const
+ opt_ModStatus :PAnsiChar = 'module/statistic';
+
+ opt_StatName :PAnsiChar = 'report/statname';
+ opt_RepName :PAnsiChar = 'report/repname';
+ opt_TmplName :PAnsiChar = 'report/tmplname';
+ opt_SortMode :PAnsiChar = 'report/sortmode';
+ opt_ReportMask:PAnsiChar = 'report/reportmask';
+ opt_ReportItem:PAnsiChar = 'report/reportitems';
+ opt_Direction :PAnsiChar = 'report/direction';
+ opt_RunReport :PAnsiChar = 'report/runreport';
+ opt_AddExt :PAnsiChar = 'report/addext';
+ opt_AutoSort :PAnsiChar = 'report/autosort';
+ opt_LastSort :PAnsiChar = 'report/lastsort';
+
+function GetModStatus:integer;
+begin
+ result:=DBReadByte(0,PluginShort,opt_ModStatus,1);
+end;
+
+procedure SetModStatus(stat:integer);
+begin
+ DBWriteByte(0,PluginShort,opt_ModStatus,stat);
+end;
+
+procedure loadstat;
+begin
+ ReportName :=DBReadString(0,PluginShort,opt_RepName ,nil);
+ StatName :=DBReadString(0,PluginShort,opt_StatName,nil);
+ TmplName :=DBReadString(0,PluginShort,opt_TmplName,nil);
+ DoAddExt :=DBReadByte (0,PluginShort,opt_AddExt ,BST_CHECKED);
+ RunReport :=DBReadByte (0,PluginShort,opt_RunReport ,BST_UNCHECKED);
+ Direction :=DBReadByte (0,PluginShort,opt_Direction ,smDirect);
+ SortMode :=DBReadByte (0,PluginShort,opt_SortMode ,stArtist);
+ ReportItems:=DBReadWord (0,PluginShort,opt_ReportItem,10);
+ ReportMask :=DBReadWord (0,PluginShort,opt_ReportMask,$FFFF);
+ AutoSort :=DBReadByte (0,PluginShort,opt_AutoSort ,1);
+ LastSort :=DBReadDWord (0,PluginShort,opt_LastSort ,0);
+end;
+
+procedure savestat;
+begin
+ DBWriteString(0,PluginShort,opt_RepName ,ReportName);
+ DBWriteString(0,PluginShort,opt_StatName,StatName);
+ DBWriteString(0,PluginShort,opt_TmplName,TmplName);
+ DBWriteByte (0,PluginShort,opt_AddExt ,DoAddExt);
+ DBWriteByte (0,PluginShort,opt_RunReport ,RunReport);
+ DBWriteByte (0,PluginShort,opt_Direction ,Direction);
+ DBWriteByte (0,PluginShort,opt_SortMode ,SortMode);
+ DBWriteWord (0,PluginShort,opt_ReportItem ,ReportItems);
+ DBWriteWord (0,PluginShort,opt_ReportMask ,ReportMask);
+ DBWriteByte (0,PluginShort,opt_AutoSort ,AutoSort);
+// DBWriteDWord (0,PluginShort,opt_LastSort ,LastSort);
+end;
+
+procedure FreeStat;
+begin
+ mFreeMem(ReportName);
+ mFreeMem(StatName);
+ mFreeMem(TmplName);
+end;
diff --git a/plugins/Watrack/stat/stat_rc.inc b/plugins/Watrack/stat/stat_rc.inc new file mode 100644 index 0000000000..ff697e95f7 --- /dev/null +++ b/plugins/Watrack/stat/stat_rc.inc @@ -0,0 +1,29 @@ +const
+ IDC_STATNAME = 1026;
+ IDC_SNBUTTON = 1027;
+ IDC_SORTFILE = 1028;
+ IDC_REPORT = 1029;
+ IDC_BYTITLE = 1030;
+ IDC_BYDATE = 1031;
+ IDC_BYCOUNT = 1032;
+ IDC_BYPATH = 1033;
+ IDC_DIRECTION = 1034;
+ IDC_REPNAME = 1035;
+ IDC_RNBUTTON = 1036;
+ IDC_ITEMS = 1037;
+ IDC_CLEAR = 1038;
+ IDC_FREQART = 1040;
+ IDC_FREQSONG = 1041;
+ IDC_FREQPATH = 1042;
+ IDC_LASTSONG = 1043;
+ IDC_SONGTIME = 1044;
+ IDC_TMPLNAME = 1045;
+ IDC_TNBUTTON = 1046;
+ IDC_EXPORTDEF = 1047;
+ IDC_RUNREPORT = 1048;
+ IDC_ADDEXT = 1049;
+ IDC_FREQALBUM = 1050;
+ IDC_AUTOSORT = 1051;
+ IDC_BYLENGTH = 1052;
+
+ BTN_REPORT = 12;
diff --git a/plugins/Watrack/stat/stat_vars.inc b/plugins/Watrack/stat/stat_vars.inc new file mode 100644 index 0000000000..ccc7c0c5b2 --- /dev/null +++ b/plugins/Watrack/stat/stat_vars.inc @@ -0,0 +1,21 @@ +{statistic variables}
+var
+ SortMode:dword;
+ ReportMask:dword;
+ ReportItems:cardinal;
+ Direction:cardinal;
+ RunReport:cardinal;
+ DoAddExt:cardinal;
+ AutoSort:cardinal;
+ LastSort:dword;
+const
+ StatName :PAnsiChar=nil;
+ ReportName:PAnsiChar=nil;
+ TmplName :PAnsiChar=nil;
+var
+ hPackLog,
+ hMakeReport,
+ hAddToLog,
+ plStatusHook,
+ sic,
+ hMenuReport:THANDLE;
diff --git a/plugins/Watrack/stat/statlog.pas b/plugins/Watrack/stat/statlog.pas new file mode 100644 index 0000000000..50af34508d --- /dev/null +++ b/plugins/Watrack/stat/statlog.pas @@ -0,0 +1,650 @@ +{Statistic}
+unit StatLog;
+{$include compilers.inc}
+interface
+{$Resource stat.res}
+implementation
+
+uses windows,messages,shellapi,commctrl
+ ,wrapper,io,wat_api,common,global,m_api,dbsettings,mirutils;
+
+{$include stat_data.inc}
+{$include stat_vars.inc}
+{$include stat_opt.inc}
+
+type
+ pStatCell = ^tStatCell;
+ tStatCell = record
+ Count :integer;
+ AltCount :integer;
+ LastTime :dword;
+ Length :integer;
+ Artist :PAnsiChar;
+ Title :PAnsiChar;
+ MFile :PAnsiChar;
+ Album :PAnsiChar;
+ next :pStatCell; // only for fill
+ end;
+
+type
+ pCells = ^tCells;
+ tCells = record
+ Count:integer;
+ Cells:array [0..1] of pStatCell
+ end;
+
+const
+ IcoBtnReport:PAnsiChar='WATrack_Report';
+const
+ DelimChar = '|';
+const
+ buflen = 2048;
+
+const
+ Lock:boolean=false;
+
+procedure err(str:PWideChar);
+begin
+ MessageBoxW(0,TranslateW(str),TranslateW('Music Statistic'),MB_OK);
+end;
+
+function OnlyPath(dst,src:PAnsiChar):PAnsiChar;
+var
+ i:integer;
+begin
+ i:=StrLen(src)-1;
+ while (i>0) and (src[i]<>'\') do dec(i);
+ StrCopy(dst,src,i);
+ result:=dst;
+end;
+
+function PackTime(aTime:TSYSTEMTIME):dword;
+begin
+ with aTime do
+ result:=wSecond+
+ (wMinute shl 06)+
+ (wHour shl 12)+
+ (wDay shl 17)+
+ (wMonth shl 22)+
+ (((wYear-2000) and $3F) shl 26);
+end;
+
+procedure UnPackTime(aTime:dword;var MyTime:TSYSTEMTIME);
+begin
+ with MyTime do
+ begin
+ wYear :=(aTime shr 26)+2000;
+ wMonth :=(aTime shr 22) and $0F;
+ wDay :=(aTime shr 17) and $1F;
+ wHour :=(aTime shr 12) and $1F;
+ wMinute:=(aTime shr 6 ) and $3F;
+ wSecond:=aTime and $3F;
+ end;
+end;
+
+function ShowTime(buf:PAnsiChar;aTime:dword):PAnsiChar;
+var
+ MyTime:TSYSTEMTIME;
+begin
+ UnPackTime(aTime,MyTime);
+ with MyTime do
+ begin
+ IntToStr(buf ,wDay ,2);
+ IntToStr(buf+3 ,wMonth ,2);
+ IntToStr(buf+6 ,wYear ,2);
+ IntToStr(buf+9 ,wHour ,2);
+ IntToStr(buf+12,wMinute,2);
+ IntToStr(buf+15,wSecond,2);
+ end;
+ buf[2] :='.'; buf[5] :='.'; buf[8] :=' ';
+ buf[11]:=':'; buf[14]:=':'; buf[17]:=#0;
+ result:=buf;
+end;
+
+function AppendStr(src:PAnsiChar;var dst:PAnsiChar):PAnsiChar; overload;
+begin
+ dst^:=DelimChar; inc(dst);
+ while src^<>#0 do
+ begin
+ dst^:=src^;
+ inc(dst);
+ inc(src);
+ end;
+ result:=dst;
+end;
+
+function AppendStr(src:PWideChar;var dst:PAnsiChar):PAnsiChar; overload;
+var
+ p,lp:PAnsiChar;
+begin
+ dst^:=DelimChar; inc(dst);
+ lp:=WideToUTF8(src,p);
+ while lp^<>#0 do
+ begin
+ dst^:=lp^;
+ inc(dst);
+ inc(lp);
+ end;
+ mFreeMem(p);
+ result:=dst;
+end;
+
+procedure AppendStat(fname:PAnsiChar;si:pSongInfo);
+var
+ f:THANDLE;
+ MyTime:TSYSTEMTIME;
+ buf:array [0..buflen-1] of char;
+ lp:PAnsiChar;
+begin
+ if Lock then
+ exit;
+ if (si^.artist=NIL) and (si^.title=NIL) and
+ (si^.album =NIL) and (si^.mfile=NIL) then
+ exit;
+ f:=Append(fname);
+// if dword(f)=INVALID_HANDLE_VALUE then f:=Rewrite(fname);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then exit;
+ FillChar(buf,SizeOf(buf),0);
+ lp:=@buf;
+ buf[0]:='1'; buf[1]:=DelimChar; inc(lp,2); // Count
+
+ GetLocalTime(MyTime);
+ IntToStr(lp,PackTime(MyTime),9);
+ inc(lp,9);
+ lp^:=DelimChar;
+ inc(lp);
+ IntToStr(lp,si^.total); while lp^<>#0 do inc(lp);
+
+ AppendStr(si^.artist,lp);
+ AppendStr(si^.title ,lp);
+ AppendStr(si^.mfile ,lp);
+ AppendStr(si^.album ,lp);
+
+ lp^:=#$0D; inc(lp); lp^:=#$0A;
+ BlockWrite(f,buf,lp-PAnsiChar(@buf)+1);
+ CloseHandle(f);
+end;
+
+procedure OutputStat(fname:PAnsiChar;aCells:pCells);
+var
+ f:THANDLE;
+ buf:array [0..2047] of char;
+ lp:PAnsiChar;
+ i:integer;
+begin
+ f:=Rewrite(fname);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ for i:=0 to aCells^.Count-1 do
+ begin
+ lp:=@buf;
+ with aCells^.Cells[i]^ do
+ begin
+ IntToStr(buf,Count); while lp^<>#0 do inc(lp);
+ lp^:=DelimChar; inc(lp);
+ IntToStr(lp,LastTime,9); inc(lp,9);
+ lp^:=DelimChar; inc(lp);
+ IntToStr(lp,Length); while lp^<>#0 do inc(lp);
+ AppendStr(Artist,lp);
+ AppendStr(Title ,lp);
+ AppendStr(MFile ,lp);
+ AppendStr(Album ,lp);
+
+ lp^:=#$0D; inc(lp); lp^:=#$0A;
+ BlockWrite(f,buf,lp-PAnsiChar(@buf)+1);
+ end;
+ end;
+ CloseHandle(f);
+end;
+
+function CutStr(var src:PAnsiChar):PAnsiChar;
+begin
+ result:=src;
+ while (src^<>DelimChar) and (src^>=' ') do inc(src);
+ src^:=#0;
+ inc(src);
+end;
+
+procedure ClearStatCells(aCells:pCells);
+begin
+ with aCells^ do
+ while Count>0 do
+ begin
+ dec(Count);
+ mFreeMem(Cells[Count]);
+ end;
+ mFreeMem(aCells);
+end;
+
+function FillCell(src:PAnsiChar):pStatCell;
+var
+ Cell:pStatCell;
+begin
+ mGetMem(Cell,SizeOf(tStatCell));
+ FillChar(Cell^,SizeOf(tStatCell),0);
+ Cell^.Count :=StrToInt(src);
+ while src^<>DelimChar do inc(src); inc(src);
+ Cell^.LastTime:=StrToInt(src);
+ while src^<>DelimChar do inc(src); inc(src);
+ Cell^.Length :=StrToInt(src);
+ while src^<>DelimChar do inc(src); inc(src);
+ Cell^.Artist:=CutStr(src);
+ Cell^.Title :=CutStr(src);
+ Cell^.MFile :=CutStr(src);
+ Cell^.Album :=CutStr(src);
+
+ result:=Cell;
+end;
+
+function Compare(C1,C2:pStatCell; SortType:integer):integer;
+var
+ ls,ls1:array [0..511] of AnsiChar;
+begin
+ case SortType of
+ stArtist: begin
+ result:=lstrcmpia(C1^.Artist,C2^.Artist);
+ if result=0 then
+ result:=lstrcmpia(C1^.Title,C2^.Title);
+ if result=0 then
+ result:=lstrcmpia(C1^.Album,C2^.Album);
+ end;
+ stAlbum: result:=lstrcmpia(C1^.Album,C2^.Album);
+ stPath : result:=lstrcmpia(OnlyPath(ls,C1^.MFile),OnlyPath(ls1,C2^.MFile));
+ stDate : result:=C2^.LastTime-C1^.LastTime;
+ stCount : result:=C2^.Count-C1^.Count;
+ stLength : result:=C2^.Length-C1^.Length;
+ stAltCount: result:=C2^.AltCount-C1.AltCount;
+ else
+ result:=0;
+ end;
+end;
+
+function SwapProc(var Root:pCells;First,Second:integer):integer;
+var
+ p:pStatCell;
+begin
+ p:=Root^.Cells[First];
+ Root^.Cells[First]:=Root^.Cells[Second];
+ Root^.Cells[Second]:=p;
+ result:=0;
+end;
+
+procedure Resort(var Root:pCells;sort:integer;adirection:integer=smDirect);
+
+ function CompareProc(First,Second:integer):integer;
+ begin
+ result:=Compare(Root^.cells[First],Root^.cells[Second],sort);
+ if direction=smReverse then
+ result:=-result;
+ end;
+
+var
+ i,j,gap:longint;
+begin
+ gap:=Root^.Count shr 1;
+ while gap>0 do
+ begin
+ for i:=gap to Root^.Count-1 do
+ begin
+ j:=i-gap;
+ while (j>=0) and (CompareProc(j,UInt(j+gap))>0) do
+ begin
+ SwapProc(Root,j,UInt(j+gap));
+ dec(j,gap);
+ end;
+ end;
+ gap:=gap shr 1;
+ end;
+// now pack doubles
+end;
+
+function BuildTree(fname:PAnsiChar;var buffer:PAnsiChar):pCells;
+var
+ f:THANDLE;
+ i,cnt:integer;
+ FirstCell,CurCell,Cell:pStatCell;
+ lRec:TWin32FindDataA;//WIN32_FIND_DATAA;
+ h:THANDLE;
+ p,p1,p2:PAnsiChar;
+ ls,buf:PAnsiChar;
+ arr:pCells;
+begin
+ result:=nil;
+ buffer:=nil;
+ h:=FindFirstFileA(fname,lRec);
+ if h=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ i:=lRec.nFileSizeLow;
+ FindClose(h);
+ if i<22 then
+ Exit;
+ f:=Reset(fname);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ mGetMem(buffer,i+1);
+ p:=buffer;
+ BlockRead(f,p^,i);
+ CloseHandle(f);
+ p1:=p;
+ p2:=p+i;
+ FirstCell:=nil;
+ mGetMem(buf,buflen);
+ buf^:=#0;
+ cnt:=0;
+ while p<p2 do
+ begin
+ while p^<>#$0D do inc(p);
+ i:=p-p1;
+ p^:=#0;
+ if i>=20 then //min log template + min fname [d:\.e]
+ begin
+ ls:=p1;
+// skip duplicates one-by-one
+ while ls^<>DelimChar do inc(ls); inc(ls); // Count
+ while ls^<>DelimChar do inc(ls); inc(ls); // time
+ while ls^<>DelimChar do inc(ls); inc(ls); // length
+ if StrCmp(buf,ls)<>0 then
+ begin
+ inc(cnt);
+ StrCopy(buf,ls);
+ Cell:=FillCell(p1);
+
+ if FirstCell=nil then
+ begin
+ FirstCell:=Cell;
+ CurCell :=FirstCell;
+ end
+ else
+ begin
+ CurCell^.next:=Cell;
+ CurCell:=Cell;
+ end;
+ end;
+ end;
+ inc(p,2); p1:=p;
+ end;
+ mFreeMem(buf);
+ // Fill array
+ if cnt>0 then
+ begin
+ mGetMem(arr,SizeOf(integer)+cnt*SizeOf(pStatCell));
+ arr^.Count:=cnt;
+ CurCell:=FirstCell;
+ i:=0;
+ while CurCell<>nil do
+ begin
+ arr^.Cells[i]:=CurCell;
+ CurCell:=CurCell.next;
+ inc(i);
+ end;
+ result:=arr;
+ // sort & pack
+ Resort(arr,stArtist);
+
+ i:=1;
+ Cell:=arr^.Cells[0];
+ while i<arr^.Count do
+ begin
+ with arr^.Cells[i]^ do
+ if (lstrcmpia(Cell^.Artist,Artist)=0) and
+ (lstrcmpia(Cell^.Title,Title)=0) and
+ (lstrcmpia(Cell^.Album,Album)=0) then
+ begin
+ if Cell^.LastTime<LastTime then
+ Cell^.LastTime:=LastTime;
+ inc(Cell^.Count,Count);
+ dec(arr^.Count);
+ if i<arr^.Count then
+ move(arr^.Cells[i+1],arr^.Cells[i],SizeOf(pStatCell)*(arr^.Count-i));
+ continue;
+ end
+ else
+ Cell:=arr^.Cells[i];
+ inc(i);
+ end;
+
+ end;
+end;
+
+procedure SortFile(fname:PAnsiChar;mode:integer;adirection:integer);
+var
+ Root:pCells;
+ buf:PAnsiChar;
+ buf1:array [0..511] of AnsiChar;
+begin
+ Lock:=true;
+ ConvertFileName(fname,buf1);
+// CallService(MS_UTILS_PATHTOABSOLUTE,dword(fname),dword(@buf1));
+ Root:=BuildTree(buf1,buf);
+ if Root<>nil then
+ begin
+ if (mode<>stArtist) or (adirection<>smDirect) then
+ Resort(Root,mode,adirection);
+ OutputStat(buf1,Root);
+ ClearStatCells(Root);
+ end;
+ mFreeMem(buf);
+ Lock:=false;
+end;
+
+{$include report.inc}
+
+// --------------- service functions -----------------
+
+function ThAddToLog(param:pdword):dword; stdcall;
+begin
+ result:=0;
+end;
+
+procedure ThPackLog(param:pdword); cdecl;
+begin
+ SortFile(StatName,SortMode,Direction);
+end;
+
+function ThMakeReport(param:pdword):dword; stdcall;
+begin
+ result:=0;
+end;
+
+function AddToLog(wParam:WPARAM;lParam:LPARAM):integer;cdecl;
+var
+ fname:PAnsiChar;
+ log:array [0..511] of AnsiChar;
+begin
+ result:=0;
+ if (StatName=nil) or (StatName[0]=#0) then
+ exit;
+ if wParam=0 then
+ fname:=StatName
+ else
+ fname:=PAnsiChar(wParam);
+ ConvertFileName(fname,log);
+// CallService(MS_UTILS_PATHTOABSOLUTE,dword(fname),dword(@log));
+ AppendStat(log,pSongInfo(lParam));
+end;
+
+function PackLog(wParam:WPARAM;lParam:LPARAM):integer;cdecl;
+begin
+ result:=0;
+ CloseHandle(mir_forkthread(@ThPackLog,nil));
+end;
+
+function MakeReport(wParam:WPARAM;lParam:LPARAM):integer;cdecl;
+var
+ report,log,template:array [0..511] of AnsiChar;
+ l,r:PAnsiChar;
+begin
+ result:=0;
+ if CallService(MS_WAT_PLUGINSTATUS,2,0)=WAT_RES_DISABLED then
+ exit;
+ if (wParam<>0) and (wParam<>MenuReportPos) then
+ l:=PAnsiChar(wParam)
+ else
+ l:=TmplName;
+ if PAnsiChar(lParam)<>nil then r:=PAnsiChar(lParam) else r:=ReportName;
+ if (r=nil) or (r^=#0) then
+ err('Report file name not defined')
+ else if (StatName=nil) or (StatName^=#0) then
+ err('Log file name not defined')
+ else
+ begin
+ ConvertFileName(r,report);
+ ConvertFileName(l,template);
+ ConvertFileName(StatName,log);
+// CallService(MS_UTILS_PATHTOABSOLUTE,dword(r),dword(@report));
+// CallService(MS_UTILS_PATHTOABSOLUTE,dword(l),dword(@template));
+// CallService(MS_UTILS_PATHTOABSOLUTE,dword(StatName),dword(@log));
+ if DoAddExt=BST_CHECKED then
+ ChangeExt(report,'htm');
+ if StatOut(report,log,template) then
+ begin
+ if RunReport=BST_CHECKED then
+ begin
+ ShellExecuteA(0,nil{'open'},report,nil,nil,SW_SHOWNORMAL);
+ end;
+ result:=1;
+ end
+ else
+ err('Oops, something wrong!');
+ end;
+end;
+
+{$include stat_dlg.inc}
+
+function NewPlStatus(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ flag:integer;
+ mi:tClistMenuItem;
+ CurTime:dword;
+begin
+ result:=0;
+ case wParam of
+ WAT_EVENT_NEWTRACK: begin
+ if (StatName<>nil) and (StatName[0]<>#0) then
+ begin
+ AppendStat(StatName,pSongInfo(lParam));
+ if AutoSort>0 then
+ begin
+ CurTime:=GetCurrentTime;
+ if (CurTime-LastSort)>=(86400*AutoSort) then
+ begin
+ SortFile(StatName,SortMode,Direction); //PackLog(0,0);
+ LastSort:=CurTime;
+ DBWriteDWord(0,PluginShort,opt_LastSort,LastSort);
+ end;
+ end;
+ end;
+ end;
+ WAT_EVENT_PLUGINSTATUS: begin
+ case lParam of
+ 0: flag:=0;
+ 2: flag:=CMIF_GRAYED;
+ else // like 1
+ exit
+ end;
+ FillChar(mi,sizeof(mi),0);
+ mi.cbSize:=sizeof(mi);
+ mi.flags :=CMIM_FLAGS+flag;
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuReport,tlparam(@mi));
+ end;
+ end;
+end;
+
+function IconChanged(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ mi:TCListMenuItem;
+begin
+ result:=0;
+ FillChar(mi,SizeOf(mi),0);
+ mi.cbSize:=sizeof(mi);
+ mi.flags :=CMIM_ICON;
+ mi.hIcon :=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnReport));
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuReport,tlparam(@mi));
+end;
+
+// ------------ base interface functions -------------
+
+function InitProc(aGetStatus:boolean=false):integer;
+var
+ mi:TCListMenuItem;
+ sid:TSKINICONDESC;
+begin
+ if aGetStatus then
+ begin
+ if GetModStatus=0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ end
+ else
+ SetModStatus(1);
+ result:=1;
+
+ hPackLog :=CreateServiceFunction(MS_WAT_PACKLOG ,@PackLog);
+ hMakeReport:=CreateServiceFunction(MS_WAT_MAKEREPORT,@MakeReport);
+ hAddToLog :=CreateServiceFunction(MS_WAT_ADDTOLOG ,@AddToLog);
+ loadstat;
+
+ FillChar(sid,SizeOf(TSKINICONDESC),0);
+ sid.cbSize:=SizeOf(TSKINICONDESC);
+ sid.cx:=16;
+ sid.cy:=16;
+ sid.szSection.a:='WATrack';
+ sid.hDefaultIcon :=LoadImage(hInstance,MAKEINTRESOURCE(BTN_REPORT),IMAGE_ICON,16,16,0);
+ sid.pszName :=IcoBtnReport;
+ sid.szDescription.a:='Create Report';
+ Skin_AddIcon(@sid);
+ DestroyIcon(sid.hDefaultIcon);
+ sic:=HookEvent(ME_SKIN2_ICONSCHANGED,@IconChanged);
+
+ FillChar(mi, sizeof(mi), 0);
+ mi.cbSize :=sizeof(mi);
+ mi.flags :=0;
+ mi.szPopupName.a:=PluginShort;
+ mi.hIcon :=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnReport));
+ mi.szName.a :='Create WATrack report';
+ mi.pszService :=MS_WAT_MAKEREPORT;
+ mi.popupPosition:=MenuReportPos;
+ hMenuReport :=Menu_AddMainMenuItem(@mi);
+ plStatusHook:=HookEvent(ME_WAT_NEWSTATUS,@NewPlStatus);
+end;
+
+procedure DeInitProc(aSetDisable:boolean);
+begin
+ if aSetDisable then
+ SetModStatus(0);
+
+ CallService(MS_CLIST_REMOVEMAINMENUITEM,hMenuReport,0);
+ UnhookEvent(plStatusHook);
+ UnhookEvent(sic);
+ DestroyServiceFunction(hPackLog);
+ DestroyServiceFunction(hMakeReport);
+ DestroyServiceFunction(hAddToLog);
+ FreeStat;
+end;
+
+function AddOptionsPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+begin
+ tmpl:='STATS';
+ proc:=@DlgProcOptions;
+ name:='Statistics';
+ result:=0;
+end;
+
+var
+ Stat:twModule;
+
+procedure Init;
+begin
+ Stat.Next :=ModuleLink;
+ Stat.Init :=@InitProc;
+ Stat.DeInit :=@DeInitProc;
+ Stat.AddOption :=@AddOptionsPage;
+ Stat.ModuleName:='Statistic';
+ ModuleLink :=@Stat;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Watrack/stat/wat_report.ico b/plugins/Watrack/stat/wat_report.ico Binary files differnew file mode 100644 index 0000000000..8e9c02fb93 --- /dev/null +++ b/plugins/Watrack/stat/wat_report.ico |