summaryrefslogtreecommitdiff
path: root/plugins/Watrack/myshows
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Watrack/myshows')
-rw-r--r--plugins/Watrack/myshows/i_const.inc14
-rw-r--r--plugins/Watrack/myshows/i_cookies.inc91
-rw-r--r--plugins/Watrack/myshows/i_myshows_api.inc247
-rw-r--r--plugins/Watrack/myshows/i_myshows_dlg.inc111
-rw-r--r--plugins/Watrack/myshows/i_myshows_opt.inc47
-rw-r--r--plugins/Watrack/myshows/myshows.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/myshows/myshows.pas333
-rw-r--r--plugins/Watrack/myshows/myshows.rc41
-rw-r--r--plugins/Watrack/myshows/myshows.resbin0 -> 1728 bytes
9 files changed, 884 insertions, 0 deletions
diff --git a/plugins/Watrack/myshows/i_const.inc b/plugins/Watrack/myshows/i_const.inc
new file mode 100644
index 0000000000..47c4b52618
--- /dev/null
+++ b/plugins/Watrack/myshows/i_const.inc
@@ -0,0 +1,14 @@
+const
+ IDC_LOGIN = 1025;
+ IDC_PASS = 1026;
+ IDC_TRIES = 1027;
+ IDC_TIME = 1028;
+ IDC_SCROBPOS = 1029;
+
+ IDC_INFO_SERIES = 1039;
+ IDC_DATA_PIC = 1040;
+ IDC_DATA_SERIES = 1041;
+ IDC_DATA_EPISODE = 1042;
+ IDC_DATA_TAGS = 1044;
+ IDC_DATA_INFO = 1045;
+ IDC_KINOPOISK = 1046;
diff --git a/plugins/Watrack/myshows/i_cookies.inc b/plugins/Watrack/myshows/i_cookies.inc
new file mode 100644
index 0000000000..1258490199
--- /dev/null
+++ b/plugins/Watrack/myshows/i_cookies.inc
@@ -0,0 +1,91 @@
+{}
+const
+ cookies:pAnsiChar=nil;
+
+function ExtractCookies(resp:PNETLIBHTTPREQUEST):integer;
+var
+ cnt,len:integer;
+ p,pc:pAnsiChar;
+begin
+ result:=0;
+
+ mFreeMem(cookies);
+ mGetMem(cookies,1024);
+
+ pc:=cookies;
+ for cnt:=0 to resp^.headersCount-1 do
+ begin
+ with resp^.headers[cnt] do
+ if StrCmp(szName,'Set-Cookie')=0 then
+ begin
+ len:=0;
+ p:=szValue;
+ while (p^<>#0) and (p^<>';') do
+ begin
+ inc(p);
+ inc(len);
+ end;
+ if pc<>cookies then
+ begin
+ pc^:=';'; inc(pc);
+ pc^:=' '; inc(pc);
+ end;
+ pc:=StrCopyE(pc,szValue,len);
+ inc(result);
+ end;
+ end;
+end;
+
+function SendRequestCookies(url:PAnsiChar;useCookies:boolean):pAnsiChar;
+var
+ nlu:TNETLIBUSER;
+ req :TNETLIBHTTPREQUEST;
+ resp:PNETLIBHTTPREQUEST;
+ hTmpNetLib:THANDLE;
+ nlh:array [0..10] of TNETLIBHTTPHEADER;
+begin
+ result:=nil;
+
+ FillChar(req,SizeOf(req),0);
+ req.cbSize :=NETLIBHTTPREQUEST_V1_SIZE;//SizeOf(req);
+ req.requestType:=REQUEST_GET;
+ req.szUrl :=url;
+ req.flags :=NLHRF_NODUMP or NLHRF_HTTP11;
+
+ if useCookies and (cookies<>nil) then
+ begin
+ nlh[0].szName :='Cookie';
+ nlh[0].szValue:=cookies;
+
+ req.headers :=@nlh;
+ req.headersCount:=1;
+ end;
+
+ FillChar(nlu,SizeOf(nlu),0);
+ nlu.cbSize :=SizeOf(nlu);
+ nlu.flags :=NUF_HTTPCONNS or NUF_NOHTTPSOPTION or NUF_OUTGOING or NUF_NOOPTIONS;
+ nlu.szSettingsModule:='dummy';
+ hTmpNetLib:=CallService(MS_NETLIB_REGISTERUSER,0,lparam(@nlu));
+
+ resp:=pointer(CallService(MS_NETLIB_HTTPTRANSACTION,hTmpNetLib,lparam(@req)));
+
+ if resp<>nil then
+ begin
+ if resp^.resultCode=200 then
+ begin
+ if resp.pData<>nil then
+ StrDup(result,resp.pData,resp.dataLength)
+ else
+ result:=PAnsiChar(200);
+ if not useCookies then
+ ExtractCookies(resp);
+ end
+ else
+ begin
+ result:=pAnsiChar(int_ptr(resp^.resultCode and $0FFF));
+ end;
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,lparam(resp));
+ end;
+
+ CallService(MS_NETLIB_CLOSEHANDLE,hTmpNetLib,0);
+end;
diff --git a/plugins/Watrack/myshows/i_myshows_api.inc b/plugins/Watrack/myshows/i_myshows_api.inc
new file mode 100644
index 0000000000..572cc3ee31
--- /dev/null
+++ b/plugins/Watrack/myshows/i_myshows_api.inc
@@ -0,0 +1,247 @@
+{}
+//type tDigest = array [0..15] of byte;
+(*
+const
+ client_id = 'wat';//'wat'; 'tst'
+ client_ver = '1.0';
+ api_key = '51f5d25159da31b0814609c3a12900e2';
+*)
+{$include i_cookies.inc}
+
+const API_URL = 'http://api.myshows.ru/';
+
+const
+ defreq = API_URL+'profile/login?login=<login>&password=<password>';
+
+procedure ShowError(code:integer);
+var
+ buf:array [0..511] of WideChar;
+ ppc:pWideChar;
+begin
+ case code of
+ 401: begin // Требуется авторизация
+ ppc:='Authorization required';
+ end;
+ 403: begin // Имя пользователя или пароль не подошли
+ ppc:='User name of password wrong';
+ end;
+ 404: begin // Не найдено, неправильные параметры
+ ppc:='Not found / wrong parameters';
+ end;
+ 500: begin // параметр запроса отсутствует
+ ppc:='Wrong query parameters';
+ end;
+ else
+ ppc:='something wrong!';
+ end;
+ StrCopyW(StrCopyEW(buf,'MyShows: '),TranslateW(ppc));
+
+ if ServiceExists(MS_POPUP_SHOWMESSAGEW)<>0 then
+ CallService(MS_POPUP_SHOWMESSAGEW,TWPARAM(@buf),SM_WARNING)
+ else
+ MessageBoxW(0,@buf,'ERROR',MB_ICONERROR)
+end;
+
+function GetMD5Str(digest:TMD5Hash; buf:pAnsiChar):PAnsiChar;
+begin
+ buf[00]:=HexDigitChrLo[digest[00] shr 4]; buf[01]:=HexDigitChrLo[digest[00] and $0F];
+ buf[02]:=HexDigitChrLo[digest[01] shr 4]; buf[03]:=HexDigitChrLo[digest[01] and $0F];
+ buf[04]:=HexDigitChrLo[digest[02] shr 4]; buf[05]:=HexDigitChrLo[digest[02] and $0F];
+ buf[06]:=HexDigitChrLo[digest[03] shr 4]; buf[07]:=HexDigitChrLo[digest[03] and $0F];
+ buf[08]:=HexDigitChrLo[digest[04] shr 4]; buf[09]:=HexDigitChrLo[digest[04] and $0F];
+ buf[10]:=HexDigitChrLo[digest[05] shr 4]; buf[11]:=HexDigitChrLo[digest[05] and $0F];
+ buf[12]:=HexDigitChrLo[digest[06] shr 4]; buf[13]:=HexDigitChrLo[digest[06] and $0F];
+ buf[14]:=HexDigitChrLo[digest[07] shr 4]; buf[15]:=HexDigitChrLo[digest[07] and $0F];
+ buf[16]:=HexDigitChrLo[digest[08] shr 4]; buf[17]:=HexDigitChrLo[digest[08] and $0F];
+ buf[18]:=HexDigitChrLo[digest[09] shr 4]; buf[19]:=HexDigitChrLo[digest[09] and $0F];
+ buf[20]:=HexDigitChrLo[digest[10] shr 4]; buf[21]:=HexDigitChrLo[digest[10] and $0F];
+ buf[22]:=HexDigitChrLo[digest[11] shr 4]; buf[23]:=HexDigitChrLo[digest[11] and $0F];
+ buf[24]:=HexDigitChrLo[digest[12] shr 4]; buf[25]:=HexDigitChrLo[digest[12] and $0F];
+ buf[26]:=HexDigitChrLo[digest[13] shr 4]; buf[27]:=HexDigitChrLo[digest[13] and $0F];
+ buf[28]:=HexDigitChrLo[digest[14] shr 4]; buf[29]:=HexDigitChrLo[digest[14] and $0F];
+ buf[30]:=HexDigitChrLo[digest[15] shr 4]; buf[31]:=HexDigitChrLo[digest[15] and $0F];
+ buf[32]:=#0;
+ result:=@buf;
+end;
+
+function GetMD5(const data;datalen:integer;var digest:TMD5Hash):TMD5Hash;
+begin
+ FillChar(digest,16,0);
+
+ mir_md5_hash(pmir_md5_byte_t(data),datalen,digest);
+
+ result:=digest;
+end;
+
+function Handshake(login, password:PAnsiChar):boolean;
+var
+ buf:array [0..32] of AnsiChar;
+ digest:TMD5Hash;
+ request:array [0..511] of AnsiChar;
+ res:pAnsiChar;
+ stat:mir_md5_state_t;
+begin
+ result:=false;
+ GetMD5Str(GetMD5(password,StrLen(password),digest),buf);
+ mir_md5_init(@stat);
+ mir_md5_append(@stat,@buf,32);
+ mir_md5_finish(@stat,digest);
+ StrCopy(request,defreq);
+ StrReplace(request,'<login>' ,login);
+ StrReplace(request,'<password>',buf);
+
+ res:=SendRequestCookies(request,false);
+// res:=SendRequest(request,REQUEST_GET);
+ if res<>nil then
+ begin
+ if uint_ptr(res)<$0FFF then
+ begin
+ ShowError(int_ptr(res));
+ end
+ else
+ begin
+ result:=true;
+ mFreeMem(res);
+ end;
+ end;
+end;
+
+function Encode(dst,src:pAnsiChar):PAnsiChar;
+begin
+ while src^<>#0 do
+ begin
+ if not (src^ in [' ','%','+','&','?',#128..#255]) then
+ dst^:=src^
+ else
+ begin
+ dst^:='%'; inc(dst);
+ dst^:=HexDigitChr[ord(src^) shr 4]; inc(dst);
+ dst^:=HexDigitChr[ord(src^) and $0F];
+ end;
+ inc(src);
+ inc(dst);
+ end;
+ dst^:=#0;
+ result:=dst;
+end;
+
+function SendMSRequest(request:pAnsiChar;doShowError:boolean):boolean;
+var
+ res:pAnsiChar;
+begin
+ result:=true;
+ res:=SendRequestCookies(request,true);
+ if (uint_ptr(res)<>200) and (uint_ptr(res)<$0FFF) then
+ begin
+//!! if int_ptr(res)=401 then
+ begin
+ Handshake(msh_login,msh_password);
+
+ res:=SendRequestCookies(request,true);
+ end;
+ if (uint_ptr(res)<$0FFF) then
+ if (uint_ptr(res)<>200) and doShowError then
+ begin
+ ShowError(int_ptr(res));
+ result:=false;
+ end;
+ end;
+end;
+
+function Scrobble(show:boolean):boolean;
+var
+ si:pSongInfoA;
+ buf:array [0..511] of AnsiChar;
+// bufw:array [0..511] of WideChar;
+ res,pc:PAnsiChar;
+ {img,}shId,epId:pAnsiChar;
+// imgw:pWideChar;
+ json:TJSONSERVICEINTERFACE;
+ jn,jroot:PJSONNODE;
+begin
+ result:=false;
+
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UTF8,0));
+ Encode(buf,si.mfile);
+ pc:=Extract(buf,true);
+
+ // Episode search by filename
+ StrCopy(StrCopyE(buf,API_URL+'shows/search/file/?q='),pc);
+ mFreeMem(pc);
+ res:=SendRequest(buf,REQUEST_GET);
+ if uint_ptr(res)>$0FFF then
+ begin
+ CallService(MS_JSON_GETINTERFACE,wparam(@json),0);
+
+ jroot:=json.parse(res);
+
+ jn:=json.get(jroot,'show');
+ shId:=json.as_string(json.get(jn,'id'));
+
+ jn:=json.get(jn,'episodes');
+ epId:=json.name(json.at(jn,0));
+{
+kinopoiskId
+image
+ruTitle
+episodes:{:{id:
+}
+ end
+ else
+ begin
+ if show and (res<>nil) then
+ ShowError(int_ptr(res));
+ exit;
+ end;
+
+ // Show mark as "watching"
+ StrCopy(StrCopyE(StrCopyE(buf,API_URL+'profile/shows/'),shId),'/watching');
+ if SendMSRequest(buf,show) then
+ begin
+ // Episode check
+ StrCopy(StrCopyE(buf,API_URL+'profile/episodes/check/'),epId);
+ // StrCopy(request,API_URL+'profile/shows/');
+ if SendMSRequest(buf,show) then
+ begin
+{
+ if si.cover=nil then
+ begin
+ jn:=json.get(jroot,'show');
+ img:=json.as_string(json.get(jn,'image'));
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UNICODE,0));
+ FastAnsiToWide(img,pSongInfoW(si)^.cover);
+ json.free(img);
+ end;
+}
+ //!! add option to show it??
+ if ServiceExists(MS_POPUP_SHOWMESSAGE)<>0 then
+ begin
+ json.free(shId);
+ json.free(epId);
+
+ jn:=json.get(jroot,'show');
+ shId:=json.as_string(json.get(jn,'title'));
+
+ jn:=json.get(jn,'episodes');
+ epId:=json.as_string(json.get(jn,'title'));
+
+ StrCopy(
+ StrCopyE(
+ StrCopyE(
+ StrCopyE(
+ StrCopyE(buf,'Show "'),
+ shId),
+ '"'#13#10'episode "'),
+ epId),
+ '" checked');
+ CallService(MS_POPUP_SHOWMESSAGE,TWPARAM(@buf),SM_NOTIFY);
+ end;
+ result:=true;
+ end;
+ end;
+ json.free(shId);
+ json.free(epId);
+
+ json.delete_(jroot);
+end;
+
diff --git a/plugins/Watrack/myshows/i_myshows_dlg.inc b/plugins/Watrack/myshows/i_myshows_dlg.inc
new file mode 100644
index 0000000000..13740d5a34
--- /dev/null
+++ b/plugins/Watrack/myshows/i_myshows_dlg.inc
@@ -0,0 +1,111 @@
+{}
+
+const
+ kinopoisk_info = 'http://www.kinopoisk.ru/level/1/film/';
+
+procedure ClearInfo(dlg:HWND);
+begin
+ SetDlgItemTextW(dlg,IDC_DATA_SERIES ,'');
+ SetDlgItemTextW(dlg,IDC_DATA_EPISODE,'');
+ SetDlgItemTextW(dlg,IDC_DATA_TAGS ,'');
+ SetDlgItemTextW(dlg,IDC_DATA_TAGS ,'');
+ SetDlgItemTextW(dlg,IDC_DATA_INFO ,'');
+end;
+
+function DlgProcOptions(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ inited:bool=false;
+var
+ tmp:longbool;
+// bmp,wnd:HWND;
+// buf:array [0..255] of AnsiChar;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ inited:=false;
+ TranslateDialogDefault(Dialog);
+
+ SetDlgItemTextA(Dialog,IDC_LOGIN,msh_login);
+ SetDlgItemTextA(Dialog,IDC_PASS ,msh_password);
+ SetDlgItemInt (Dialog,IDC_TRIES,msh_tries,false);
+// SetDlgItemInt (Dialog,IDC_TIME ,msh_timeout,false);
+// ClearInfo(Dialog);
+// EnableWindow(GetDlgItem(Dialog,IDC_KINOPOISK),false);
+
+ SendDlgItemMessage(Dialog,IDC_SCROBPOS,TBM_SETRANGE,0,MAKELONG(0,100));
+ SendDlgItemMessage(Dialog,IDC_SCROBPOS,TBM_SETPOS,1,msh_scrobpos);
+ inited:=true;
+ end;
+
+ WM_HSCROLL: begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ WM_COMMAND: begin
+ if inited then
+ begin
+ (*
+ case Loword(wParam) of
+ IDC_KINOPOISK: begin
+ StrCopy(StrCopyE(buf,kinopoisk_info),MSData.kinopoisk_id);
+ CallService(MS_UTILS_OPENURL,TWPARAM(True),TLPARAM(@buf));
+ result:=1;
+ exit;
+ end;
+ end;
+ *)
+ case wParam shr 16 of
+ BN_CLICKED: begin
+ (*
+ case LoWord(wParam) of
+ IDC_INFO_SERIES: begin
+ ClearInfo(Dialog);
+ ClearData;
+
+ SetDlgItemTextW(Dialog,IDC_DATA_SERIES ,MSData.series);
+ SetDlgItemTextW(Dialog,IDC_DATA_EPISODE,MSData.episode);
+ // SetDlgItemTextW(Dialog,IDC_DATA_TAGS ,data.genre);
+ SetDlgItemTextW(Dialog,IDC_DATA_INFO ,MSData.info);
+
+ bmp:=LoadImageURL(MSData.image,80);
+ if bmp<>0 then
+ DeleteObject(SendDlgItemMessage(Dialog,IDC_DATA_PIC,STM_SETIMAGE,IMAGE_BITMAP,bmp));
+
+ EnableWindow(GetDligItem(Dialog,IDC_KINOPOISK),true);
+ end;
+ *)
+ end;
+
+ EN_CHANGE: begin
+ case loword(wParam) of
+ IDC_LOGIN,IDC_PASS,IDC_TRIES{,IDC_TIME}:
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ case integer(PNMHdr(lParam)^.code) of
+ PSN_APPLY: begin
+ msh_scrobpos:=SendDlgItemMessage(Dialog,IDC_SCROBPOS,TBM_GETPOS,0,0);
+ msh_tries :=GetDlgItemInt(Dialog,IDC_TRIES,tmp,false);
+ mFreeMem(msh_login ); msh_login :=GetDlgText(Dialog,IDC_LOGIN,true);
+ mFreeMem(msh_password); msh_password:=GetDlgText(Dialog,IDC_PASS ,true);
+ {
+ mFreeMem(session_id);
+ mFreeMem(np_url);
+ mFreeMem(sub_url);
+ }
+ // msh_timeout:=GetDlgItemInt(Dialog,IDC_TIME ,tmp,false);
+
+ SaveOpt;
+ end;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/myshows/i_myshows_opt.inc b/plugins/Watrack/myshows/i_myshows_opt.inc
new file mode 100644
index 0000000000..f3287aba05
--- /dev/null
+++ b/plugins/Watrack/myshows/i_myshows_opt.inc
@@ -0,0 +1,47 @@
+{}
+const
+ optLogin :pAnsiChar='myshows/login';
+ optPassword:pAnsiChar='myshows/password';
+ optTries :pAnsiChar='myshows/tries';
+// optTimeout :PAnsiChar='myshows/timeout';
+ optScrobPos:pAnsiChar='myshows/scrobpos';
+ optScrobble:pAnsiChar='myshows/scrobble';
+
+procedure SaveOpt;
+var
+ tmppass:array [0..255] of AnsiChar;
+begin
+ if msh_password<>nil then
+ begin
+ StrCopy(tmppass,msh_password);
+ CallService(MS_DB_CRYPT_ENCODESTRING,StrLen(tmppass)+1,LPARAM(@tmppass));
+ end;
+ DBWriteString(0,PluginShort,optPassword,tmppass);
+ DBWriteString(0,PluginShort,optLogin ,msh_login);
+ DBWriteByte (0,PluginShort,optTries ,msh_tries);
+ DBWriteByte (0,PluginShort,optScrobPos,msh_scrobpos);
+// DBWriteWord (0,PluginShort,optTries ,msh_timeout);
+ DBWriteByte (0,PluginShort,optScrobble,msh_on and 1);
+end;
+
+procedure LoadOpt;
+begin
+// msh_timeout :=DBReadWord(0,PluginShort,optTimeout ,0);
+ msh_scrobpos:=DBReadByte(0,PluginShort,optScrobPos,30);
+ msh_tries :=DBReadByte(0,PluginShort,optTries ,3);
+ msh_on :=DBReadByte(0,PluginShort,optScrobble,0);
+ mFreeMem(msh_login ); msh_login :=DBReadString(0,PluginShort,optLogin);
+ mFreeMem(msh_password); msh_password:=DBReadString(0,PluginShort,optPassword);
+ if msh_password<>nil then
+ CallService(MS_DB_CRYPT_DECODESTRING,StrLen(msh_password)+1,LPARAM(msh_password));
+ if (msh_login=nil) or (msh_password=nil) then
+ CallService(MS_POPUP_SHOWMESSAGEW,
+ WPARAM(TranslateW('Don''t forget to enter Login and Password to use MyShows service')),
+ SM_WARNING);
+end;
+
+procedure FreeOpt;
+begin
+ mFreeMem(msh_login);
+ mFreeMem(msh_password);
+end;
diff --git a/plugins/Watrack/myshows/myshows.ico b/plugins/Watrack/myshows/myshows.ico
new file mode 100644
index 0000000000..ab34e43a20
--- /dev/null
+++ b/plugins/Watrack/myshows/myshows.ico
Binary files differ
diff --git a/plugins/Watrack/myshows/myshows.pas b/plugins/Watrack/myshows/myshows.pas
new file mode 100644
index 0000000000..ce07ee0d68
--- /dev/null
+++ b/plugins/Watrack/myshows/myshows.pas
@@ -0,0 +1,333 @@
+unit myshows;
+{$include compilers.inc}
+interface
+{$Resource myshows.res}
+implementation
+
+uses windows, messages, commctrl,
+ common,
+ m_api,dbsettings,wrapper, mirutils,
+ wat_api,global;
+
+const
+ DefTimerValue = 10*60*1000; // 10 minutes
+const
+ opt_ModStatus:PAnsiChar = 'module/myshows';
+const
+ IcoMyShows:pAnsiChar = 'WATrack_myshows';
+type
+ tMyShowsData = record
+ series :PAnsiChar;
+ series_id :PAnsiChar;
+ kinopoisk_id:PAnsiChar;
+ episode :PAnsiChar;
+ episode_id :PAnsiChar;
+ info :PAnsiChar;
+ image :PAnsiChar;
+ end;
+var
+ msh_tries,
+// msh_timeout,
+ msh_scrobpos:integer;
+ sic:THANDLE;
+// slastinf:THANDLE;
+ slast:THANDLE;
+ MSData:tMyShowsData;
+const
+ msh_on :integer=0;
+ hMenuMyShows:HMENU = 0;
+ msh_login :pAnsiChar=nil;
+ msh_password:pAnsiChar=nil;
+ session_id :pAnsiChar=nil;
+ np_url :pAnsiChar=nil;
+ sub_url :pAnsiChar=nil;
+
+procedure ClearData;
+begin
+ mFreeMem(MSData.series);
+ mFreeMem(MSData.series_id);
+ mFreeMem(MSData.kinopoisk_id);
+ mFreeMem(MSData.episode);
+ mFreeMem(MSData.episode_id);
+ mFreeMem(MSData.info);
+ mFreeMem(MSData.image);
+ FillChar(MSData,SizeOf(MSData),0);
+end;
+
+function GetModStatus:integer;
+begin
+ result:=DBReadByte(0,PluginShort,opt_ModStatus,1);
+end;
+
+procedure SetModStatus(stat:integer);
+begin
+ DBWriteByte(0,PluginShort,opt_ModStatus,stat);
+end;
+
+{$i i_const.inc}
+{$i i_myshows_opt.inc}
+{$i i_myshows_api.inc}
+
+procedure ThScrobble(param:LPARAM); cdecl;
+var
+ count:integer;
+begin
+ count:=msh_tries;
+ repeat
+ dec(count);
+ if Scrobble(count<=0) then break;
+ until count<=0;
+end;
+
+const
+ hTimer:THANDLE=0;
+
+procedure TimerProc(wnd:HWND;uMsg:uint;idEvent:uint_ptr;dwTime:dword); stdcall;
+begin
+ if hTimer<>0 then
+ begin
+ KillTimer(0,hTimer);
+ hTimer:=0;
+ end;
+
+ if (msh_login <>nil) and (msh_login^ <>#0) and
+ (msh_password<>nil) and (msh_password^<>#0) then
+ CloseHandle(mir_forkthread(@ThScrobble,nil));
+end;
+
+function NewPlStatus(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ flag:integer;
+ mi:TCListMenuItem;
+ timervalue:integer;
+begin
+ result:=0;
+ case wParam of
+ WAT_EVENT_NEWTRACK: begin
+ if hTimer<>0 then
+ KillTimer(0,hTimer);
+ // need to use half of movie len if presents
+ if msh_on=0 then
+ begin
+ if pSongInfo(lParam).width>0 then // for video only
+ begin
+ if ServiceExists(MS_JSON_GETINTERFACE)<>0 then
+ begin
+ timervalue:=integer(pSongInfo(lParam).total)*10*msh_scrobpos; // 1000(msec) div 100(%)
+ if timervalue=0 then
+ timervalue:=DefTimerValue;
+ hTimer:=SetTimer(0,0,timervalue,@TimerProc);
+ end;
+ end;
+ end;
+ end;
+
+ WAT_EVENT_PLUGINSTATUS: begin
+ case lParam of
+ dsEnabled: begin
+ msh_on:=msh_on and not 2;
+ flag:=0;
+ end;
+ dsPermanent: begin
+ msh_on:=msh_on or 2;
+ if hTimer<>0 then
+ begin
+ KillTimer(0,hTimer);
+ hTimer:=0;
+ end;
+ flag:=CMIF_GRAYED;
+ end;
+ else // like 1
+ exit
+ end;
+ FillChar(mi,sizeof(mi),0);
+ mi.cbSize:=sizeof(mi);
+ mi.flags :=CMIM_FLAGS+flag;
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuMyShows,tlParam(@mi));
+ end;
+
+ WAT_EVENT_PLAYERSTATUS: begin
+ case Integer(loword(lParam)) of
+ WAT_PLS_NOMUSIC,WAT_PLS_NOTFOUND: begin
+ if hTimer<>0 then
+ begin
+ KillTimer(0,hTimer);
+ hTimer:=0;
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+{$i i_myshows_dlg.inc}
+
+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(IcoMyShows));
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuMyShows,tlParam(@mi));
+end;
+
+(* kinopoisk link, cover, series?
+function SrvMyShowsInfo(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+//var
+// data:tMyShowsInfo;
+begin
+ result:=0;
+{
+ case wParam of
+ 0: result:=GetArtistInfo(data,lParam);
+ 1: result:=GetAlbumInfo (data,lParam);
+ 2: result:=GetTrackInfo (data,lParam);
+ else
+ result:=0;
+ end;
+}
+end;
+*)
+function SrvMyShows(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ mi:TCListMenuItem;
+begin
+ FillChar(mi,sizeof(mi),0);
+ mi.cbSize:=sizeof(mi);
+ mi.flags :=CMIM_NAME;
+ if odd(msh_on) then
+ begin
+ mi.szName.a:='Disable scrobbling';
+ msh_on:=msh_on and not 1;
+ end
+ else
+ begin
+ mi.szName.a:='Enable scrobbling';
+ msh_on:=msh_on or 1;
+ if hTimer<>0 then
+ begin
+ KillTimer(0,hTimer);
+ hTimer:=0;
+ end;
+ end;
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuMyShows,tlParam(@mi));
+ result:=ord(not odd(msh_on));
+end;
+
+procedure CreateMenus;
+var
+ mi:TCListMenuItem;
+ sid:TSKINICONDESC;
+begin
+ FillChar(sid,SizeOf(TSKINICONDESC),0);
+ sid.cbSize:=SizeOf(TSKINICONDESC);
+ sid.cx:=16;
+ sid.cy:=16;
+ sid.szSection.a:='WATrack';
+
+ sid.hDefaultIcon :=LoadImage(hInstance,'IDI_MYSHOWS',IMAGE_ICON,16,16,0);
+ sid.pszName :=IcoMyShows;
+ sid.szDescription.a:='MyShows';
+ Skin_AddIcon(@sid);
+ DestroyIcon(sid.hDefaultIcon);
+
+ FillChar(mi, sizeof(mi), 0);
+ mi.cbSize :=sizeof(mi);
+ mi.szPopupName.a:=PluginShort;
+
+ mi.hIcon :=CallService(MS_SKIN2_GETICON,0,tlParam(IcoMyShows));
+ mi.szName.a :='Disable scrobbling';
+ mi.pszService :=MS_WAT_MYSHOWS;
+ mi.popupPosition:=500050000;
+ hMenuMyShows:=Menu_AddMainMenuItem(@mi);
+end;
+
+// ------------ base interface functions -------------
+
+function AddOptionsPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+begin
+ tmpl:='MYSHOWS';
+ proc:=@DlgProcOptions;
+ name:='MyShows';
+ result:=0;
+end;
+
+var
+ plStatusHook:THANDLE;
+
+function InitProc(aGetStatus:boolean=false):integer;
+begin
+// slastinf:=CreateServiceFunction(MS_WAT_MYSHOWSINFO,@SrvMyShowsInfo);
+ if aGetStatus then
+ begin
+ if GetModStatus=0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ end
+ else
+ begin
+ SetModStatus(1);
+ msh_on:=msh_on and not 4;
+ end;
+ result:=1;
+
+ LoadOpt;
+
+ slast:=CreateServiceFunction(MS_WAT_MYSHOWS,@SrvMyShows);
+ if hMenuMyShows=0 then
+ CreateMenus;
+ sic:=HookEvent(ME_SKIN2_ICONSCHANGED,@IconChanged);
+ if (msh_on and 4)=0 then
+ plStatusHook:=HookEvent(ME_WAT_NEWSTATUS,@NewPlStatus);
+end;
+
+procedure DeInitProc(aSetDisable:boolean);
+begin
+ if aSetDisable then
+ SetModStatus(0)
+ else
+;// DestroyServiceFunction(slastinf);
+
+ DestroyServiceFunction(slast);
+ UnhookEvent(plStatusHook);
+ UnhookEvent(sic);
+
+ if hTimer<>0 then
+ begin
+ KillTimer(0,hTimer);
+ hTimer:=0;
+ end;
+
+ FreeOpt;
+
+ mFreeMem(session_id);
+ mFreeMem(np_url);
+ mFreeMem(sub_url);
+
+ msh_on:=msh_on or 4;
+
+ mFreeMem(cookies); //!!
+end;
+
+var
+ mmyshows:twModule;
+
+procedure Init;
+begin
+ mmyshows.Next :=ModuleLink;
+ mmyshows.Init :=@InitProc;
+ mmyshows.DeInit :=@DeInitProc;
+ mmyshows.AddOption :=@AddOptionsPage;
+ mmyshows.ModuleName:='MyShows.ru';
+ ModuleLink :=@mmyshows;
+
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Watrack/myshows/myshows.rc b/plugins/Watrack/myshows/myshows.rc
new file mode 100644
index 0000000000..adc05a23b7
--- /dev/null
+++ b/plugins/Watrack/myshows/myshows.rc
@@ -0,0 +1,41 @@
+#include "i_const.inc"
+
+LANGUAGE 0,0
+
+MYSHOWS DIALOGEX 0, 0, 304, 226, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ LTEXT "Login" , -1, 108, 2, 70, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_LOGIN , 4, 4, 100, 12,
+ LTEXT "Password" , -1, 108, 18, 70, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_PASS , 4, 20, 100, 12, ES_PASSWORD
+ LTEXT "Attempts" , -1, 40, 34, 64, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_TRIES , 4, 36, 32, 12, ES_RIGHT | ES_NUMBER
+// LTEXT "Timeout, ms", -1, 40, 50, 64, 16, SS_CENTERIMAGE
+// EDITTEXT IDC_TIME , 4, 52, 32, 12, ES_RIGHT | ES_NUMBER
+
+ CONTROL "",IDC_SCROBPOS,"msctls_trackbar32", TBS_BOTTOM|TBS_NOTICKS|$100,120,45,94,11
+ CTEXT "Scrobble at",-1,120,35,94,11, SS_CENTERIMAGE
+/*
+ PUSHBUTTON "Get Series Info", IDC_INFO_SERIES, 4, 206, 72, 16
+
+ CONTROL "", IDC_DATA_PIC, "STATIC", SS_BITMAP | WS_BORDER, 220, 2, 80, 80
+
+ RTEXT "Show", -1 , 0, 86, 76, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_DATA_SERIES , 80, 87, 220, 14, ES_READONLY | ES_AUTOHSCROLL
+ RTEXT "Episode",-1 , 0, 102, 76, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_DATA_EPISODE , 80, 103, 220, 14, ES_READONLY | ES_AUTOHSCROLL
+ RTEXT "Genres", -1 , 0, 118, 76, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_DATA_TAGS , 80, 119, 220, 14, ES_READONLY | ES_AUTOHSCROLL
+ RTEXT "Info" , -1 , 0, 134, 76, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_DATA_INFO , 80, 135, 220, 75,
+ ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL
+
+ CONTROL "Kinopoisk info page", IDC_KINOPOISK, "Hyperlink",
+ WS_CHILD | WS_TABSTOP | WS_DISABLED | 0x1, 80, 212, 220, 10
+*/
+}
+
+IDI_MYSHOWS ICON "myshows.ico"
diff --git a/plugins/Watrack/myshows/myshows.res b/plugins/Watrack/myshows/myshows.res
new file mode 100644
index 0000000000..1b888d6762
--- /dev/null
+++ b/plugins/Watrack/myshows/myshows.res
Binary files differ