summaryrefslogtreecommitdiff
path: root/plugins/Watrack
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-10-08 18:43:29 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-10-08 18:43:29 +0000
commit864081102a5f252415f41950b3039a896b4ae9c5 (patch)
treec6b764651e9dd1f8f53b98eab05f16ba4a492a79 /plugins/Watrack
parentdb5149b48346c417e18add5702a9dfe7f6e28dd0 (diff)
Awkwars's plugins - welcome to our trunk
git-svn-id: http://svn.miranda-ng.org/main/trunk@1822 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Watrack')
-rw-r--r--plugins/Watrack/HlpDlg.pas83
-rw-r--r--plugins/Watrack/docs/const.php157
-rw-r--r--plugins/Watrack/docs/m_music.h386
-rw-r--r--plugins/Watrack/docs/m_music.inc404
-rw-r--r--plugins/Watrack/docs/sampledll.dpr139
-rw-r--r--plugins/Watrack/docs/wat.php28
-rw-r--r--plugins/Watrack/docs/watrack_history.txt519
-rw-r--r--plugins/Watrack/docs/watrack_readme.txt110
-rw-r--r--plugins/Watrack/formats/fmt_aac.pas93
-rw-r--r--plugins/Watrack/formats/fmt_ape.pas137
-rw-r--r--plugins/Watrack/formats/fmt_avi.pas295
-rw-r--r--plugins/Watrack/formats/fmt_dummy.pas46
-rw-r--r--plugins/Watrack/formats/fmt_flv.pas334
-rw-r--r--plugins/Watrack/formats/fmt_m4a.pas378
-rw-r--r--plugins/Watrack/formats/fmt_mkv.pas235
-rw-r--r--plugins/Watrack/formats/fmt_mp3.pas460
-rw-r--r--plugins/Watrack/formats/fmt_mpc.pas90
-rw-r--r--plugins/Watrack/formats/fmt_ofr.pas74
-rw-r--r--plugins/Watrack/formats/fmt_ogg.pas522
-rw-r--r--plugins/Watrack/formats/fmt_real.pas335
-rw-r--r--plugins/Watrack/formats/fmt_tta.pas65
-rw-r--r--plugins/Watrack/formats/fmt_wav.pas146
-rw-r--r--plugins/Watrack/formats/fmt_wma.pas438
-rw-r--r--plugins/Watrack/formats/tag_apev2.inc124
-rw-r--r--plugins/Watrack/formats/tag_id3v1.inc175
-rw-r--r--plugins/Watrack/formats/tag_id3v2.inc545
-rw-r--r--plugins/Watrack/formats/tags.pas21
-rw-r--r--plugins/Watrack/global.pas86
-rw-r--r--plugins/Watrack/i_cover.inc90
-rw-r--r--plugins/Watrack/i_gui.inc114
-rw-r--r--plugins/Watrack/i_opt_0.inc91
-rw-r--r--plugins/Watrack/i_opt_1.inc256
-rw-r--r--plugins/Watrack/i_opt_dlg.inc57
-rw-r--r--plugins/Watrack/i_options.inc171
-rw-r--r--plugins/Watrack/i_timer.inc26
-rw-r--r--plugins/Watrack/i_vars.inc37
-rw-r--r--plugins/Watrack/icons/GO/GoAsm.Exebin0 -> 124416 bytes
-rw-r--r--plugins/Watrack/icons/GO/GoLink.exebin0 -> 48640 bytes
-rw-r--r--plugins/Watrack/icons/GO/GoRC.exebin0 -> 54784 bytes
-rw-r--r--plugins/Watrack/icons/GO/icons.bat8
-rw-r--r--plugins/Watrack/icons/GO/icons.rc58
-rw-r--r--plugins/Watrack/icons/GO/waticons.h35
-rw-r--r--plugins/Watrack/icons/GO/watrack_buttons.asm5
-rw-r--r--plugins/Watrack/icons/MASM/icons.bat8
-rw-r--r--plugins/Watrack/icons/MASM/icons.rc58
-rw-r--r--plugins/Watrack/icons/MASM/iconspl.rc83
-rw-r--r--plugins/Watrack/icons/MASM/poasm.exebin0 -> 653488 bytes
-rw-r--r--plugins/Watrack/icons/MASM/polink.exebin0 -> 164528 bytes
-rw-r--r--plugins/Watrack/icons/MASM/porc.dllbin0 -> 146096 bytes
-rw-r--r--plugins/Watrack/icons/MASM/porc.exebin0 -> 30208 bytes
-rw-r--r--plugins/Watrack/icons/MASM/waticons.h35
-rw-r--r--plugins/Watrack/icons/MASM/watrack.asm5
-rw-r--r--plugins/Watrack/icons/TASM/RLINK32.DLLbin0 -> 59904 bytes
-rw-r--r--plugins/Watrack/icons/TASM/TASM32.EXEbin0 -> 188416 bytes
-rw-r--r--plugins/Watrack/icons/TASM/TLINK32.EXEbin0 -> 208896 bytes
-rw-r--r--plugins/Watrack/icons/TASM/brcc32.exebin0 -> 169008 bytes
-rw-r--r--plugins/Watrack/icons/TASM/icons.bat9
-rw-r--r--plugins/Watrack/icons/TASM/icons.rc58
-rw-r--r--plugins/Watrack/icons/TASM/iconspl.rc61
-rw-r--r--plugins/Watrack/icons/TASM/rw32core.dllbin0 -> 812576 bytes
-rw-r--r--plugins/Watrack/icons/TASM/waticons.h35
-rw-r--r--plugins/Watrack/icons/TASM/watrack.asm8
-rw-r--r--plugins/Watrack/icons/iconsets/players/1by1.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/AIMP.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Ashampoo Media Player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/BeholdTV.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Billy.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Core Media Player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Crystal Player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Cyberlink PowerDVD.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Evil Player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/GOMPlayer.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Helium Music Manager.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/J.River Media Center.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/JetAudio.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/KMPlayer.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/LastFM.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/MediaMonkey.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/MoreAmp.icobin0 -> 2862 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/MusikCube.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/QCDPlayer.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Quicktime Player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/RadLight.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Real Player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Spider Player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Ultra player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/VUPlayer.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/WMP 9.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/WinDVD.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/XMPlay.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/Zoom Player.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/alshow.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/alsong.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/apollo.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/audio.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/bsplayer.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/cms.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/flv.icobin0 -> 1406 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/foobar2000.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/itunes.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/la.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/mcone.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/mcx.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/mmatch.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/mpc.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/mplayer.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/pluton.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/saps.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/songbird.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/vlc.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/vp3.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/wany.icobin0 -> 1406 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/wifi.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/players/winamp.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/disable.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/enable.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/next.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/next_hovered.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/next_pressed.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/pause.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/pause_hovered.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/pause_pressed.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/play.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/play_hovered.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/play_pressed.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/previous.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/previous_hovered.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/previous_pressed.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/slider.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/slider_hovered.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/slider_pressed.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/stop.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/stop_hovered.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/stop_pressed.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/volume_down.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/volume_down_hovered.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/volume_down_pressed.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/volume_up.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/volume_up_hovered.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true+256-solid/volume_up_pressed.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/next.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/next_hovered.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/next_pressed.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/pause.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/pause_hovered.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/pause_pressed.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/play.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/play_hovered.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/play_pressed.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/previous.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/previous_hovered.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/previous_pressed.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/slider.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/stop.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/stop_hovered.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/stop_pressed.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/ver.resbin0 -> 744 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/volume_down.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/volume_down_hovered.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/volume_down_pressed.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/volume_up.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/volume_up_hovered.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/iconsets/true-solid-faith/volume_up_pressed.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/icons/make-buttons.bat4
-rw-r--r--plugins/Watrack/icons/make-players.bat2
-rw-r--r--plugins/Watrack/icons/make.bat16
-rw-r--r--plugins/Watrack/icons/waticons.inc35
-rw-r--r--plugins/Watrack/kolframe/frm.rc84
-rw-r--r--plugins/Watrack/kolframe/frm.resbin0 -> 3032 bytes
-rw-r--r--plugins/Watrack/kolframe/frm_data.inc37
-rw-r--r--plugins/Watrack/kolframe/frm_designer.inc164
-rw-r--r--plugins/Watrack/kolframe/frm_dlg1.inc283
-rw-r--r--plugins/Watrack/kolframe/frm_dlg2.inc172
-rw-r--r--plugins/Watrack/kolframe/frm_frame.inc497
-rw-r--r--plugins/Watrack/kolframe/frm_icogroup.inc115
-rw-r--r--plugins/Watrack/kolframe/frm_rc.inc56
-rw-r--r--plugins/Watrack/kolframe/frm_text.inc90
-rw-r--r--plugins/Watrack/kolframe/frm_trackbar.inc229
-rw-r--r--plugins/Watrack/kolframe/frm_vars.inc80
-rw-r--r--plugins/Watrack/kolframe/i_bitmap.inc290
-rw-r--r--plugins/Watrack/kolframe/kolframe.pas327
-rw-r--r--plugins/Watrack/lastfm/i_const.inc17
-rw-r--r--plugins/Watrack/lastfm/i_last_api.inc599
-rw-r--r--plugins/Watrack/lastfm/i_last_dlg.inc120
-rw-r--r--plugins/Watrack/lastfm/i_last_opt.inc44
-rw-r--r--plugins/Watrack/lastfm/lastfm.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/lastfm/lastfm.pas300
-rw-r--r--plugins/Watrack/lastfm/lastfm.rc38
-rw-r--r--plugins/Watrack/lastfm/lastfm.resbin0 -> 3720 bytes
-rw-r--r--plugins/Watrack/lst_formats.inc16
-rw-r--r--plugins/Watrack/lst_players.inc17
-rw-r--r--plugins/Watrack/m_music.inc419
-rw-r--r--plugins/Watrack/macros.pas93
-rw-r--r--plugins/Watrack/make.bat26
-rw-r--r--plugins/Watrack/myrtf.pas219
-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
-rw-r--r--plugins/Watrack/player.ini283
-rw-r--r--plugins/Watrack/players/mradio.icobin0 -> 1150 bytes
-rw-r--r--plugins/Watrack/players/mradio.rc3
-rw-r--r--plugins/Watrack/players/mradio.resbin0 -> 1264 bytes
-rw-r--r--plugins/Watrack/players/pl_1by1.pas84
-rw-r--r--plugins/Watrack/players/pl_aimp.pas376
-rw-r--r--plugins/Watrack/players/pl_apollo.pas263
-rw-r--r--plugins/Watrack/players/pl_behold.pas175
-rw-r--r--plugins/Watrack/players/pl_bs.pas252
-rw-r--r--plugins/Watrack/players/pl_cowon.pas392
-rw-r--r--plugins/Watrack/players/pl_foobar.pas534
-rw-r--r--plugins/Watrack/players/pl_itunes.pas392
-rw-r--r--plugins/Watrack/players/pl_la.pas141
-rw-r--r--plugins/Watrack/players/pl_lastfm.pas129
-rw-r--r--plugins/Watrack/players/pl_mmonkey.pas181
-rw-r--r--plugins/Watrack/players/pl_mpc.pas117
-rw-r--r--plugins/Watrack/players/pl_mradio.pas345
-rw-r--r--plugins/Watrack/players/pl_vlc.pas380
-rw-r--r--plugins/Watrack/players/pl_winamp.pas170
-rw-r--r--plugins/Watrack/players/pl_wmp.pas128
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/Makefile12
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/res/watrack_mpd.rc112
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/commonheaders.h43
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/constants.h4
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/globals.h11
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/init.c112
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/m_music.h355
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/main.c433
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/main.h24
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/options.c91
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/resource.h32
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/utilities.c126
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/src/utilities.h6
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/watrack_mpd.vcxproj299
-rw-r--r--plugins/Watrack/plugins/watrack_mpd/watrack_mpd.vcxproj.filters56
-rw-r--r--plugins/Watrack/popup/pop_dlg.inc179
-rw-r--r--plugins/Watrack/popup/pop_opt.inc81
-rw-r--r--plugins/Watrack/popup/pop_rc.inc34
-rw-r--r--plugins/Watrack/popup/pop_vars.inc27
-rw-r--r--plugins/Watrack/popup/popup.rc55
-rw-r--r--plugins/Watrack/popup/popup.resbin0 -> 3352 bytes
-rw-r--r--plugins/Watrack/popup/popups.pas542
-rw-r--r--plugins/Watrack/popup/wat_info.icobin0 -> 1406 bytes
-rw-r--r--plugins/Watrack/proto/i_proto_dlg.inc144
-rw-r--r--plugins/Watrack/proto/i_proto_opt.inc35
-rw-r--r--plugins/Watrack/proto/i_proto_rc.inc17
-rw-r--r--plugins/Watrack/proto/proto.pas564
-rw-r--r--plugins/Watrack/proto/proto.rc36
-rw-r--r--plugins/Watrack/proto/proto.resbin0 -> 2624 bytes
-rw-r--r--plugins/Watrack/proto/wat_context.icobin0 -> 1406 bytes
-rw-r--r--plugins/Watrack/res/i_const.inc27
-rw-r--r--plugins/Watrack/res/wat_disable.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/res/wat_enable.icobin0 -> 2550 bytes
-rw-r--r--plugins/Watrack/res/watrack.rc104
-rw-r--r--plugins/Watrack/res/watrack.resbin0 -> 8520 bytes
-rw-r--r--plugins/Watrack/srv_format.pas394
-rw-r--r--plugins/Watrack/srv_player.pas1220
-rw-r--r--plugins/Watrack/stat/default.tmpl89
-rw-r--r--plugins/Watrack/stat/report.inc315
-rw-r--r--plugins/Watrack/stat/stat.rc50
-rw-r--r--plugins/Watrack/stat/stat.resbin0 -> 3320 bytes
-rw-r--r--plugins/Watrack/stat/stat_data.inc16
-rw-r--r--plugins/Watrack/stat/stat_dlg.inc223
-rw-r--r--plugins/Watrack/stat/stat_opt.inc62
-rw-r--r--plugins/Watrack/stat/stat_rc.inc29
-rw-r--r--plugins/Watrack/stat/stat_vars.inc21
-rw-r--r--plugins/Watrack/stat/statlog.pas650
-rw-r--r--plugins/Watrack/stat/wat_report.icobin0 -> 1406 bytes
-rw-r--r--plugins/Watrack/status/i_hotkey.inc62
-rw-r--r--plugins/Watrack/status/i_opt_11.inc459
-rw-r--r--plugins/Watrack/status/i_opt_12.inc108
-rw-r--r--plugins/Watrack/status/i_opt_3.inc106
-rw-r--r--plugins/Watrack/status/i_opt_status.inc49
-rw-r--r--plugins/Watrack/status/i_opt_tmpl.inc244
-rw-r--r--plugins/Watrack/status/i_st_rc.inc45
-rw-r--r--plugins/Watrack/status/i_st_vars.inc26
-rw-r--r--plugins/Watrack/status/i_status.inc223
-rw-r--r--plugins/Watrack/status/status.pas142
-rw-r--r--plugins/Watrack/status/status.rc88
-rw-r--r--plugins/Watrack/status/status.resbin0 -> 3092 bytes
-rw-r--r--plugins/Watrack/status/tmpl.pas304
-rw-r--r--plugins/Watrack/templates/i_expkey.inc34
-rw-r--r--plugins/Watrack/templates/i_macro.inc149
-rw-r--r--plugins/Watrack/templates/i_opt_it.inc50
-rw-r--r--plugins/Watrack/templates/i_text.inc135
-rw-r--r--plugins/Watrack/templates/i_tmpl_dlg.inc117
-rw-r--r--plugins/Watrack/templates/i_tmpl_rc.inc21
-rw-r--r--plugins/Watrack/templates/i_variables.inc185
-rw-r--r--plugins/Watrack/templates/templates.pas113
-rw-r--r--plugins/Watrack/templates/templates.rc51
-rw-r--r--plugins/Watrack/templates/templates.resbin0 -> 1648 bytes
-rw-r--r--plugins/Watrack/wat_api.pas183
-rw-r--r--plugins/Watrack/waticons.inc35
-rw-r--r--plugins/Watrack/waticons.pas202
-rw-r--r--plugins/Watrack/watrack.dpr675
-rw-r--r--plugins/Watrack/winampapi.pas277
300 files changed, 28064 insertions, 0 deletions
diff --git a/plugins/Watrack/HlpDlg.pas b/plugins/Watrack/HlpDlg.pas
new file mode 100644
index 0000000000..c420345bd4
--- /dev/null
+++ b/plugins/Watrack/HlpDlg.pas
@@ -0,0 +1,83 @@
+{help dialogs}
+unit HlpDlg;
+
+interface
+
+uses windows;
+
+const
+ sFormatHelp:PWideChar = 'Text format codes'#13#10'{b}text{/b}'#9'bold'#13#10+
+ '{i}text{/i}'#9'italic'#13#10'{u}text{/u}'#9'undeline'#13#10+
+ '{cf##}text{/cf}'#9'text color'#13#10'{bg##}text{/bg}'#9+
+ 'background color'#13#10'text - user text'#13#10+
+ '## - color number (1-16)'#13#10'Color 0 is background color'#13#10+
+ 'Color 17 is default text color';
+
+function ShowColorHelpDlg(parent:HWND):integer;
+
+implementation
+
+uses messages,m_api;
+
+{$include res\i_const.inc}
+
+const
+ colors:array [0..15] of dword = (
+ $00FFFFFF,$00000000,$007F0000,$00009300,
+ $000000FF,$0000007F,$009C009C,$00007FFC,
+ $0000FFFF,$0000FC00,$00939300,$00FFFF00,
+ $00FC0000,$00FF00FF,$007F7F7F,$00D2D2D2
+ );
+
+const
+ COLORDLG = 'COLOR';
+
+function ColorHelpDlg(Dialog:HWnd;hMessage,wParam,lParam:DWord):integer; stdcall;
+var
+ ps:tPaintStruct;
+ br:hBrush;
+ dc:hDC;
+ rc:tRect;
+ i,j:integer;
+begin
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ end;
+ WM_COMMAND:
+ if (wParam shr 16)=BN_CLICKED then
+ case loword(wParam) of
+ IDOK, IDCANCEL: DestroyWindow(Dialog);
+ end;
+ WM_PAINT: begin
+ dc:=BeginPaint(Dialog,ps);
+ SetBkColor(dc,GetSysColor(COLOR_BTNFACE));
+ for i:=0 to 1 do
+ begin
+ for j:=0 to 7 do
+ begin
+ with rc do
+ begin
+ left :=32+i*66;
+ top :=10+j*18;
+ right :=56+i*66;
+ bottom:=24+j*18;
+ end;
+ br:=CreateSolidBrush(colors[i*8+j]);
+ Rectangle(dc,rc.left-1,rc.top-1,rc.right+1,rc.bottom+1);
+ FillRect(dc,rc,br);
+ DeleteObject(br);
+ end;
+ end;
+ EndPaint(Dialog,ps);
+ end;
+ end;
+ result:=0;
+end;
+
+function ShowColorHelpDlg(parent:HWND):integer;
+begin
+ result:=CreateDialogW(hInstance,COLORDLG,parent,@ColorHelpDlg);
+end;
+
+end. \ No newline at end of file
diff --git a/plugins/Watrack/docs/const.php b/plugins/Watrack/docs/const.php
new file mode 100644
index 0000000000..f34156280e
--- /dev/null
+++ b/plugins/Watrack/docs/const.php
@@ -0,0 +1,157 @@
+<?php
+
+// SongInfo offsets
+
+define("wato_artist" ,0);
+define("wato_title" ,wato_artist +4);
+define("wato_album" ,wato_title +4);
+define("wato_genre" ,wato_album +4);
+define("wato_comment" ,wato_genre +4);
+define("wato_year" ,wato_comment +4);
+define("wato_mfile" ,wato_year +4);
+define("wato_kbps" ,wato_mfile +4);
+define("wato_khz" ,wato_kbps +4);
+define("wato_channels",wato_khz +4);
+define("wato_track" ,wato_channels+4);
+define("wato_total" ,wato_track +4);
+define("wato_time" ,wato_total +4);
+define("wato_wndtext" ,wato_time +4);
+define("wato_player" ,wato_wndtext +4);
+define("wato_plyver" ,wato_player +4);
+define("wato_icon" ,wato_plyver +4);
+define("wato_fsize" ,wato_icon +4);
+define("wato_vbr" ,wato_fsize +4);
+define("wato_status" ,wato_vbr +4);
+define("wato_plwnd" ,wato_status +4);
+define("wato_codec" ,wato_plwnd +4);
+define("wato_width" ,wato_codec +4);
+define("wato_height" ,wato_width +4);
+define("wato_fps" ,wato_height +4);
+define("wato_date" ,wato_fps +4);
+define("wato_txtver" ,wato_date +4);
+define("wato_lyric" ,wato_txtver +4);
+define("wato_cover" ,wato_lyric +4);
+define("wato_volume" ,wato_cover +4);
+define("wato_url" ,wato_volume +4);
+
+// player control commands
+
+define("WAT_CTRL_PREV" ,1);
+define("WAT_CTRL_PLAY" ,2);
+define("WAT_CTRL_PAUSE",3);
+define("WAT_CTRL_STOP" ,4);
+define("WAT_CTRL_NEXT" ,5);
+define("WAT_CTRL_VOLDN",6);
+define("WAT_CTRL_VOLUP",7);
+define("WAT_CTRL_SEEK" ,8);
+
+// hook service actions
+
+define("WAT_ACT_REGISTER" ,1);
+define("WAT_ACT_UNREGISTER",2);
+define("WAT_ACT_DISABLE" ,3);
+define("WAT_ACT_ENABLE" ,4);
+define("WAT_ACT_GETSTATUS" ,5); // not found/enabled/disabled
+define("WAT_ACT_SETACTIVE" ,6);
+define("WAT_ACT_REPLACE" ,0x10000); // can be combined with WAT_REGISTERFORMAT
+
+// result codes
+
+define("WAT_RES_UNKNOWN" ,-2);
+define("WAT_RES_NOTFOUND",-1);
+define("WAT_RES_ERROR" ,WAT_RES_NOTFOUND);
+define("WAT_RES_OK" ,0);
+define("WAT_RES_DISABLED",1);
+define("WAT_RES_ENABLED" ,WAT_RES_OK);
+define("WAT_RES_NEWFILE" ,3);
+
+// hook service options
+
+define("WAT_OPT_DISABLED" ,0x00000001); // registered but disabled
+define("WAT_OPT_ONLYONE" ,0x00000002); // can't be overwriten
+define("WAT_OPT_PLAYERINFO" ,0x00000004); // song info from player
+define("WAT_OPT_WINAMPAPI" ,0x00000008); // Winamp API support
+define("WAT_OPT_CHECKTIME" ,0x00000010); // check file time for changes
+define("WAT_OPT_VIDEO" ,0x00000020); // only for format registering used
+define("WAT_OPT_LAST" ,0x00000040); // (internal)
+define("WAT_OPT_FIRST" ,0x00000080); // (internal)
+define("WAT_OPT_TEMPLATE" ,0x00000100); // (internal)
+define("WAT_OPT_IMPLANTANT" ,0x00000200); // use process implantation
+define("WAT_OPT_HASURL" ,0x00000400); // (player registration) URL field present
+define("WAT_OPT_CHANGES" ,0x00000800); // obtain only chaged values
+ // (volume, status, window text, elapsed time)
+
+define("WAT_OPT_APPCOMMAND" ,0x00001000); // Special (multimedia) key support
+define("WAT_OPT_CHECKALL" ,0x00002000); // Check all players
+define("WAT_OPT_KEEPOLD" ,0x00004000); // Keep Old opened file
+define("WAT_OPT_MULTITHREAD",0x00008000); // Use multithread scan
+define("WAT_OPT_SINGLEINST" ,0x00010000); // Single player instance
+// services
+
+define("MS_WAT_GETMUSICINFO" ,"WATrack/GetMusicInfo");
+define("MS_WAT_GETFILEINFO" ,"WATrack/GetFileInfo");
+define("MS_WAT_SHOWMUSICINFO","WATrack/ShowMusicInfo");
+define("MS_WAT_MAKEREPORT" ,"WATrack/MakeReport");
+define("MS_WAT_PACKLOG" ,"WATrack/PackLog");
+define("MS_WAT_ADDTOLOG" ,"WATrack/AddToLog");
+define("MS_WAT_PLUGINSTATUS" ,"WATrack/PluginStatus");
+define("MS_WAT_PRESSBUTTON" ,"WATrack/PressButton");
+define("MS_WAT_REPLACETEXT" ,"WATrack/ReplaceText");
+
+// events
+
+define("ME_WAT_MODULELOADED" ,"WATrack/ModuleLoaded");
+define("ME_WAT_NEWSTATUS" ,"WATrack/NewStatus");
+
+// hook services
+
+define("MS_WAT_FORMAT" ,"WATrack/Format");
+define("MS_WAT_WINAMPINFO" ,"WATrack/WinampInfo");
+define("MS_WAT_WINAMPCOMMAND","WATrack/WinampCommand");
+define("MS_WAT_PLAYER" ,"WATrack/Player");
+
+// GetMuscInfo flags
+define("WAT_INF_UNICODE",0);
+define("WAT_INF_ANSI" ,1);
+define("WAT_INF_UTF8" ,2);
+define("WAT_INF_CHANGES",0x100);
+
+// player status
+
+define("WAT_PLS_NORMAL" ,WAT_RES_OK);
+define("WAT_PLS_NOMUSIC" ,WAT_RES_DISABLED);
+define("WAT_PLS_NOTFOUND",WAT_RES_NOTFOUND);
+
+// media status
+
+define("WAT_MES_STOPPED",0);
+define("WAT_MES_PLAYING",1);
+define("WAT_MES_PAUSED" ,2);
+define("WAT_MES_UNKNOWN",-1);
+
+// event types for History
+
+define("EVENTTYPE_WAT_REQUEST",9601);
+define("EVENTTYPE_WAT_ANSWER" ,9602);
+define("EVENTTYPE_WAT_ERROR" ,9603);
+define("EVENTTYPE_WAT_MESSAGE",9604);
+
+// Status events
+define("WAT_EVENT_PLAYERSTATUS",1);
+define("WAT_EVENT_NEWTRACK" ,2);
+define("WAT_EVENT_PLUGINSTATUS",3);
+define("WAT_EVENT_NEWPLAYER" ,4);
+define("WAT_EVENT_NEWTEMPLATE" ,5);
+
+define("TM_MESSAGE" ,0); // privat message
+define("TM_CHANNEL" ,1); // chat
+define("TM_STAT_TITLE",2); // xstatus title
+define("TM_STAT_TEXT" ,3); // [x]status text
+define("TM_POPTITLE" ,4); // popup title
+define("TM_POPTEXT" ,5); // popup text
+define("TM_EXPORT" ,6); // other app
+define("TM_FRAMEINFO" ,7); // frame
+
+define("TM_SETTEXT" ,0x100); // only for service
+define("TM_GETTEXT" ,0); // only for service
+?>
diff --git a/plugins/Watrack/docs/m_music.h b/plugins/Watrack/docs/m_music.h
new file mode 100644
index 0000000000..0246fabe34
--- /dev/null
+++ b/plugins/Watrack/docs/m_music.h
@@ -0,0 +1,386 @@
+#ifndef M_MUSIC
+#define M_MUSIC
+
+#define MIID_WATRACK {0xfc6c81f4, 0x837e, 0x4430, {0x96, 0x01, 0xa0, 0xaa, 0x43, 0x17, 0x7a, 0xe3}}
+
+typedef struct tSongInfoA {
+ CHAR* artist;
+ CHAR* title;
+ CHAR* album;
+ CHAR* genre;
+ CHAR* comment;
+ CHAR* year;
+ CHAR* mfile; // media file
+ DWORD kbps;
+ DWORD khz;
+ DWORD channels;
+ DWORD track;
+ DWORD total; // music length
+ DWORD time; // elapsed time
+ CHAR* wndtext; // window title
+ CHAR* player; // player name
+ DWORD plyver; // player version
+ HANDLE icon; // player icon
+ DWORD fsize; // media file size
+ DWORD vbr;
+ int status; // WAT_MES_* const
+ HWND plwnd; // player window
+ // video part
+ DWORD codec;
+ DWORD width;
+ DWORD height;
+ DWORD fps;
+ __int64 date;
+ CHAR* txtver;
+ CHAR* lyric;
+ CHAR* cover;
+ DWORD volume;
+ CHAR* url; // player homepage
+} SONGINFOA, *LPSONGINFOA;
+
+typedef struct tSongInfo {
+ WCHAR* artist;
+ WCHAR* title;
+ WCHAR* album;
+ WCHAR* genre;
+ WCHAR* comment;
+ WCHAR* year;
+ WCHAR* mfile; // media file
+ DWORD kbps;
+ DWORD khz;
+ DWORD channels;
+ DWORD track;
+ DWORD total; // music length
+ DWORD time; // elapsed time
+ WCHAR* wndtext; // window title
+ WCHAR* player; // player name
+ DWORD* plyver; // player version
+ HANDLE icon; // player icon
+ DWORD fsize; // media file size
+ DWORD vbr;
+ int status; // WAT_MES_* const
+ HWND plwnd; // player window
+ // video part
+ DWORD codec;
+ DWORD width;
+ DWORD height;
+ DWORD fps;
+ __int64 date;
+ WCHAR* txtver;
+ WCHAR* lyric;
+ WCHAR* cover; // cover path
+ DWORD volume;
+ WCHAR* url; // player homepage
+} SONGINFO, *LPSONGINFO;
+
+#if defined(_UNICODE)
+ #define WAT_INF_TCHAR WAT_INF_UNICODE
+ #define SongInfoT tSongInfo
+#else
+ #define WAT_INF_TCHAR WAT_INF_ANSI
+ #define SongInfoT tSongInfoA
+#endif
+
+ // result codes
+#define WAT_RES_UNKNOWN -2
+#define WAT_RES_NOTFOUND -1
+#define WAT_RES_ERROR WAT_RES_NOTFOUND
+#define WAT_RES_OK 0
+#define WAT_RES_ENABLED WAT_RES_OK
+#define WAT_RES_DISABLED 1
+ // internal
+#define WAT_RES_NEWFILE 3
+#define WAT_RES_NEWPLAYER 4
+
+// result for MS_WAT_GETMUSICINFO service
+#define WAT_PLS_NORMAL WAT_RES_OK
+#define WAT_PLS_NOMUSIC WAT_RES_DISABLED
+#define WAT_PLS_NOTFOUND WAT_RES_NOTFOUND
+
+#define WAT_INF_UNICODE 0
+#define WAT_INF_ANSI 1
+#define WAT_INF_UTF8 2
+#define WAT_INF_CHANGES 0x100
+
+/*
+ wParam : WAT_INF_* constant
+ lParam : pointer to LPSONGINGO (Unicode) or LPSONGINFOA (ANSI/UTF8)
+ Affects: Fill structure by currently played music info
+ returns: WAT_PLS_* constant
+ note: pointer will be point to global SONGINFO structure of plugin
+ warning: Non-Unicode data filled only by request
+ if lParam=0 only internal SongInfo structure will be filled
+ Example:
+ LPSONGINFO p;
+ PluginLink->CallService(MS_WAT_GETMUSICINFO,0,(DWORD)&p);
+*/
+#define MS_WAT_GETMUSICINFO "WATrack/GetMusicInfo"
+
+/*
+ wParam:0
+ lParam : pointer to pSongInfo (Unicode)
+ Affects: Fill structure by info from file named in SongInfo.mfile
+ returns: 0, if success
+ note: fields, which values can't be obtained, leaves old values.
+ you must free given strings by miranda mmi.free
+*/
+#define MS_WAT_GETFILEINFO "WATrack/GetFileInfo"
+
+/*
+ wParam: encoding (WAT_INF_* consts, 0 = WAT_INF_UNICODE)
+ lParam: codepage (0 = ANSI)
+ Returns Global unicode SongInfo pointer or tranlated to Ansi/UTF8 structure
+*/
+#define MS_WAT_RETURNGLOBAL "WATrack/GetMainStructure"
+
+//!! DON'T CHANGE THESE VALUES!
+#define WAT_CTRL_FIRST 1
+
+#define WAT_CTRL_PREV 1
+#define WAT_CTRL_PLAY 2
+#define WAT_CTRL_PAUSE 3
+#define WAT_CTRL_STOP 4
+#define WAT_CTRL_NEXT 5
+#define WAT_CTRL_VOLDN 6
+#define WAT_CTRL_VOLUP 7
+#define WAT_CTRL_SEEK 8 // lParam is new position (sec)
+
+#define WAT_CTRL_LAST 8
+
+/*
+ wParam: button code (WAT_CTRL_* const)
+ lParam: 0, or value (see WAT_CTRL_* const comments)
+ Affects: emulate player button pressing
+ returns: 0 if unsuccesful
+*/
+#define MS_WAT_PRESSBUTTON "WATrack/PressButton"
+
+/*
+ Get user's Music Info
+*/
+#define MS_WAT_GETCONTACTINFO "WATrack/GetContactInfo"
+
+// ------------ Plugin/player status ------------
+
+/*
+ wParam: 1 - switch off plugin
+ 0 - switch on plugin
+ -1 - switch plugin status
+ 2 - get plugin version
+ other - get plugin status
+ lParam: 0
+ Affects: Switch plugin status to enabled or disabled
+ returns: old plugin status, 0, if was enabled
+*/
+#define MS_WAT_PLUGINSTATUS "WATrack/PluginStatus"
+
+// ---------- events ------------
+
+/*ME_WAT_MODULELOADED
+ wParam: 0, lParam: 0
+*/
+#define ME_WAT_MODULELOADED "WATrack/ModuleLoaded"
+
+#define WAT_EVENT_PLAYERSTATUS 1 //lParam: WAT_PLS_* const
+#define WAT_EVENT_NEWTRACK 2 //lParam: LPSONGINFO
+#define WAT_EVENT_PLUGINSTATUS 3 //lParam: 0-enabled; 1-dis.temporary; 2-dis.permanent
+#define WAT_EVENT_NEWPLAYER 4 //
+#define WAT_EVENT_NEWTEMPLATE 5 //lParam: TM_* constant
+
+/*ME_WAT_NEWSTATUS
+ Plugin or player status changed:
+ wParam: type of event (see above)
+ lParam: value
+*/
+#define ME_WAT_NEWSTATUS "WATrack/NewStatus"
+
+// ---------- Popup module ------------
+
+/*
+ wParam: not used
+ lParam: not used
+ Affects: Show popup or Info window with current music information
+ note: Only Info window will be showed if Popup plugin disabled
+*/
+#define MS_WAT_SHOWMUSICINFO "WATrack/ShowMusicInfo"
+
+// --------- Statistic (report) module -------------
+
+/*
+ wParam: pointer to log file name or NULL
+ lParam: pointer to report file name or NULL
+ Affects: Create report from log and run it (if option is set)
+ returns: 0 if unsuccesful
+ note: if wParam or lParam is a NULL then file names from options are used
+*/
+#define MS_WAT_MAKEREPORT "WATrack/MakeReport"
+
+/*
+ wParam, lParam - not used
+ Affects: pack statistic file
+*/
+#define MS_WAT_PACKLOG = "WATrack/PackLog"
+
+/*
+ wParam: not used
+ lParam: pointer to SongInfo
+*/
+#define MS_WAT_ADDTOLOG = "WATrack/AddToLog"
+
+// ----------- Formats and players -----------
+
+// media file status
+
+#define WAT_MES_STOPPED 0
+#define WAT_MES_PLAYING 1
+#define WAT_MES_PAUSED 2
+#define WAT_MES_UNKNOWN -1
+
+#define WAT_ACT_REGISTER 1
+#define WAT_ACT_UNREGISTER 2
+#define WAT_ACT_DISABLE 3
+#define WAT_ACT_ENABLE 4
+#define WAT_ACT_GETSTATUS 5 // not found/enabled/disabled
+#define WAT_ACT_SETACTIVE 6
+#define WAT_ACT_REPLACE 0x10000 // can be combined with WAT_REGISTERFORMAT
+
+ // flags
+#define WAT_OPT_DISABLED 0x00001 // format registered but disabled
+#define WAT_OPT_ONLYONE 0x00002 // format can't be overwriten
+#define WAT_OPT_PLAYERINFO 0x00004 // song info from player
+#define WAT_OPT_WINAMPAPI 0x00008 // Winamp API support
+#define WAT_OPT_CHECKTIME 0x00010 // check file time for changes
+#define WAT_OPT_VIDEO 0x00020 // only for format registering used
+#define WAT_OPT_LAST 0x00040 // (internal)
+#define WAT_OPT_FIRST 0x00080 // (internal)
+#define WAT_OPT_TEMPLATE 0x00100 // (internal)
+#define WAT_OPT_IMPLANTANT 0x00200 // use process implantation
+#define WAT_OPT_HASURL 0x00400 // (player registration) URL field present
+#define WAT_OPT_CHANGES 0x00800 // obtain only chaged values
+ // (volume, status, window text, elapsed time)
+#define WAT_OPT_APPCOMMAND 0x01000 // Special (multimedia) key support
+#define WAT_OPT_CHECKALL 0x02000 // Check all players
+#define WAT_OPT_KEEPOLD 0x04000 // Keep Old opened file
+#define WAT_OPT_MULTITHREAD 0x08000 // Use multithread scan
+#define WAT_OPT_SINGLEINST 0x10000 // Single player instance
+#define WAT_OPT_PLAYERDATA 0x20000 // (internal) to obtain player data
+
+
+typedef BOOL (__cdecl *LPREADFORMATPROC)(LPSONGINFO Info);
+
+typedef struct tMusicFormat {
+ LPREADFORMATPROC proc;
+ CHAR ext[8];
+ UINT flags;
+} MUSICFORMAT, *LPMUSICFORMAT;
+
+/*
+ wParam: action
+ lParam: pointer to MUSICFORMAT if wParam = WAT_ACT_REGISTER,
+ else - pointer to extension string (ANSI)
+ returns: see result codes
+*/
+#define MS_WAT_FORMAT "WATrack/Format"
+
+/*
+ wParam - pointer to SONGINFO structure (plwind field must be initialized)
+ lParam - flags
+ Affects: trying to fill SongInfo using Winamp API
+*/
+#define MS_WAT_WINAMPINFO "WATrack/WinampInfo"
+
+/*
+ wParam: window
+ lParam: LoWord - command; HiWord - value
+*/
+#define MS_WAT_WINAMPCOMMAND "WATrack/WinampCommand"
+
+typedef int (__cdecl *LPINITPROC) ();
+typedef int (__cdecl *LPDEINITPROC) ();
+typedef int (__cdecl *LPSTATUSPROC) (HWND wnd);
+typedef WCHAR (__cdecl *LPNAMEPROC) (HWND wnd, int flags);
+typedef HWND (__cdecl *LPCHECKPROC) (HWND wnd,int flags);
+typedef int (__cdecl *LPINFOPROC) (LPSONGINFO Info, int flags);
+typedef int (__cdecl *LPCOMMANDPROC)(HWND wnd, int command, int value);
+
+typedef struct tPlayerCell {
+ CHAR* Desc; // Short player name
+ UINT flags;
+ HICON Icon; // can be 0. for registration only
+ LPINITPROC Init; // LPINITPROC; can be NULL. initialize any data
+ LPDEINITPROC DeInit; // LPDEINITPROC; can be NULL. finalize player processing
+ LPCHECKPROC Check; // check player
+ LPSTATUSPROC GetStatus; // tStatusProc; can be NULL. get player status
+ LPNAMEPROC GetName; // can be NULL. get media filename
+ LPINFOPROC GetInfo; // can be NULL. get info from player
+ LPCOMMANDPROC Command; // can be NULL. send command to player
+ CHAR* URL; // only if WAT_OPT_HASURL flag present
+ WCHAR* Notes; // any tips, notes etc for this player
+} PLAYERCELL, *LPPLAYERCELL;
+
+/*
+ wParam: action
+ lParam: pointer to PLAYERCELL if wParam = WAT_ACT_REGISTER,
+ else - pointer to player description string (ANSI)
+ returns: player window handle or value>0 if found
+ note: If you use GetName or GetInfo field, please, do not return empty
+ filename even when mediafile is remote!
+*/
+#define MS_WAT_PLAYER "WATrack/Player"
+
+// --------- Last FM ---------
+
+/*
+ Toggle LastFM scrobbling status
+ wParam,lParam=0
+ Returns: previous state
+*/
+#define MS_WAT_LASTFM "WATrack/LastFM"
+
+/*
+ Get Info based on currently played song
+ wParam: pLastFMInfo
+ lParam: int language (first 2 bytes - 2-letters language code)
+*/
+typedef struct tLastFMInfo {
+ UINT request; // 0 - artist, 1 - album, 2 - track
+ WCHAR* artist; // artist
+ WCHAR* album; // album or similar artists for Artist info request
+ WCHAR* title; // track title
+ WCHAR* tags; // tags
+ WCHAR* info; // artist bio or wiki article
+ WCHAR* image; // photo/cover link
+ WCHAR* similar;
+ WCHAR* release;
+ UINT trknum;
+}PLASTFMINFO, *LPLASTFMINFO;
+
+#define MS_WAT_LASTFMINFO "WATrack/LastFMInfo"
+
+// --------- Templates ----------
+
+/*
+ wParam: 0 (standard Info) or pSongInfo
+ lParam: Unicode template
+ returns: New Unicode (replaced) string
+*/
+#define MS_WAT_REPLACETEXT "WATrack/ReplaceText"
+
+/*
+ event types for History
+ Blob structure for EVENTTYPE_WAT_ANSWER:
+ Uniciode artist#0title#0album#0answer
+*/
+#define EVENTTYPE_WAT_REQUEST 9601
+#define EVENTTYPE_WAT_ANSWER 9602
+#define EVENTTYPE_WAT_ERROR 9603
+#define EVENTTYPE_WAT_MESSAGE 9604
+
+/*
+ wParam: 0 or parent window
+ lParam: 0
+ note: Shows Macro help window with edit aliases ability
+*/
+#define MS_WAT_MACROHELP "WATrack/MacroHelp"
+
+#endif
diff --git a/plugins/Watrack/docs/m_music.inc b/plugins/Watrack/docs/m_music.inc
new file mode 100644
index 0000000000..1850de52ba
--- /dev/null
+++ b/plugins/Watrack/docs/m_music.inc
@@ -0,0 +1,404 @@
+{$IFNDEF M_MUSIC}
+{$DEFINE M_MUSIC}
+
+// defined in interfaces.inc
+//const MIID_WATRACK:MUUID='{FC6C81F4-837E-4430-9601-A0AA43177AE3}';
+
+type
+ pSongInfoA = ^tSongInfoA;
+ tSongInfoA = packed record
+ artist :PAnsiChar;
+ title :PAnsiChar;
+ album :PAnsiChar;
+ genre :PAnsiChar;
+ comment :PAnsiChar;
+ year :PAnsiChar;
+ mfile :PAnsiChar; // media file
+ kbps :dword;
+ khz :dword;
+ channels :dword;
+ track :dword;
+ total :dword; // music length
+ time :dword; // elapsed time
+ wndtext :PAnsiChar; // window title
+ player :PAnsiChar; // player name
+ plyver :dword; // player version
+ icon :THANDLE; // player icon
+ fsize :dword; // media file size
+ vbr :dword;
+ status :integer; // WAT_MES_* const
+ plwnd :HWND; // player window
+ // video part
+ codec :dword;
+ width :dword;
+ height :dword;
+ fps :dword;
+ date :int64;
+ txtver :PAnsiChar;
+ lyric :PAnsiChar;
+ cover :PAnsiChar;
+ volume :dword;
+ url :PAnsiChar; // player homepage
+ winampwnd:HWND;
+ end;
+type
+ pSongInfo=^tSongInfo;
+ tSongInfo = packed record
+ artist :pWideChar;
+ title :pWideChar;
+ album :pWideChar;
+ genre :pWideChar;
+ comment :pWideChar;
+ year :pWideChar;
+ mfile :pWideChar; // media file
+ kbps :dword;
+ khz :dword;
+ channels :dword;
+ track :dword;
+ total :dword; // music length
+ time :dword; // elapsed time
+ wndtext :pWideChar; // window title
+ player :pWideChar; // player name
+ plyver :dword; // player version
+ icon :THANDLE; // player icon
+ fsize :dword; // media file size
+ vbr :dword;
+ status :integer; // WAT_MES_* const
+ plwnd :HWND; // player window
+ // video part
+ codec :dword;
+ width :dword;
+ height :dword;
+ fps :dword;
+ date :int64;
+ txtver :pWideChar;
+ lyric :pWideChar;
+ cover :pWideChar; // cover path
+ volume :dword;
+ url :PWideChar; // player homepage
+ winampwnd:HWND;
+ end;
+ pSongInfoW = pSongInfo;
+ tSongInfoW = tSongInfo;
+
+const
+ // result codes
+ WAT_RES_UNKNOWN = -2;
+ WAT_RES_NOTFOUND = -1;
+ WAT_RES_ERROR = WAT_RES_NOTFOUND;
+ WAT_RES_OK = 0;
+ WAT_RES_ENABLED = WAT_RES_OK;
+ WAT_RES_DISABLED = 1;
+ // internal
+ WAT_RES_NEWFILE = 3;
+ WAT_RES_NEWPLAYER = 4;
+
+// result for MS_WAT_GETMUSICINFO service
+const
+ WAT_PLS_NORMAL = WAT_RES_OK;
+ WAT_PLS_NOMUSIC = WAT_RES_DISABLED;
+ WAT_PLS_NOTFOUND = WAT_RES_NOTFOUND;
+
+const
+ WAT_INF_UNICODE = 0;
+ WAT_INF_ANSI = 1;
+ WAT_INF_UTF8 = 2;
+ WAT_INF_CHANGES = $100;
+
+const
+ MS_WAT_INSERT:PAnsiChar = 'WATrack/Insert';
+ MS_WAT_EXPORT:PAnsiChar = 'WATrack/Export';
+
+const
+{
+ wParam : WAT_INF_* constant
+ lParam : pointer to pSongInfo (Unicode) or pSongInfoA (ANSI/UTF8)
+ Affects: Fill structure by currently played music info
+ returns: WAT_PLS_* constant
+ note: pointer will be point to global SongInfo structure of plugin
+ warning: Non-Unicode data filled only by request
+ if lParam=0 only internal SongInfo structure will be filled
+ Example:
+ var p:pSongInfo;
+ PluginLink^.CallService(MS_WAT_GETMUSICINFO,0,dword(@p));
+}
+ MS_WAT_GETMUSICINFO:PAnsiChar = 'WATrack/GetMusicInfo';
+{
+ wParam:0
+ lParam : pointer to pSongInfo (Unicode)
+ Affects: Fill structure by info from file named in SongInfo.mfile
+ returns: 0, if success
+ note: fields, which values can't be obtained, leaves old values.
+ you must free given strings by miranda mmi.free
+}
+ MS_WAT_GETFILEINFO:PAnsiChar = 'WATrack/GetFileInfo';
+
+{
+ wParam: encoding (WAT_INF_* consts, 0 = WAT_INF_UNICODE)
+ lParam: codepage (0 = ANSI)
+ Returns Global unicode SongInfo pointer or tranlated to Ansi/UTF8 structure
+}
+ MS_WAT_RETURNGLOBAL:PAnsiChar = 'WATrack/GetMainStructure';
+
+//!! DON'T CHANGE THESE VALUES!
+const
+ WAT_CTRL_FIRST = 1;
+
+ WAT_CTRL_PREV = 1;
+ WAT_CTRL_PLAY = 2;
+ WAT_CTRL_PAUSE = 3;
+ WAT_CTRL_STOP = 4;
+ WAT_CTRL_NEXT = 5;
+ WAT_CTRL_VOLDN = 6;
+ WAT_CTRL_VOLUP = 7;
+ WAT_CTRL_SEEK = 8; // lParam is new position (sec)
+
+ WAT_CTRL_LAST = 8;
+
+{
+ wParam: button code (WAT_CTRL_* const)
+ lParam: 0, or value (see WAT_CTRL_* const comments)
+ Affects: emulate player button pressing
+ returns: 0 if unsuccesful
+}
+ MS_WAT_PRESSBUTTON:PAnsiChar = 'WATrack/PressButton';
+
+{
+ Get user's Music Info
+}
+ MS_WAT_GETCONTACTINFO:PAnsiChar = 'WATrack/GetContactInfo';
+
+// ------------ Plugin/player status ------------
+
+{
+ wParam: 1 - switch off plugin
+ 0 - switch on plugin
+ -1 - switch plugin status
+ 2 - get plugin version
+ other - get plugin status
+ lParam: 0
+ Affects: Switch plugin status to enabled or disabled
+ returns: version, old plugin status, 0, if was enabled
+}
+ MS_WAT_PLUGINSTATUS:PAnsiChar = 'WATrack/PluginStatus';
+
+ ME_WAT_MODULELOADED:PAnsiChar = 'WATrack/ModuleLoaded';
+
+const
+ WAT_EVENT_PLAYERSTATUS = 1; // WAT_PLS_* const
+ WAT_EVENT_NEWTRACK = 2; // SongInfo ptr
+ WAT_EVENT_PLUGINSTATUS = 3; // 0-enabled; 1-dis.temporary; 2-dis.permanent
+ WAT_EVENT_NEWPLAYER = 4; //
+ WAT_EVENT_NEWTEMPLATE = 5; // TM_* constant
+
+{
+ Plugin or player status changed:
+ wParam: type of event (see above)
+ lParam: value
+}
+ ME_WAT_NEWSTATUS:PAnsiChar = 'WATrack/NewStatus';
+
+// ---------- Popup module ------------
+
+{
+ wParam: not used
+ lParam: not used
+ Affects: Show popup or Info window with current music information
+ note: Only Info window will be showed if Popup plugin disabled
+}
+ MS_WAT_SHOWMUSICINFO:PAnsiChar = 'WATrack/ShowMusicInfo';
+
+// --------- Statistic (report) module -------------
+
+{
+ wParam: pointer to log file name or NIL
+ lParam: pointer to report file name or NIL
+ Affects: Create report from log and run it (if option is set)
+ returns: 0 if unsuccesful
+ note: if wParam or lParam is a NIL then file names from options are used
+}
+ MS_WAT_MAKEREPORT :PAnsiChar = 'WATrack/MakeReport';
+// MS_WAT_MAKEREPORTW:PAnsiChar = 'WATrack/MakeReportW';
+
+{
+ wParam, lParam - not used
+ Affects: pack statistic file
+}
+ MS_WAT_PACKLOG:PAnsiChar = 'WATrack/PackLog';
+
+{
+ wParam: not used
+ lParam: pointer to SongInfo
+}
+ MS_WAT_ADDTOLOG:PAnsiChar = 'WATrack/AddToLog';
+
+// ----------- Formats and players -----------
+
+// media file status
+
+const
+ WAT_MES_STOPPED = 0;
+ WAT_MES_PLAYING = 1;
+ WAT_MES_PAUSED = 2;
+ WAT_MES_UNKNOWN = -1;
+
+const
+ WAT_ACT_REGISTER = 1;
+ WAT_ACT_UNREGISTER = 2;
+ WAT_ACT_DISABLE = 3;
+ WAT_ACT_ENABLE = 4;
+ WAT_ACT_GETSTATUS = 5; // not found/enabled/disabled
+ WAT_ACT_SETACTIVE = 6;
+ WAT_ACT_REPLACE = $10000; // can be combined with WAT_REGISTERFORMAT
+
+const
+ // flags
+ WAT_OPT_DISABLED = $00000001; // registered but disabled
+ WAT_OPT_ONLYONE = $00000002; // can't be overwriten
+ WAT_OPT_PLAYERINFO = $00000004; // song info from player
+ WAT_OPT_WINAMPAPI = $00000008; // Winamp API support
+ WAT_OPT_CHECKTIME = $00000010; // check file time for changes
+ WAT_OPT_VIDEO = $00000020; // only for format registering used
+ WAT_OPT_LAST = $00000040; // (internal-Winamp Clone) put to the end of queue
+ WAT_OPT_FIRST = $00000080; // (internal)
+ WAT_OPT_TEMPLATE = $00000100; // (internal)
+ WAT_OPT_IMPLANTANT = $00000200; // use process implantation
+ WAT_OPT_HASURL = $00000400; // (player registration) URL field present
+ WAT_OPT_CHANGES = $00000800; // obtain only chaged values
+ // (volume, status, window text, elapsed time)
+ WAT_OPT_APPCOMMAND = $00001000; // Special (multimedia) key support
+ WAT_OPT_CHECKALL = $00002000; // Check all players
+ WAT_OPT_KEEPOLD = $00004000; // Keep Old opened file
+ WAT_OPT_MULTITHREAD = $00008000; // Use multithread scan
+ WAT_OPT_SINGLEINST = $00010000; // Single player instance
+ WAT_OPT_PLAYERDATA = $00020000; // (internal) to obtain player data
+
+type
+ tReadFormatProc = function(var Info:tSongInfo):boolean; cdecl;
+ pMusicFormat = ^tMusicFormat;
+ tMusicFormat = packed record
+ proc :tReadFormatProc;
+ ext :array [0..7] of AnsiChar;
+ flags:cardinal;
+ end;
+
+const
+{
+ wParam: action
+ lParam: pointer to tMusicFormat if wParam = WAT_ACT_REGISTER,
+ else - pointer to extension string (ANSI)
+ returns: see result codes
+}
+ MS_WAT_FORMAT:PAnsiChar = 'WATrack/Format';
+
+{
+ wParam: pointer to SongInfo structure (plwind field must be initialized)
+ lParam: flags
+ Affects: trying to fill SongInfo using Winamp API
+}
+ MS_WAT_WINAMPINFO:PAnsiChar = 'WATrack/WinampInfo';
+
+{
+ wParam: window
+ lParam: LoWord - command; HiWord - value
+}
+ MS_WAT_WINAMPCOMMAND:PAnsiChar = 'WATrack/WinampCommand';
+
+type
+ tInitProc = function():integer;cdecl;
+ tDeInitProc = function():integer;cdecl;
+ tStatusProc = function(wnd:HWND):integer;cdecl;
+ tNameProc = function(wnd:HWND;flags:integer):pWideChar;cdecl;
+ tCheckProc = function(wnd:HWND;flags:integer):HWND;cdecl;
+ tInfoProc = function(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+ tCommandProc = function(wnd:HWND;command:integer;value:integer):integer;cdecl;
+
+ pPlayerCell = ^tPlayerCell;
+ tPlayerCell = packed record
+ Desc :PAnsiChar; // Short player name
+ flags :cardinal;
+ Icon :HICON; // can be 0. for registration only
+ Init :pointer; // tInitProc; can be NIL. initialize any data
+ DeInit :pointer; // tDeInitProc; can be NIL. finalize player processing
+ Check :pointer; // tCheckProc; check player
+ GetStatus:pointer; // tStatusProc; can be NIL. get player status
+ GetName :pointer; // tNameProc; can be NIL. get media filename
+ GetInfo :pointer; // tInfoProc; can be NIL. get info from player
+ Command :pointer; // tCommandProc; can be NIL. send command to player
+ URL :PAnsiChar; // only if WAT_OPT_HASURL flag present
+ Notes :PWideChar; // any tips, notes etc for this player
+ end;
+
+const
+{
+ wParam: action
+ lParam: pointer to tPlayerCell if wParam = WAT_ACT_REGISTER,
+ else - pointer to player description string (ANSI)
+ returns: player window handle or value>0 if found
+ note: If you use GetName or GetInfo field, please, do not return empty
+ filename even when mediafile is remote!
+}
+ MS_WAT_PLAYER:PAnsiChar = 'WATrack/Player';
+
+// --------- Last FM ---------
+
+{
+ Toggle LastFM scrobbling status
+ wParam,lParam=0
+ Returns: previous state
+}
+const
+ MS_WAT_LASTFM:pAnsiChar = 'WATrack/LastFM';
+
+{
+ Get Info based on currently played song
+ wParam: pLastFMInfo
+ lParam: int language (first 2 bytes - 2-letters language code)
+}
+type
+ pLastFMInfo = ^tLastFMInfo;
+ tLastFMInfo = packed record
+ request:cardinal; // 0 - artist, 1 - album, 2 - track
+ artist :pWideChar; // artist
+ album :pWideChar; // album or similar artists for Artist info request
+ title :pWideChar; // track title
+ tags :pWideChar; // tags
+ info :pWideChar; // artist bio or wiki article
+ image :pAnsiChar; // photo/cover link
+ similar:pWideChar;
+ release:pWideChar;
+ trknum :cardinal;
+ end;
+const
+ MS_WAT_LASTFMINFO:pAnsiChar = 'WATrack/LastFMInfo';
+
+// --------- Templates ----------
+
+const
+{
+ wParam: 0 (standard Info) or pSongInfo
+ lParam: Unicode template
+ returns: New Unicode (replaced) string
+}
+ MS_WAT_REPLACETEXT:PAnsiChar = 'WATrack/ReplaceText';
+
+{
+ event types for History
+ Blob structure for EVENTTYPE_WAT_ANSWER:
+ Uniciode artist#0title#0album#0answer
+}
+const
+ EVENTTYPE_WAT_REQUEST = 9601;
+ EVENTTYPE_WAT_ANSWER = 9602;
+ EVENTTYPE_WAT_ERROR = 9603;
+ EVENTTYPE_WAT_MESSAGE = 9604;
+
+const
+{
+ wParam: 0 or parent window
+ lParam: 0
+ note: Shows Macro help window with edit aliases ability
+}
+ MS_WAT_MACROHELP:pAnsiChar = 'WATrack/MacroHelp';
+
+{$ENDIF M_MUSIC}
diff --git a/plugins/Watrack/docs/sampledll.dpr b/plugins/Watrack/docs/sampledll.dpr
new file mode 100644
index 0000000000..908fe60597
--- /dev/null
+++ b/plugins/Watrack/docs/sampledll.dpr
@@ -0,0 +1,139 @@
+library testdll;
+
+uses m_api, Windows,common;
+
+{$include m_helpers.inc}
+{$include m_music.inc}
+
+const
+ PluginInfo:TPLUGININFOEX=(
+ cbSize :sizeof(TPLUGININFOEX);
+ shortName :'Plugin Template';
+ version :$00000001;
+ description:'The long description of your plugin, to go in the plugin options dialog';
+ author :'J. Random Hacker';
+ authorEmail:'noreply@sourceforge.net';
+ copyright :'(c) 2003 J. Random Hacker';
+ homepage :'http://miranda-icq.sourceforge.net/';
+ flags :UNICODE_AWARE;
+ replacesDefaultModule:0;
+ uuid:'{00000000-0000-0000-0000-000000000000}'
+ );
+var
+ PluginInterfaces:array [0..1] of MUUID;
+
+var
+ hook:integer;
+ oldproc:tReadFormatProc;
+
+// -------- format --------
+Function mp3proc(var dst:tSongInfo):boolean;cdecl;
+begin
+{
+ MP3 Handler here
+}
+//messagebox(0,'ok','',0);
+// Example for old handler
+ if (int(@oldproc)<>WAT_RES_OK) and (int(@oldproc)<>WAT_RES_ERROR) then
+ result:=oldproc(dst)
+ else
+ result:=true;
+end;
+
+// ---------- Player ----------
+var
+ plwnd:HWND;
+
+function Check(flags:integer):HWND;cdecl;
+begin
+ result:=1;
+ plwnd:=12;
+end;
+
+function GetFileName:pWideChar;cdecl;
+begin
+ result:=nil;
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+begin
+ PluginLink^.CallService(MS_WAT_WINAMPINFO,integer(@SongInfo),flags);
+ SongInfo.plyver:=$1234;
+ result:=0;
+end;
+
+function Command(command:integer;value:integer):integer;cdecl;
+begin
+ result:=PluginLink^.CallService(MS_WAT_WINAMPCOMMAND,plwnd,
+ command+(value shl 16));
+end;
+
+function OnWATLoaded(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ tmp:tMusicFormat;
+ tmp1:tPlayerCell;
+begin
+ PluginLink^.UnhookEvent(hook);
+
+ FillChar(tmp,SizeOf(tMusicFormat),0);
+ lstrcpy(tmp.ext,'MP3');
+ tmp.proc:=mp3proc;
+ oldproc:=tReadFormatProc(PluginLink^.CallService(MS_WAT_FORMAT,
+ WAT_ACT_REGISTER+WAT_ACT_REPLACE,dword(@tmp)));
+
+ FillChar(tmp1,SizeOf(tPlayerCell),0);
+ tmp1.desc :='Sampler';
+ tmp1.flags :=0;// WAT_OPT_WINAMPAPI
+ tmp1.Check :=@Check;
+ tmp1.GetInfo:=@GetInfo;
+ tmp1.Command:=@Command;
+ tmp1.GetName:=@GetFileName;
+ PluginLink^.CallService(MS_WAT_PLAYER,WAT_ACT_REGISTER+WAT_ACT_REPLACE,dword(@tmp1));
+ result:=0;
+end;
+
+function OnModuleLoaded(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+begin
+ hook:=HookEvent(ME_WAT_MODULELOADED,@OnWATLoaded);
+ result:=0;
+end;
+
+function MirandaPluginInfo(mirandaVersion:DWORD):PPLUGININFO; cdecl;
+begin
+ result:=@PluginInfo;
+ PluginInfo.cbSize:=SizeOf(TPLUGININFO);
+end;
+
+function MirandaPluginInfoEx(mirandaVersion:DWORD):PPLUGININFOEX; cdecl;
+begin
+ result:=@PluginInfo;
+ PluginInfo.cbSize:=SizeOf(TPLUGININFOEX);
+end;
+
+function Load(link: PPLUGINLINK): int; cdecl;
+begin
+ PLUGINLINK := Pointer(link);
+ InitMMI;
+ Result:=0;
+ hook:=HookEvent(ME_SYSTEM_MODULESLOADED,@OnModuleLoaded);
+end;
+
+function Unload: int; cdecl;
+begin
+ Result:=0;
+end;
+
+function MirandaPluginInterfaces:PMUUID; cdecl;
+begin
+ PluginInterfaces[0]:=PluginInfo.uuid;
+ PluginInterfaces[1]:=MIID_LAST;
+ result:=@PluginInterfaces;
+end;
+
+exports
+ Load, Unload,
+ MirandaPluginInfo
+ ,MirandaPluginInterfaces,MirandaPluginInfoEx;
+
+begin
+end.
diff --git a/plugins/Watrack/docs/wat.php b/plugins/Watrack/docs/wat.php
new file mode 100644
index 0000000000..d15049dd72
--- /dev/null
+++ b/plugins/Watrack/docs/wat.php
@@ -0,0 +1,28 @@
+<?php
+
+include_once 'const.php';
+
+function mbot_load()
+{
+ mb_SchReg("ex/1min","* * *",'every_1min',1,1);
+}
+
+function every_1min()
+{
+ $songinfo = 0;
+ if(mb_SysCallService(MS_WAT_GETMUSICINFO, WAT_INF_ANSI,
+ mb_SysGetPointer($songinfo))!=WAT_PLS_NORMAL)
+ return 0;
+
+ $artist_pos = mb_SysGetNumber($songinfo+wato_artist, 4);
+ $artist = mb_SysGetString($artist_pos);
+
+ $title_pos = mb_SysGetNumber($songinfo+wato_title, 4);
+ $title = mb_SysGetString($title_pos);
+
+ $newtext = "mp3: $artist - $title";
+
+ mb_MsgBox($newtext, "MBot", 4);
+ return 0;
+}
+?> \ No newline at end of file
diff --git a/plugins/Watrack/docs/watrack_history.txt b/plugins/Watrack/docs/watrack_history.txt
new file mode 100644
index 0000000000..bea80d4e85
--- /dev/null
+++ b/plugins/Watrack/docs/watrack_history.txt
@@ -0,0 +1,519 @@
+0.0.6.12 (17 nov 2009)
+ Added Last.FM scrobbling support
+0.0.6.11 (14 sep 2009)
+ Added watrack parts admin page
+ Fixed cover reading from OGG files
+ Fixed mRadio work when no avatar plugin presents
+ Fixed wrong LastFM recognition
+0.0.6.10 (28 aug 2008)
+ Added basic LastFM support
+ Added hidden option 'xstatpause',ms (word type) to make pause between XStatus changing
+ Added option to emulate multimedia keys
+ Added avatar as cover for mRadio contacts support
+0.0.6.9 (28 jan 2008)
+ Fixes for FLV format
+ Added option to assign 'music' and 'video' xstatuses
+ Changed Handle checking (to avoid Thread handle leak)
+ First tab setting notes shows on mouse hover (not click)
+0.0.6.8 (29 oct 2007)
+ Added two options to alter filename search method
+ Fixed: mRadio track changing not catched
+0.0.6.7 (26 aug 2007)
+ Added lyric support for APev2 tags, WMA
+ Added cover support for APev2 tags, WMA, OGG, SPX and fLaC
+ Optimized APEv2, OGG, fLaC and WMA reading code
+ Fixed ID3v2.4 tag reading code
+ Optimized mediafile handle checking
+0.0.6.6 (9 aug 2007)
+ AIMP player support code changed
+ Fixed some memoryleaks
+0.0.6.5 (20 jun 2007)
+ 'Use existing XStatus' options changes only message text, not title
+ Optimized FLV reading code
+ Fixed and optimized MPG reading code
+0.0.6.4 (13 jun 2007)
+ Added AIMP control
+0.0.6.3 (10 jun 2007)
+ Added: mRadio %version% macro support
+ Fixed: in rare case covers can be renamed and deleted
+ Fixed: %cover% value can be wrong if cover not present
+ Fixed: %volume% value for mRadio not obtaining
+0.0.6.2 (9 jun 2007)
+ Small players code fixes
+ Commented some thread code (due to AIMP 1.77 changes)
+ Fixed version number
+ Added seek ability for local mediafiles
+0.0.6.1 (7 jun 2007)
+ Added extended control for mRadio Mod
+ Added compatibility with AIMP 1.77
+ Added service to obtain not only played file info
+ Fixed: frame not change cover picture obtained from mediafile tags
+(01 jun 2007)
+ Added %nstatus% macro (like %status% but w/o translation)
+(29 may 2007)
+ Very small fixes (for mRadio too)
+(25 may 2007)
+ Added ability to show popups only by request, not new track
+(20 may 2007)
+ Changed: added threads for popups and statistic
+ Changed: Music/player Info obtaining code
+ Fixed: QCD player recognizing and processing
+(16 may 2007)
+ Added actions support for Popup Plus 2.1.0.5
+(15 may 2007)
+ Added %playerhome% (Player homepage url) macro
+(11 may 2007)
+ Small fixes
+ Statistic code optimized for speed
+(09 may 2007)
+ Added two buttons to check player/format list
+ AIMP player now processed separately
+ Changed code for played filename obtaining
+0.0.6.0 (05 may 2007)
+ Many small codechanges and fixes
+ Music info request can be send by ASKWAT text sending (received as message)
+ Settings saved only in profile db now
+0.0.5.0 (18 feb 2007)
+ Fixed: cover is showed only when backround picture name is not empty
+ Cover files deleted at exit now
+ Added volume field (see readme) to SongInfo structure.
+ Fixed: Cover from ID3v2 tag saved incorrectly
+ Fixed: Miranda crashed when shutdowned
+ Code cleaning and optimization
+0.0.4.30 (24 dec.2006)
+ Changed internal code library
+ Fixed comment reading from ID3v2 tag
+0.0.4.29 (29 nov 2006)
+ Small Fixes
+ Changes for external icon support for player.ini file
+ Fixed: ini file modified constantly if player not found
+0.0.4.28 (16 nov 2006)
+ Other bugfixes
+ Fixed: Contact menu handler chain was broken
+0.0.4.27 (15 nov 2006)
+ Small player handles fixes
+ Fixed: crash with WAV file samplesize<8 bit
+ Added options to choose Music info sharing ability
+ Added context menu music info request
+ Fixed bug with Frame redraw/resizing
+ Added external player definition
+0.0.4.26 (7 nov 2006)
+ Added album sort mode to report
+ Fixed some report errors
+ Changes for old miranda versions (before 0.6) compatibility
+0.0.4.25 (31 oct 2006)
+ INI file (not database) used by default
+ Winamp video width and height recognizing returned (for test)
+ Fixed: log file rewrited always
+ Fixed: Report creating from Options tab was wrong
+ Fixed: "Export default" button on options tab not work
+0.0.4.24 (29 oct 2006)
+ Report code was rewritten to template support
+ Current settings saved when saving place changed (switch at last!)
+ Loading settings from profile database works now normally
+ Fixed: Player name case conversion was after WAT_EVENT_NEWTRACK sending
+ Width and Height recognition through Winamp API disables due to wrong return values
+0.0.4.23 (15 oct 2006)
+ Save in INI/profile base file option returned
+ API changes
+ ID3v2 tag reading code was changed
+ Rewritten and reorganized internal structure
+ mBot script sample added
+0.0.4.22 (17 sep 2006)
+ INI-file structure changes (frame, report and popup options is separated)
+ CyberLink PowerDVD recognizing added
+ ALSong player recognizing added
+ MediaInfo obtained at plugin start now (if refresh time is not 0)
+ First version of new Player API is finished
+ Underscore replaces by spaces only in text macros (not media filename)
+ Fixed: wrong action on "Use Frame" checkbox
+0.0.4.21 (28 aug 2006) (test)
+ Miranda memory manager used now
+ Fixed: ID3v2 tags cannot process Unicode strings with reverse byte order
+ Media format API rewrited, new service added
+ Added event notifier for plugin loading
+ Added event notifier for plugin/player status changing
+0.0.4.20 (20 aug 2006)
+ Only songs with known length are addings to log
+ Added frame text centering
+ Small bugfixes
+ Fixed: Mirada crashes while report creating changed from menu
+ Added mRadio plugin support (test)
+ Fixed: sometimes trackbar is hidden
+ Added SongBird player support
+0.0.4.19 (11 aug 2006)
+ XStatus 'Watching pro7 on TV' works like 'Listening to music' XStatus but for video
+ Show/hide trakbar option is separated now
+ Sources changed for delphi7_up compatibility
+ Fixed: Sometimes plugin show hotkey registration error
+ Fixed: Timer stopped when Options page is open
+ Added some additional settings for frame text scrolling
+ Fixed: iTunes volume control does not work
+ Added menu item and toolbar button to disable plugin
+ Fixed error with unknown format tag in the frame template
+ Added WiFiRadio player support
+ Added option to hide frame when player not found
+0.0.4.18 (14 jul 2006)
+ Added GOM player detection
+ {cf#nnnnnn} and {bg#nnnnnn} is define color with hex trucolor value 'nnnnnn'
+ Added frame text format support
+ Added pushed/hovered button status support if watrack_buttons.dll is used
+0.0.4.17 (10 jul 2006)
+ Fixed: frame button not unpress when pressed button mouse moves out of frame
+ Added option to use or not gap between frame buttons
+ Option tabs changed back to theme ability
+ Added "skin" trackbar ability
+0.0.4.16 (9 jul 2006)
+ Small interface changes
+ Volume buttons on the frame changed and can be hided now
+ '\t' combination (Tabulation) changed to '{tab}' tag format
+ Fixed avoid '\n' combination conflict in templates
+ Holding mouse button on volume control make continuous decremet/increment
+ Fixed some bugs
+ Added frame transparency
+0.0.4.15 (5 jul 2006)
+ Added right align frame picture option
+ Fixed: text insertion hotkey do not always register
+ Service for player control is created
+ Added "Next track" to popup click options
+ If timer value greater than 499, time signify as milliseconds
+0.0.4.14 (3 jul 2006)
+ Added bottom align frame picture option
+ Fixed: Miranda freezes on W2K when some radiobuttons clicked
+ Returned modified old code for Foobar recognize
+0.0.4.13 (29 jun 2006)
+ Updater data changed for new hosting compatibility
+ Added support \t in templates (expanded when used)
+ Frame text now can be edited
+ Frame background can be picture (with effects: center, tile, stretch)
+ Options saves in profile directory as default (if old settings not found)
+ Foobar2000 recognizing code changed
+ Jabber chat recognized now
+ Fixed: 'Try to use OLE interface' option not changed
+ Added frame bitmap background support
+ Fixed: control icons in IcoLib not shows then watrack_icons.dll is not found
+ Volume control added
+ New Frame options added
+0.0.4.12 (18 jun 2006)
+ Fixed (i hope) bug with info refresh while MediaMonkey finished
+ Added frame support with IcoLib support
+ Added control procedures for some players
+ Small speed optimization
+ Introduced option to enable/disable players OLE interface
+0.0.4.11 (14 jun 2006)
+ Fixed FLV bug
+ Added MPEG file support (only MPEG audio stream)
+0.0.4.10 test (11 jun 2006)
+ New macro %txtver% (text version number representation) was introduced
+ Small fixes
+ Imroved Foobar2000 support if foo_comserver2 plugin is present
+0.0.4.9 (06 jun 2006)
+ Added partial support for MOV and 3GP file formats
+ Added support for ID3v2 tag v.2
+ Added option to skip some plugin error messages (mainly for hotkeys)
+ INI file is not rewritten now if default player was not changed
+ Added QuickTime player support
+0.0.4.8 (31 may 2006)
+ Added New options to insert text in text field of other apps
+ Code compiled with KOL (smaller size)
+0.0.4.7
+ Version numeration changed for more Updater compatibility. Last number is for betas.
+ Trying to use XP theming in TABs
+ Changed XStatus recovery code
+0.0.4.6 (23 may 2006)
+ Variables and NewAwaySys works now with Unicode
+ Small interface changes
+ Added FLVPlayer support
+ Added option to check file date/time changes while playing
+ Added option to set XStatus regardless of ICQ status
+ Added option to replace underline with spaces
+ Fixed NAS service call
+ Added partial FLV format support
+ Fixed: some unicode named files can't be processed
+ Macro help removed from resource
+0.0.4.5 (11 may 2006)
+ Changed Macro help window - with localisation support now
+ Added NewAwaySys (unicode) support for status text changings
+ Added MPlayer support
+ Fixed MusikCube player code
+ Fixed template formatting in IRC channel
+ Added partial MKV, WMV and ASF formats support
+ Changed RM reading code to video info compatibility
+ Added AVI file support (test version)
+ Added OGM file support
+ %fps%, %width%, %height% and %codec% macro added
+ OGG file info reading changes
+ Fixes for large files
+ Finally fixed bug with Popup templates
+ Options dialog changed again (Templates and Protocols tabs is merged)
+0.0.4.4 (24 apr 2006)
+ Fixed: Template macro help not work
+ Changed WavPack reading code for v.4* compatibility
+ Fixed bug with INI file name processing
+ Status message now uses 'Status Text' template (was 'Status Title')
+ MediaMonkey player class now partially uses OLE interface
+ Music XStatus can be cleared when miranda starts without music
+ Watrack.ini used if private INI file is absent
+ Notes in first option tab is Unicode now
+ Changed work with statuses (normal and extended)
+ Changed plugin behaviour when Miranda started without played song
+ Default template texts changed
+ Fixed: unused strings was keeped in INI file.
+ Fixed: can crash when Variables plugin not exists
+ Fixed: protocols enabling-disabling not works properly
+ Fixed: Crashes when music played and templates changed
+ MediaMonkey recognized as separate player now, not Winamp clone
+ All settings now saved in INI-file
+ Template option dialog was totally rewrited
+0.0.4.3 (26 mar 2006)
+ Added option to return Variables value in ANSI
+ Small save-related changes
+ Added 'AudioPlayer' support
+ Player icons moved to separate file (must be in icons or plugins directory)
+ Added player window handle to SongInfo structure
+ Added popup option to activate player window
+ Fixed: wrong 'Total logged music time' value
+ Added Core Media Player support
+0.0.4.2 (03 mar 2006)
+ Fixed RM file reading
+ Fixed ID3v2 tag reading (UTF8 encoding)
+ Small option dialog interface changes
+ Localisation sample file included (russian)
+ psapi.dll included (needed when plugin can't get song filename)
+ Fixed WMA tag reading
+ Fixed LA player recognition (wrong player status was returned)
+ Old XStatus restored now if player not found
+ Changed: if XStatus title is empty, it is cleared now
+ Changed %music% command translation code
+0.0.4.1 (26 feb 2006)
+ Deleted ICQ XStatus old API code
+ Added Creative Media Source support
+ Added 'version' resource
+ Status and popup templates are separated now
+ Added Media Commander Express player support
+ Added IcoLib support
+ Added VLC player support
+ Added Helium Music Manager support
+ Added Musicmatch Jukebox player support
+ Added %music% command with BB-code formatting in message dialog
+ Added option for player title formatting
+ Fixed error with filename in File info called from popup
+ Added support for J.River Media Center
+ Fixed situation when player is stopped
+ Fixed: 511 byte per string only saved in INI-file
+ Fixed player status for unknown filetypes
+ Small fix for MP4/M4A reading
+ Added partial M4A file format tag support
+ Added option to get unknown music format info from player
+ Changed WMA tag reading code to obtain number-type values
+ All resource language is Neutral now
+ Changed MusicCubeOne and SAPS players recognition
+ When 'no-music text' is empty and player stopped status message cleared
+ When 'Keep Status' is 'on' status text cleared
+ Song time can show more than 99 hours now
+ Changed recognizing song filename when Apollo is 'stopped'
+ Added Pluton player support
+ Fixed: Clearing 'Music' XStatus doesn't work with new ICQ API
+0.0.4.0 (29 jan 2006)
+ Added option to disable log
+ Changed XStatus setting code to compatibles with new ICQ API
+ Fixed: Popup service function works only with TopToolBar
+ Vorbis comment tag names now case insensitive
+ Changed FLAC reading code. Now with Vorbis comments
+ Current music format saves and checks firstly
+ Fixed: 'Save settings in INI-file' option cleared if Options dialog opens
+ Nearby twin record in statistic file is ignored now
+ Relative report or statistic file path calculated now from Miranda directory
+ Corrected status changing when player stopped
+ Added %status% macro (works with not all players!!!)
+ Added option to save CSS file separately
+ Added automatic report file extension adding/changing
+ Added VBR/CBR text to File Info from pupup
+ Added %year% macro help (i just forgot)
+ Empty report file not created if log file is invalid
+ Added menu item and service function for report creating
+ Added support for SAPS player
+ Added support for Zoom player
+ Changed QCDPlayer code to support new QMPlayer
+0.0.3.8 (19 jan 2006)
+ Fixed MP3 VBR reading bug
+ Added simple statistic (UTF8 enc.) (just for fun)
+ Added %vbr% macro and option for it
+ Added template when player not found
+ Changed Options interface
+ Changed Service function interface (please, see comments!)
+ Fixed wrong %total% value when 'Variables' plugin used
+ Added MusicCube One player support
+ OGG tags now translated as UTF8
+ Fixed some ID3v2 tag reading issues and errors
+ Fixed track number recognize in APEv2 tag
+ Active Player places on first place (save in settings - AI! :) )
+ Now MP3 files checked firstly
+ Changed Foobar2000 main window search procedure
+ Deep code changes (translating to Unicode strings and other)
+0.0.3.7 (26 dec 2005)
+ Added file size text formatting
+ Corrected formatted text output
+ Fixed WMA reading code (again)
+ Fixed internal ANSI to Unicode transformation
+ Changed Options dialog
+0.0.3.6 (21 dec 2005)
+ Added Unicode support
+ Fixed wrong WMA tag reading
+ Advances PopUp settings
+ Toolbar button for popup window added
+ Small code optimisation
+ Fixed chat or message window recognition
+ Partially avoiding WMP10 playlist bug
+ Added XMPlayer support
+ Added macros %size% (file size) and %type% (file ext.)
+0.0.3.5 (05 dec 2005)
+ Now Status not processes and Popup not shows when player is stopped
+ Popup settings dialog created
+ Added BSPlayer support
+0.0.3.4 (28 nov 2005)
+ Some changes for Service function (mainly description, see header)
+ Fixed (i hope): Miranda crushes sometimes by pressing hotkey
+ 'No-music text' can processed by Variables plugin
+ Now Status changing works in separated protocols
+ Fixed: Popup shows not always
+ Status template now multiline
+ Added player icon in Popup window
+0.0.3.3 (24 nov 2005)
+ Changed Foobar2000 recognition for new versions
+ Remove elapsed time recongition within Foobar2000 (sorry!)
+ Now with player shutdown XStatus changes to 'none' and no sets anymore
+ Added simply PopUp support (Status Template value)
+ Added option to change XStatus only for existing Music xstatus
+ Added option to keep or not Music XStatus on player exit
+ Fixed: Miranda can crush while use Variables plugin
+0.0.3.2 (19 nov 2005)
+ File renamed for avoiding Updater plugin crash
+ Fixed: format tag at the end of template not translated
+ Fixed variables help
+ Added support for ViPlay3 player
+ Data for 'Variables' plugin updated by timer
+ Added ability to switch off some players
+ Added ability to change processed status mode
+ Added ability to save settings in INI-file
+ Settings saved only from Options dialog, not on exit
+ Some code changes
+0.0.3.0 (29 oct 2005)
+ Genre name table moved to resource
+ ICQ XStatus changes only for non-offline user mode
+ Fixed: 'new line' code inserted at the end
+0.0.2.9 (27 oct 2005)
+ Fixed: Stupid bug - text not inserted into CHAT window
+ Temporary: text formatting used in ordinal message window too (only for testing)
+0.0.2.8 (27 oct 2005)
+ Added support for RA/RM format (experimental)
+ Changed text formatting algorithm (test for Asian text, please!)
+ Created version archive on http://awkward.front.ru/archive/
+ Try to use simple Updater plugin compatibility
+0.0.2.7 (25 oct 2005)
+ Fixed: Status message not changed by timer
+ Added: experimental Chat window text formatting (see readme)
+0.0.2.6 (23 oct 2005)
+ Fixed some bugs.
+ Other small changes.
+0.0.2.5 (23 oct 2005)
+ Modified Option Dialog and added translation ability
+ Added partial support for AAC file format
+ Added support for MP4 with MP3-coding format
+ Added support for MusikCube player
+ Added alternative ID3v2 tag frames
+0.0.2.4 (19 oct 2005)
+ Changed hotkey processing (not global hook now)
+ Changed some players recognition
+ Changed Music info interface (see include file)
+ Added support for 'Variables' plugin (not fully tested)
+ Added support for MediaMonkey Player
+ Added support for RealPlayer
+ Added support for MPC file format (only 'MPC' extension)
+ Added partial support for SPX file format (not tested)
+ Added partial support for OFR file format (not tested)
+ Now Status sets only if changed
+0.0.2.2 (10 oct 2005)
+ (Not fully tested, save previous version!)
+ Now HotKey work only with own Miranda copy
+ New tag processing algorithm
+ Added WAV format support
+ Added experimental APE,TTA and FLAC formats support (not tested)
+ Added iTunes and PlayNow! players recognize
+ Some internal changes
+ Macro %samplerate% and %bitrate% (%khz% and %kbps% synonims) added
+ Fixed: unwanted XStatus changing to 'Music'
+0.0.1.8 (05 oct 2005)
+ Fixed: Sometime Foobar2000 main window not recognized properly
+ Small speed optimisation
+ Added LightAlloy recognize
+ Empty "No-Music text" keep original Miranda status messages now
+ Fixed: in Apollo and OGG-file Bitrate was Bps, not KBps,
+ Samplerate was Hz, not KHz
+0.0.1.7 (04 oct 2005)
+ Added automatic Music info refresh by timer
+ Added option to NOT insert music info into message window
+ Fixed: crash on some comments in ID3v2
+0.0.1.6 (03 oct 2005)
+ Changed Options dialog
+ Added simple Away-message support (only by Hotkey pressing)
+ Macro %year% now work
+0.0.1.5 (02 oct 2005)
+ Support for Unicode value in ID3v2
+ Add WMA tag support
+ Fixed: macro %genre% not translated
+ Fixed: Winamp window title processing
+0.0.1.4 (29 sep 2005)
+ Added JetAudio support
+ Fixed: VBR MP3 length not propely calculated
+ Fixed music file name recognition
+ Added APEv2+ID3v1 at one time tag support
+0.0.1.3 (28 sep 2005)
+ Now get music info from file on local network
+0.0.1.2 (27 sep 2005)
+ Changed 'year' field type in music info
+ Added APEv2 tag support for MP3
+ Remove Win98-code part
+ Other small changes
+0.0.1.1 (25 sep 2005)
+ Test version.
+ win2KXP-only compatible.
+ Service function added.
+ MP3 IDv2 tag data read fixed
+ Some other bugs fixed (sorry, not all!).
+0.0.1.0 (25 sep 2005)
+ Test version: new music file search algorithm (MP3 OGG WMA only)
+ Windows media player wrapper not needed now
+0.0.0.9 (24 sep 2005)
+ correct MP3 file processing with padding at start
+ cutting template strings tail fixed again :(
+ add %percent% macro
+ Modified source code uploaded
+0.0.0.8 (22 sep 2005)
+ cutting template strings tail (sometime) fixed
+ %wndtext% macro turn "on" again :)
+0.0.0.7 (19 sep 2005)
+ MP3 tag support extended
+ OGG file info (not length, sorry!) added
+ music info readed at one time now (for Winamp-like API - at request too)
+ Apollo samplerate show changed
+ %comment% macro added
+0.0.0.6 (18 sep 2005)
+ Macro %track% value changed
+ audio MPEG 2 & 2,5 and layer 1 & 2 file support added
+ Some code cleaning
+ Correct data view from MP3 Tag
+ Changed Artist-Title determination algorithm
+ Changed Winamp search algorithm
+0.0.0.5 (14 sep 2005)
+ Work improved, more players added
+ Default macro processing added
+ Fix some bugs
+ FooBar without Winamp wrapper supported (not full)
+ MP3 tag v1 partial support added
+0.0.0.3 (12 sep 2005)
+ New option interface
+ New engine for many player support
+ Macro support added
+0.0.0.1 (07 sep 2005)
+ First release
diff --git a/plugins/Watrack/docs/watrack_readme.txt b/plugins/Watrack/docs/watrack_readme.txt
new file mode 100644
index 0000000000..ef2ec81e98
--- /dev/null
+++ b/plugins/Watrack/docs/watrack_readme.txt
@@ -0,0 +1,110 @@
+For what:
+ Insert Played music info in message window or Status text. ICQ extended
+ status supported.
+
+Requirements:
+ Windows 2K/XP (SP2 better)
+ Miranda 0.6.x
+
+Supported Players:
+ Winamp (http://www.winamp.com/)
+ Apollo (http://www.iki.fi/hy/apollo/)
+ 1by1 (http://www.mpesch3.de/)
+ Media Player Classic (http://gabest.org/)
+ Window Media Player (http://www.microsoft.com/windows/windowsmedia/players.aspx)
+ FooBar2000 (http://www.foobar2000.org/)
+ LightAlloy (http://www.softella.com/)
+ Cowon JetAudio (http://www.jetaudio.com/)
+ Quintessential Player (http://quinnware.com/)
+ iTunes (http://www.itunes.com/)
+ MediaMonkey (http://www.mediamonkey.com/)
+ Real Player (http://www.real.com/)
+ MusikCube (http://www.musikcube.com/)
+ BSPlayer (http://www.bsplayer.org/)
+ MusicCube One (http://www.rodi.dk/musiccubeone)
+ Zoom Player (http://www.inmatrix.com/)
+ Pluton (http://pluton.oss.ru/)
+ J. River Media Center (http://www.jrmediacenter.com/)
+ Musicmatch Jukebox (http://wwwp.musicmatch.com/)
+ VideoLAN media player (http://www.videolan.org/)
+ mRadio miranda plugin (http://miranda.kom.pl/dev/bankrut/)
+ ALSong&ALShow (http://www.altools.net/)
+
+ and others. List of other players see in player.ini
+
+Supported Formats:
+ MP3, OGG, WMA, WAV, APE, TTA, AAC, FLA/FLAC, MPC, OFR/OFS, SPX, MP4, M4A,
+ ASF, WMV, AVI, MKV, OGM, RA/RM/RAM, FLV, MOV, 3GP, MPEG/MPG
+
+In Chat (and maybe message) window, you can use text formatting:
+{b}text{/b} - 'bold' text
+{i}text{/i} - 'italic' text
+{u}text{/u} - 'undeline' text
+{cf##}text{/cf} - text with color ## (0-15)
+{bg##}text{/bg} - text with background color ## (0-15)
+Sample:/me {b}listen{/b} {cf5}{i}%artist%{/i}{/cf} - {bg10}{u}"%title%"{/u}{/bg}
+
+Macros:
+ %album% - album
+ %artist% - artist
+ %bitrate% - bitrate
+ %channels% - number of channels
+ %codec% - video codec like 0x30355844 (DX50)
+ %comment% - comment from tag
+ %cover% - cover file name
+ %file% - media file name
+ %fps% - 100*FPS (Frames Per Second) for video files
+ %height% - video height in pixels
+ %genre% - genre
+ %kbps% - bitrate
+ %khz% - samplerate
+ %length% - total song length (sec)
+ %lyric% - lyric text
+ %mono% - "mono"/"stereo"
+ %nstatus%' - player status (stopped,playing,paused) - nontranslated
+ %percent% - %time% / %total% * 100%
+ %player% - player
+ %samplerate% - samplerate
+ %size% - media file size
+ %status%' - player status (stopped,playing,paused)
+ %time% - current song position (sec)
+ %title% - song title
+ %total% - total song length (sec)
+ %track% - track number
+ %txtver% - player version in text format
+ %type% - media file type (extension)
+ %vbr% - 'VBR' if VBR :)
+ %version% - player version
+ %width% - video width in pixels
+ %wndtext% - title from player window (usually "artist" - "title")
+ %year% - song year (from tag)
+
+Notes:
+ - Volume field has a original volume value in hiword and scaled to 0-15 range
+ in loword. Not all players supported.
+ - Frame background picture transparence is not implemented
+ - To obtain more information from foobar2000 player, you must download plugin
+ http://foosion.foobar2000.org/0.9/foo_comserver2-0.7-setup.exe
+ or use foo_winampspam plugin
+ - FileInfo (called from popup) not shows Video file properties
+ - FPS saves as FPS*100
+ - Frame text output is Left-to-Right only now
+
+Known BUGs:
+ - if Frame text uses %time% macro, text can't scroll
+ - Foobar seeking with foo_winamp_spam may not work
+ - Miranda can freeze if Foobar OLE interface used
+ - Player can start again if OLE checks while it shutdown
+ - ICQLite and ICQ2003 users cannot see XStatus text changes
+ - in MP3 with VBR total song time sometime is not properly calculated
+ - default color of formated text is color of text at insert position
+ - some macros don't work with some players. Replaced by '' and 0
+ - 1by1 player can show wrong elapsed time value
+ - some players version not properly displayed
+ - bad MP3 headers not properly handled
+ - plugin can show wrong song when Player scans directory for music files
+
+PS. To compile plugin you must use something like this:
+ dcc32 -$A+ -$H+ watrack.dpr
+
+All comments, errors & wishes please send to awkward@land.ru or panda75@bk.ru
diff --git a/plugins/Watrack/formats/fmt_aac.pas b/plugins/Watrack/formats/fmt_aac.pas
new file mode 100644
index 0000000000..db8e03b153
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_aac.pas
@@ -0,0 +1,93 @@
+{AAC file process}
+unit fmt_AAC;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadAAC(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format;
+
+const
+ SampleRates:array [0..15] of dword = (
+ 96000,88200,64000,48000,44100,32000,24000,22050,
+ 16000,12000,11025,8000,0,0,0,0);
+
+procedure ReadADIFheader(f:THANDLE;var Info:tSongInfo);
+var
+ buf:array [0..29] of byte;
+ bs,sf_idx,skip:dword;
+begin
+ BlockRead(f,buf,30);
+ if (buf[0] and $80)<>0 then
+ skip:=9
+ else
+ skip:=0;
+ Info.kbps:=(((buf[0+skip] and $0F) shl 19)+(buf[1+skip] shl 11)+
+ (buf[2+skip] shl 3)+{or}((buf[3+skip] and $E0){shr 5})) div 1000;
+ bs:=buf[0+skip] and $10;
+ if bs=0 then
+ sf_idx:=(buf[7+skip] and $78) shr 3
+ else
+ sf_idx:=((buf[4+skip] and $07) shl 1)+((buf[5+skip] and $80) shr 7);
+ Info.khz:=SampleRates[sf_idx];
+end;
+
+procedure ReadADTSheader(var Info:tSongInfo;sign:dword);
+type
+ l2b=record
+ b:array [0..3] of byte;
+ end;
+var
+ sr_idx:integer;
+begin
+ Info.channels:=((l2b(sign).b[2] and $01) shl 2)+
+ ((l2b(sign).b[3] and $C0) shr 6);
+ sr_idx:=(l2b(sign).b[2] and $3C) shr 2;
+ Info.khz:=SampleRates[sr_idx] div 1000;
+end;
+
+function ReadAAC(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ sign:dword;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ ReadID3v2(f,Info);
+ BlockRead(f,sign,4);
+ Info.khz:=44;
+ Info.kbps:=128;
+ Info.channels:=2;
+ if (lobyte(sign)=$FF) and ((hibyte(sign) and $F6)=$F0) then
+ ReadADTSheader(Info,sign)
+ else if sign=$46494441 then // 'ADIF'
+ ReadADIFheader(f,Info);
+
+ ReadAPEv2(f,Info);
+ ReadID3v1(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLink:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLink.Next:=FormatLink;
+
+ LocalFormatLink.This.proc :=@ReadAAC;
+ LocalFormatLink.This.ext :='AAC';
+ LocalFormatLink.This.flags:=0;
+
+ FormatLink:=@LocalFormatLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_ape.pas b/plugins/Watrack/formats/fmt_ape.pas
new file mode 100644
index 0000000000..fbabdac19c
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_ape.pas
@@ -0,0 +1,137 @@
+{APE file}
+unit fmt_APE;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadAPE(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+
+uses windows,common,io,tags,srv_format;
+
+const
+ defID = $2043414D;
+type
+(* Old Version ?
+ tMonkeyHeader = record
+ ID :dword; { Always "MAC " }
+ VersionID :word; { Version number * 1000 (3.91 = 3910) }
+ CompressionID :word; { Compression level code }
+ Flags :word; { Any format flags }
+ Channels :word; { Number of channels }
+ SampleRate :dword; { Sample rate (hz) }
+ HeaderBytes :dword; { Header length (without header ID) }
+ TerminatingBytes:dword; { Extended data }
+ Frames :dword; { Number of frames in the file }
+ FinalSamples :dword; { Number of samples in the final frame }
+ PeakLevel :dword; { Peak level (if stored) }
+ SeekElements :dword; { Number of seek elements (if stored) }
+ end;
+*)
+ tMonkeyHeader = packed record
+ ID :dword; // should equal 'MAC '
+ VersionID :dword; // version number * 1000 (3.81 = 3810)
+ nDescriptorBytes :dword; // descriptor bytes
+ nHeaderBytes :dword; // APEHeader bytes
+ nSeekTableBytes :dword; // bytes of the seek table
+ nHeaderDataBytes :dword; // header data bytes (from original file)
+ nFrameDataBytes :dword; // bytes of APE frame data
+ nFrameDataBytesHi:dword; // the high order number of APE frame data bytes
+ nTerminatingBytes:dword; // the terminating data of the file (w/o tag data)
+ cFileMD5:array [0..15] of byte;
+ end;
+type
+ tAPEHeader = packed record
+ nCompressionLevel:word; // the compression level
+ nFormatFlags :word; // any format flags (for future use)
+ nBlocksPerFrame :dword; // the number of audio blocks in one frame
+ nFinalFrameBlocks:dword; // the number of audio blocks in the final frame
+ nTotalFrames :dword; // the total number of frames
+ nBitsPerSample :word; // the bits per sample (typically 16)
+ nChannels :word; // the number of channels (1 or 2)
+ nSampleRate :dword; // the sample rate (typically 44100)
+ end;
+
+const
+ MONKEY_COMPRESSION_FAST = 1000; // Fast (poor)
+ MONKEY_COMPRESSION_NORMAL = 2000; // Normal (good)
+ MONKEY_COMPRESSION_HIGH = 3000; // High (very good)
+ MONKEY_COMPRESSION_EXTRA_HIGH = 4000; // Extra high (best)
+const
+ MONKEY_FLAG_8_BIT = 1; // Audio 8-bit
+ MONKEY_FLAG_CRC = 2; // New CRC32 error detection
+ MONKEY_FLAG_PEAK_LEVEL = 4; // Peak level stored
+ MONKEY_FLAG_24_BIT = 8; // Audio 24-bit
+ MONKEY_FLAG_SEEK_ELEMENTS = 16; // Number of seek elements stored
+ MONKEY_FLAG_WAV_NOT_STORED = 32; // WAV header not stored
+
+function ReadAPE(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ hdr:tMonkeyHeader;
+ hdr1:tAPEHeader;
+ blocks:dword;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ ReadID3v2(f,Info);
+ BlockRead(f,hdr ,SizeOf(tMonkeyHeader));
+ BlockRead(f,hdr1,SizeOf(tAPEHeader)); //hdr.nHeaderBytes
+ if hdr1.nTotalFrames=0 then
+ blocks:=0
+ else
+ blocks:=(hdr1.nTotalFrames-1)*hdr1.nBlocksPerFrame+hdr1.nFinalFrameBlocks;
+ Info.khz :=hdr1.nSampleRate div 1000;
+ if hdr1.nSampleRate<>0 then
+ Info.total :=blocks div hdr1.nSampleRate;
+ Info.channels:=hdr1.nChannels;
+// Info.kbps:=Info.khz*deep*Info.channels/1152
+// Info.kbps:=(blocks*Info.channels*hdr1.nBitsPerSample) div (Info.total*8000);
+// Info.kbps :=((hdr1.nBitsPerSample div 8)*hdr1.nSamplerate) div 1000;
+(* Old version ?
+ if (hdr.ID<>DefID) or (hdr.SampleRate=0) or (hdr.Channels=0) then
+ exit;
+ if (hdr.VersionID>=3900) or
+ ((hdr.VersionID>=3800) and
+ (hdr.CompressionID=MONKEY_COMPRESSION_EXTRA_HIGH)) then
+ tmp:=73728
+ else
+ tmp:=9216;
+ tmp:=(hdr.Frames-1)*tmp+hdr.FinalSamples;
+ Info.total :=tmp div hdr.SampleRate;
+ Info.khz :=hdr.SampleRate div 1000;
+ Info.channels:=hdr.Channels;
+
+ Info.kbps:=tmp;//samples
+ if (hdr.Flags and MONKEY_FLAG_8_BIT)<>0 then tmp:=8
+ else if (hdr.Flags and MONKEY_FLAG_24_BIT)<>0 then tmp:=24
+ else tmp:=16;
+ Info.kbps:=((Info.kbps*tmp*hdr.Channels) div Info.Total) div 1000;
+*)
+ ReadAPEv2(f,Info);
+ ReadID3v1(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLink:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLink.Next:=FormatLink;
+
+ LocalFormatLink.This.proc :=@ReadAPE;
+ LocalFormatLink.This.ext :='APE';
+ LocalFormatLink.This.flags:=0;
+
+ FormatLink:=@LocalFormatLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_avi.pas b/plugins/Watrack/formats/fmt_avi.pas
new file mode 100644
index 0000000000..3646236cf7
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_avi.pas
@@ -0,0 +1,295 @@
+{AVI file format}
+unit fmt_AVI;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadAVI(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,srv_format;
+
+type
+ FOURCC = array [0..3] of AnsiChar;
+type
+ tChunkHeader = packed record
+ case byte of
+ 0: (Lo,Hi:dword); {Common}
+ 1: (ID:FOURCC; {RIFF}
+ Length:dword);
+ end;
+
+const
+ sRIFF = $46464952;
+ sLIST = $5453494C;
+ savih = $68697661; { avi header }
+ sstrf = $66727473; { stream format }
+ sstrh = $68727473; { stream header }
+const
+ smovi = $69766F6D; {movi list type}
+const
+ svids = $73646976; {video}
+ sauds = $73647561; {audio}
+const
+ sIART = $54524149; {director}
+ sICMT = $544D4349; {comment}
+ sICRD = $44524349; {creation date}
+ sIGNR = $524E4749; {genre}
+ sINAM = $4D414E49; {title}
+ sIPRT = $54525049; {part}
+ sIPRO = $4F525049; {produced by}
+ sISBJ = $4A425349; {subject description}
+
+type
+ tWaveFormatEx = packed record
+ wFormatTag :word;
+ nChannels :word;
+ nSamplesPerSec :dword;
+ nAvgBytesPerSec:dword;
+ nBlockAlign :word;
+ wBitsPerSample :word;
+ cbSize :word;
+
+ Reserved1 :word;
+ wID :word;
+ fwFlags :word;
+ nBlockSize :word;
+ nFramesPerBlock:word;
+ nCodecDelay :word; {ms}
+ end;
+
+type
+ tMainAVIHeader = packed record {avih}
+ dwMicroSecPerFrame :dword;
+ dwMaxBytesPerSec :dword;
+ dwPaddingGranularity :dword;
+ dwFlags :dword;
+ dwTotalFrames :dword; { # frames in first movi list}
+ dwInitialFrames :dword;
+ dwStreams :dword;
+ dwSuggestedBufferSize:dword;
+ dwWidth :dword;
+ dwHeight :dword;
+ dwScale :dword;
+ dwRate :dword;
+ dwStart :dword;
+ dwLength :dword;
+ end;
+
+type
+ TAVIExtHeader = packed record {dmlh}
+ dwGrandFrames:dword; {total number of frames in the file}
+ dwFuture:array[0..60] of dword;
+ end;
+
+type
+ tAVIStreamHeader = packed record {strh}
+ fccType :FOURCC; {vids|auds}
+ fccHandler :FOURCC;
+ dwFlags :dword;
+ wPriority :word;
+ wLanguage :word;
+ dwInitialFrames :dword;
+ dwScale :dword;
+ dwRate :dword;
+ dwStart :dword;
+ dwLength :dword;
+ dwSuggestedBufferSize:dword;
+ dwQuality :dword;
+ dwSampleSize :dword;
+ rcFrame: packed record
+ left :word;
+ top :word;
+ right :word;
+ bottom:word;
+ end;
+ end;
+
+var
+ vora:dword;
+
+procedure Skip(f:THANDLE;bytes:dword);
+var
+ i:dword;
+begin
+ i:=FilePos(f);
+ if bytes=0 then
+ begin
+ if odd(i) then
+ Seek(f,i+1);
+ end
+ else
+ Seek(f,i+bytes+(bytes mod 2));
+end;
+
+procedure ProcessVideoFormat(f:THANDLE;Size:dword;var Info:tSongInfo);
+var
+ bih:BitmapInfoHeader;
+begin
+ BlockRead(f,bih,SizeOf(bih));
+ Info.codec :=bih.biCompression;
+ Info.width :=bih.biWidth;
+ Info.height:=bih.biHeight;
+ Skip(f,Size-SizeOf(bih));
+end;
+
+procedure ProcessAudioFormat(f:THANDLE;Size:dword;var Info:tSongInfo);
+{WAVEFORMATEX or PCMWAVEFORMAT}
+var
+ AF:tWaveFormatEx;
+begin
+ BlockRead(f,AF,SizeOf(AF));
+ Info.channels:=AF.nChannels;
+ Info.khz :=AF.nSamplesPerSec div 1000;
+ Info.kbps :=(AF.nAvgBytesPerSec*8) div 1000;
+ Skip(f,Size-SizeOf(AF));
+end;
+
+function ProcessASH(f:THANDLE;var Info:tSongInfo):dword;
+var
+ ASH:tAVIStreamHeader;
+begin
+ BlockRead(f,ASH,SizeOf(ASH));
+ with ASH do
+ begin
+ if dword(fccType)=svids then
+ begin
+ if ASH.dwScale<>0 then
+ Info.fps:=(ASH.dwRate*100) div ASH.dwScale;
+ if Info.fps<>0 then
+ Info.total:=(ASH.dwLength*100) div Info.fps;
+ ProcessASH:=1
+ end
+ else if dword(fccType)=sauds then ProcessASH:=2
+ else ProcessASH:=0;
+ end;
+end;
+
+procedure ProcessMAH(f:THANDLE;var Info:tSongInfo);
+var
+ MAH:tMainAVIHeader;
+begin
+ BlockRead(f,MAH,SizeOf(MAH));
+// Info.width:=MAH.dwWidth;
+// Info.height:=MAH.dwHeight;
+// Info.fps:=100000000 div MAH.dwMicroSecPerFrame;
+end;
+
+function ProcessChunk(f:THANDLE;var Info:tSongInfo):dword;
+var
+ lTotal:dword;
+ Chunk:tChunkHeader;
+ cType:FOURCC;
+ ls:PAnsiChar;
+begin
+ Skip(f,0);
+ if (BlockRead(f,Chunk,SizeOF(Chunk))=0) or (Chunk.Lo=0) then
+ begin
+ result:=FileSize(f);
+ Seek(f,FileSize(f));
+ exit;
+ end;
+ result:=Chunk.Length+SizeOf(Chunk);
+ case Chunk.Lo of
+ sRIFF,sLIST: begin
+ BlockRead(f,cType,SizeOf(cType));
+ if dword(cType)=smovi then
+ Skip(f,Chunk.Length-SizeOf(cType)) // result:=FileSize(f)
+ else
+ begin
+ lTotal:=SizeOf(FOURCC);
+ while lTotal<Chunk.Length do
+ inc(lTotal,ProcessChunk(f,Info));
+ end;
+ end;
+ sIART,sICMT,sICRD,sIGNR,sINAM,sIPRT,sIPRO,sISBJ: begin
+ mGetMem(ls,Chunk.Length);
+ BlockRead(f,ls^,Chunk.Length);
+ case Chunk.Lo of
+ sIART: begin
+ AnsiToWide(ls,Info.artist);
+ end;
+ sICMT: begin
+ if Info.comment=NIL then
+ AnsiToWide(ls,Info.comment);
+ end;
+ sICRD: begin
+ AnsiToWide(ls,Info.year);
+ end;
+ sIGNR: begin
+ AnsiToWide(ls,Info.genre);
+ end;
+ sINAM: begin
+ AnsiToWide(ls,Info.title);
+ end;
+ sIPRT: begin
+ Info.track:=StrToInt(ls);
+ end;
+ sIPRO: begin
+ if Info.artist=NIL then
+ AnsiToWide(ls,Info.artist);
+ end;
+ sISBJ: begin
+ AnsiToWide(ls,Info.comment);
+ end;
+ end;
+ mFreeMem(ls);
+ end;
+ savih: begin
+ ProcessMAH(f,Info);
+ end;
+ sstrh: begin
+ vora:=ProcessASH(f,Info);
+ end;
+ sstrf: begin
+ case vora of
+ 1: ProcessVideoFormat(f,Chunk.Hi,Info);
+ 2: ProcessAudioFormat(f,Chunk.Hi,Info);
+ else
+ end;
+ end;
+ else
+ Skip(f,Chunk.Length);
+ end;
+end;
+
+function ReadAVI(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ ProcessChunk(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLinkAVI,
+ LocalFormatLinkDIVX:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkAVI.Next:=FormatLink;
+
+ LocalFormatLinkAVI.This.proc :=@ReadAVI;
+ LocalFormatLinkAVI.This.ext :='AVI';
+ LocalFormatLinkAVI.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkAVI;
+
+ LocalFormatLinkDIVX.Next:=FormatLink;
+
+ LocalFormatLinkDIVX.This.proc :=@ReadAVI;
+ LocalFormatLinkDIVX.This.ext :='DIVX';
+ LocalFormatLinkDIVX.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkDIVX;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_dummy.pas b/plugins/Watrack/formats/fmt_dummy.pas
new file mode 100644
index 0000000000..e691def279
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_dummy.pas
@@ -0,0 +1,46 @@
+{OFR file}
+unit fmt_Dummy;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadDummy(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format;
+
+function ReadDummy(var Info:tSongInfo):boolean; cdecl;
+{
+var
+ f:THANDLE;
+}
+begin
+{
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+
+ CloseHandle(f);
+}
+ result:=true;
+end;
+
+var
+ LocalFormatLinkCUE:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkCUE.Next:=FormatLink;
+
+ LocalFormatLinkCUE.This.proc :=@ReadDummy;
+ LocalFormatLinkCUE.This.ext :='CUE';
+ LocalFormatLinkCUE.This.flags:=WAT_OPT_CONTAINER;
+
+ FormatLink:=@LocalFormatLinkCUE;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_flv.pas b/plugins/Watrack/formats/fmt_flv.pas
new file mode 100644
index 0000000000..b8e23f5809
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_flv.pas
@@ -0,0 +1,334 @@
+{FLV file format}
+unit fmt_FLV;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadFLV(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,srv_format;
+
+type
+ tFLVHeader = packed record
+ Signature:array [0..2] of AnsiChar; // FLV
+ Version :byte;
+ flags :byte;
+ Offset :dword; // reversed byte order
+ end;
+type
+ tFLVStream = packed record
+ PreviousTagSize :dword;
+ TagType :byte;
+ BodyLength :array [0..2] of byte;
+ Timestamp :array [0..2] of byte;
+ TimestampExtended:byte;
+ StreamID :array [0..2] of byte;
+// Body
+ end;
+{
+ twork = record
+ endptr:PAnsiChar;
+ Info :pSongInfo;
+ key :PAnsiChar;
+ len :cardinal;
+ end;
+}
+// FLVTagTypes
+const
+ FLV_AUDIO = 8;
+ FLV_VIDEO = 9;
+ FLV_META = 18;
+
+const
+ BufSize = 128*1024;
+
+type
+ pArr = ^tArr;
+ tArr = array [0..7] of byte;
+
+ transform=packed record
+ case byte of
+ 0: (txt:array [0..3] of AnsiChar);
+ 1: (num:dword);
+ end;
+ trecode=packed record
+ case byte of
+ 0: (i:int64);
+ 1: (d:double);
+ end;
+
+function Reverse(buf:int64;len:integer):int64;
+var
+ i:integer;
+begin
+ result:=0;
+ for i:=0 to len-1 do
+ result:=(result shl 8)+tArr(buf)[i];
+end;
+
+function ProcessValue(var ptr:PAnsiChar;key:pAnsiChar;var Info:tSongInfo):integer;
+var
+ tmp:int64;
+ i,len:integer;
+ recode:trecode;
+ code:integer;
+ codec:transform;
+ value:array [0..63] of AnsiChar;
+begin
+ result:=1;
+ code:=ord(ptr^); // type of value
+ ptr^:=#0; // finalization for key name
+ inc(ptr); // value data pointer
+
+ case code of // v10.1 specification
+
+ // Numeric, Double (8 bytes)
+ 0: begin
+ move(ptr^,tmp,8);
+ recode.i:=Reverse(tmp,8);
+ i:=trunc(recode.d);
+ if StrCmp(key,'duration' )=0 then Info.total :=i
+ else if StrCmp(key,'totalduration')=0 then Info.total :=i
+ else if StrCmp(key,'width' )=0 then Info.width :=i
+ else if StrCmp(key,'height' )=0 then Info.height:=i
+ else if StrCmp(key,'audiodatarate')=0 then Info.kbps :=i
+ else if StrCmp(key,'framerate' )=0 then Info.fps :=trunc(recode.d*100)
+ else if StrCmp(key,'audiosize' )=0 then
+ begin
+ if Info.kbps=0 then
+ Info.kbps:=trunc((recode.d*8)/(Info.total*1000))
+ end
+ else if StrCmp(key,'videocodecid')=0 then
+ begin
+ case i of
+ 2: codec.txt:='H263';
+ 3: codec.txt:='Scrn';
+ 4,5: codec.txt:='VP6 ';
+ 6: codec.txt:='Src2';
+ 7: codec.txt:='AVC ';
+ end;
+ Info.codec:=codec.num;
+ end;
+
+ inc(ptr,8);
+ end;
+
+ // Boolean, UI8
+ 1: begin
+ if StrCmp(key,'stereo')=0 then Info.channels:=ORD(ptr^)+1;
+
+ inc(ptr);
+ end;
+
+ // String
+ 2: begin
+ i:=Reverse(pWord(ptr)^,2); inc(ptr,2);
+
+ if StrCmp(key,'creationdate')=0 then
+ begin
+ move(ptr^,value[0],i);
+ value[i]:=#0;
+ AnsiToWide(value,Info.year);
+ end;
+
+ inc(ptr,i);
+ end;
+
+ // Object
+ 3: begin
+ repeat
+ len:=Reverse(pWord(ptr)^,2); inc(ptr,2); // key name length
+ key:=ptr; inc(ptr,len); // key name
+
+ result:=ProcessValue(ptr,key,Info);
+ until result<=0;
+
+ if result<0 then
+ result:=1;
+ end;
+
+ // Movie clip, reserved
+ 4: begin
+ end;
+
+ // NULL
+ 5: begin
+ end;
+
+ // Undefined
+ 6: begin
+ end;
+
+ // reference, UI16
+ 7: begin
+ inc(ptr,2);
+ end;
+
+ // ECMA array
+ 8: begin
+ i:=pdword(ptr)^; inc(ptr,4);
+ i:=Reverse(i,4);
+ while i>0 do
+ begin
+
+ len:=Reverse(pWord(ptr)^,2); inc(ptr,2); // key name length
+ key:=ptr; inc(ptr,len); // key name
+
+ result:=ProcessValue(ptr,key,Info);
+
+ if result=0 then break
+ else if result<0 then
+ begin
+ result:=1;
+ break;
+ end;
+ dec(i);
+ end;
+ end;
+
+ // Object end marker, UI8[3]=0,0,9
+ 9: begin
+ result:=-1;
+ inc(ptr,3);
+ end;
+
+ 10: // array, 4 bytes - num of elements, elements
+ begin
+ i:=pdword(ptr)^; inc(ptr,4);
+ i:=Reverse(i,4);
+ while i>0 do
+ begin
+ result:=ProcessValue(ptr,nil,Info);
+ if result=0 then exit
+ else if result<0 then
+ begin
+ result:=1;
+ break;
+ end;
+ dec(i);
+ end;
+ end;
+
+ // Date, Double + UI16 (UTC)
+ 11: begin
+ inc(ptr,8);
+ inc(ptr,2);
+ end;
+
+ // LongString, 4 bytes = len, len - string
+ 12: begin
+ i:=pdword(ptr)^; inc(ptr,4);
+ i:=Reverse(i,4);
+
+ inc(ptr,i);
+ end;
+
+ end;
+end;
+
+function ReadFLV(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ codec:transform;
+ FLVHdr:tFLVHeader;
+ StrmHdr:tFLVStream;
+ i,len:integer;
+ buf,pp,p,endbuf:PAnsiChar;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+
+ mGetMem(buf,BufSize);
+ endbuf:=buf+BlockRead(f,buf^,BufSize);
+ p:=buf;
+ CloseHandle(f);
+ move(p^,FLVHdr,SizeOf(tFLVHeader));
+ if (FLVHdr.Signature[0]='F') and (FLVHdr.Signature[1]='L') and
+ (FLVHdr.Signature[2]='V') and (FLVHdr.Version=1) then
+ begin
+ inc(p,SizeOf(tFLVHeader));
+ result:=true;
+ while (p<endbuf) and ((FLVHdr.flags and 5)<>0) do
+ begin
+ move(p^,StrmHdr,SizeOf(tFLVStream));
+ inc(p,SizeOf(tFLVStream));
+ len:=(StrmHdr.BodyLength[0] shl 16)+(StrmHdr.BodyLength[1] shl 8)+
+ StrmHdr.BodyLength[2];
+ pp:=p;
+ case StrmHdr.TagType of
+
+ FLV_AUDIO: begin
+ Info.channels:=(ord(p^) and 1)+1;
+ // samplesize is (S_Byte and 2) shr 1 = 8 or 16
+ case (ord(p^) and $C) shr 2 of
+ 0: Info.khz:=5;
+ 1: Info.khz:=11;
+ 2: Info.khz:=22;
+ 3: Info.khz:=44;
+ end;
+ FLVHdr.flags:=FLVHdr.flags and not 4;
+ end;
+
+ FLV_VIDEO: begin
+ case ord(p^) and $0F of
+ 2: codec.txt:='H263';
+ 3: codec.txt:='Scrn';
+ 4,5: codec.txt:='VP6 ';
+ 6: codec.txt:='Src2';
+ 7: codec.txt:='AVC ';
+ end;
+ Info.codec:=codec.num;
+ FLVHdr.flags:=FLVHdr.flags and not 1;
+ end;
+
+ FLV_META: begin
+ if (StrmHdr.TagType and $40)=0 then // not encripted
+ begin
+ if pByte(p)^=2 then // string
+ begin
+ Inc(p);
+ i:=Reverse(pWord(p)^,2); inc(p,2);
+ if StrCmp(p,'onMetaData',i)=0 then // Metadata processing start
+ begin
+ inc(p,i);
+ ProcessValue(p,nil,Info); // metadata, no need key name, our info
+ // checking for video
+ if Info.codec<>0 then
+ FLVHdr.flags:=FLVHdr.flags and not 1;
+ // checking for audio
+ if (Info.khz<>0) and (Info.channels<>0) then
+ FLVHdr.flags:=FLVHdr.flags and not 4;
+ // break; // if metainfo is enough
+ end;
+ end;
+ end;
+ end;
+
+ end;
+ p:=pp+len;
+ end;
+ end;
+ mFreeMem(buf);
+end;
+
+var
+ LocalFormatLink:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLink.Next:=FormatLink;
+
+ LocalFormatLink.This.proc :=@ReadFLV;
+ LocalFormatLink.This.ext :='FLV';
+ LocalFormatLink.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_m4a.pas b/plugins/Watrack/formats/fmt_m4a.pas
new file mode 100644
index 0000000000..1bfcf2309a
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_m4a.pas
@@ -0,0 +1,378 @@
+{M4A code template}
+unit fmt_M4A;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadM4A(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+
+uses windows,common,io,srv_format,
+{$IFDEF KOL_MCK}KolZlibBzip{$ELSE}Zlib,zwrapper{$ENDIF};
+
+type
+ mp4Atom = record
+ len:dword;
+ name:dword;
+ end;
+
+const
+ at_moov = $766F6F6D;
+ at_mvhd = $6468766D;
+ at_udta = $61746475;
+ at_meta = $6174656D;
+ at_ilst = $74736C69;
+ at_cmov = $766F6D63;
+ at_dcom = $6D6F6364;
+ at_cmvd = $64766D63; // 4 - unpacked size, data
+ at_trak = $6B617274;
+ at_tkhd = $64686B74; // not needed
+ at_mdia = $6169646D;
+ at_minf = $666E696D;
+ at_smhd = $64686D73;
+ at_vmhd = $64686D76;
+ at_stbl = $6C627473;
+ at_stsd = $64737473;
+
+const
+ atm_nam = $6D616EA9; // title
+ atm_ART = $545241A9; // artist
+ atm_wrt = $747277A9; // writer
+ atm_alb = $626C61A9; // album
+ atm_day = $796164A9; // date
+ atm_cmt = $746D63A9; // comment
+ atm_gen = $6E6567A9; // alt.genre
+ atm_gnre = $65726E67; // genre
+ atm_trkn = $6E6B7274; // track number
+// atm_zlib = $62696C7A;
+
+type
+ pstsd = ^tstsd;
+ tstsd = packed record
+ version :byte;
+ flags :array [0..2] of byte;
+ NumEntries :dword;
+ SampleDescSize:dword; // $56
+ DataFormat :dword;
+ reserved :array [0..5] of byte;
+ RefIndex :word;
+ Ver :word;
+ Revision :word;
+ Vendor :dword;
+ Temporal :dword;
+ Spacial :dword;
+ Width :word;
+ Height :word;
+ HRes :dword; //single;
+ VRes :dword;
+ DataSize :dword;
+ FrameCount :word;
+ CompNameLen :byte;
+ Compressor :array [0..18] of AnsiChar;
+ ColorDepth :word;
+ ColorTableID :word;
+ end;
+ pastsd = ^astsd;
+ astsd = packed record
+ Version :byte;
+ Flags :array [0..2] of byte;
+ NumEntires :dword;
+ DescSize :dword;
+ CodingName :array[0..3] of AnsiChar;
+ Reserved :array[0..5] of Byte;
+ RefIndex :Word;
+ Reserved_ :array[0..1] of dword;
+ ChannelCount:Word;
+ SampleSize :Word;
+ Pre_defined :Word;
+ Reserved___ :Word;
+ Samplerate :dword;
+ end;
+ pmvhd = ^mvhd;
+ mvhd = packed record
+ Version:byte;
+ flags:array [0..2] of byte;
+ Creation:dword;
+ Modification:dword;
+ TimeScale:dword;
+ Duration:dword;
+ end;
+
+procedure ReadAtom(f:THANDLE;var atom:mp4Atom);
+begin
+ BlockRead(f,atom.len,4);
+ if atom.len>0 then
+ begin
+ BlockRead(f,atom.name,4);
+ atom.len:=BSwap(atom.len);
+ end
+ else
+ begin
+ atom.name:=0;
+ atom.len:=8;
+ end;
+end;
+
+procedure GetAtom(var p:pbyte;var atom:mp4Atom);
+begin
+ atom.len:=pdword(p)^;
+ inc(p,4);
+ if atom.len>0 then
+ begin
+ atom.name:=pdword(p)^;
+ inc(p,4);
+ atom.len:=BSwap(atom.len);
+ end
+ else
+ begin
+ atom.name:=0;
+ atom.len:=8;
+ end;
+end;
+
+function SetTree(from:mp4Atom;var p:pbyte;path:PAnsiChar;var parent:pbyte):integer;
+var
+ atom:mp4Atom;
+ len:cardinal;
+ saved:pbyte;
+begin
+ saved:=p;
+ len:=0;
+ dec(from.len,SizeOf(from));
+ parent:=p;
+ repeat
+ GetAtom(p,atom);
+ if atom.name=pdword(path)^ then
+ begin
+ inc(path,4);
+ if path^<>#0 then
+ begin
+ parent:=p;
+ inc(path);
+ len:=0;
+ from.len:=atom.len-SizeOf(atom);
+ end
+ else
+ begin
+ result:=atom.len;
+ exit;
+ end;
+ end
+ else
+ begin
+ inc(p,atom.len-SizeOf(atom));
+ inc(len,atom.len);
+ end;
+ until len>=from.len;
+ result:=-1;
+ p:=saved;
+end;
+
+function ReadInt(var p:pbyte):dword;
+var
+ len:integer;
+begin
+ len:=pdword(p)^;
+ inc(p,4);
+ len:=BSwap(len);
+ if len>0 then
+ inc(p,4); // 'data'
+ inc(p,4); // type?
+ inc(p,4); // encoding?
+ dec(len,8+8);
+ if len>4 then len:=4;
+ if len=2 then
+ begin
+ result:=p^*$100;
+ inc(p);
+ inc(result,p^);
+ inc(p);
+ end
+ else
+ begin
+ result:=BSwap(pdword(p)^);
+ inc(p,4);
+ end;
+end;
+
+procedure ReadProp(var p:pbyte;var prop:pWideChar);
+var
+ len:integer;
+ ltmp:PAnsiChar;
+ c:byte;
+begin
+ len:=pdword(p)^;
+ inc(p,4);
+ len:=BSwap(len);
+ if len>0 then
+ inc(p,4); // 'data'
+ inc(p,4); // type?
+ inc(p,4); // encoding?
+ dec(len,8+8);
+ ltmp:=pointer(p);
+ inc(p,len);
+ c:=p^;
+ p^:=0;
+ UTF8ToWide(ltmp,prop);
+ p^:=c;
+end;
+
+function ReadM4A(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ atom:mp4Atom;
+ cursize,parentsize:integer;
+ par,buf,p,pn,finish:pbyte;
+ size:integer;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ cursize:=0;
+ parentsize:=FileSize(f);
+ repeat
+ ReadAtom(f,atom);
+ if atom.name=at_moov then
+ begin
+ mGetMem(buf,atom.len);
+ BlockRead(f,buf^,atom.len);
+ p:=buf;
+ finish:=pByte(PAnsiChar(p)+atom.len-SizeOf(atom));
+ repeat
+ GetAtom(p,atom);
+ pn:=PByte(PAnsiChar(p)+atom.len-SizeOf(atom));
+
+ if atom.name=at_cmov then
+ begin
+ size:=SetTree(atom,p,'cmvd',par);
+ if size>0 then
+ begin
+ ZDecompressBuf(PAnsiChar(p)+4,size-SizeOf(mp4Atom),
+ pointer(pn),size,BSwap(pdword(p)^));
+ mFreeMem(buf);
+ buf:=pn;
+ p:=buf;
+ GetAtom(p,atom); //must be 'moov'
+ finish:=PByte(PAnsiChar(p)+atom.len-SizeOf(atom));
+ continue;
+ end;
+ end;
+
+ if atom.name=at_mvhd then
+ begin
+ if pmvhd(p)^.TimeScale<>0 then
+ Info.total:=BSwap(pmvhd(p)^.Duration) div BSwap(pmvhd(p)^.TimeScale);
+ end;
+ if atom.name=at_udta then
+ begin
+ size:=SetTree(atom,p,'meta.ilst',par);
+ if size>0 then
+ begin
+ cursize:=0;
+ repeat
+ GetAtom(p,atom);
+ if atom.name=atm_nam then ReadProp(p,Info.title)
+ else if atom.name=atm_ART then ReadProp(p,Info.artist)
+// else if atom.name=atm_wrt then ReadProp(p,Info.title)
+ else if atom.name=atm_alb then ReadProp(p,Info.album)
+ else if atom.name=atm_day then ReadProp(p,Info.year)
+ else if atom.name=atm_cmt then ReadProp(p,Info.comment)
+// else if atom.name=atm_gen then ReadProp(p,Info.genre)
+ else if atom.name=atm_gnre then Info.genre:=GenreName(ReadInt(p)-1)
+ else if atom.name=atm_trkn then Info.track:=ReadInt(p)
+ else
+ inc(p,atom.len-SizeOf(mp4Atom));
+ inc(cursize,atom.len);
+ until cursize>=size;
+ end;
+ end;
+ // video properties
+ if atom.name=at_trak then
+ begin
+ if SetTree(atom,p,'mdia.minf.vmhd',par)>0 then
+ begin
+ p:=par;
+ if SetTree(atom,p,'stbl.stsd',par)>0 then
+ begin
+ Info.width :=swap(pstsd(p)^.Width);
+ Info.height:=swap(pstsd(p)^.Height);
+ Info.codec :=pstsd(p)^.DataFormat;
+ end;
+ end
+ // audio props
+ else if SetTree(atom,p,'mdia.minf.smhd',par)>0 then
+ begin
+ p:=par;
+ if SetTree(atom,p,'stbl.stsd',par)>0 then
+ begin
+ Info.khz:=(BSwap(pastsd(p)^.Samplerate) shr 16) div 1000;
+ Info.channels:=swap(pastsd(p)^.ChannelCount);
+ end;
+ p:=par;
+ if SetTree(atom,p,'stsz',par)>0 then
+ begin
+ if pdword(PAnsiChar(p)+4)^=0 then
+ Info.vbr:=1;
+ end;
+ end;
+ end;
+ p:=pn;
+ until PAnsiChar(p)>=PAnsiChar(finish);
+ mFreeMem(buf);
+ break;
+ end
+ else
+ Skip(f,atom.len-SizeOf(mp4Atom));
+ inc(cursize,atom.len);
+ until cursize>=parentsize;
+ CloseHandle(f);
+end;
+
+var
+ LocalFormatLinkM4A,
+ LocalFormatLinkMP4,
+ LocalFormatLinkMOV,
+ LocalFormatLink3GP:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkM4A.Next:=FormatLink;
+
+ LocalFormatLinkM4A.This.proc :=@ReadM4A;
+ LocalFormatLinkM4A.This.ext :='M4A';
+ LocalFormatLinkM4A.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkM4A;
+
+ LocalFormatLinkMP4.Next:=FormatLink;
+
+ LocalFormatLinkMP4.This.proc :=@ReadM4A;
+ LocalFormatLinkMP4.This.ext :='MP4';
+ LocalFormatLinkMP4.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkMP4;
+
+ LocalFormatLinkMOV.Next:=FormatLink;
+
+ LocalFormatLinkMOV.This.proc :=@ReadM4A;
+ LocalFormatLinkMOV.This.ext :='MOV';
+ LocalFormatLinkMOV.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkMOV;
+
+ LocalFormatLink3GP.Next:=FormatLink;
+
+ LocalFormatLink3GP.This.proc :=@ReadM4A;
+ LocalFormatLink3GP.This.ext :='3GP';
+ LocalFormatLink3GP.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLink3GP;
+
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_mkv.pas b/plugins/Watrack/formats/fmt_mkv.pas
new file mode 100644
index 0000000000..df01a82f59
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_mkv.pas
@@ -0,0 +1,235 @@
+{MKV file process}
+unit fmt_MKV;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadMKV(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,srv_format;
+
+const
+ idEBML = $A45DFA3;
+ idSegment = $8538067;
+ idInfo = $549A966;
+ idTimecodeScale = $AD7B1;
+ idDuration = $489;
+ idTracks = $654AE6B;
+ idTrackEntry = $2E;
+ idTrackType = $3;
+ idCodecPrivate = $23A2;
+ idName = $136E;
+ idVideo = $60;
+ idAudio = $61;
+ idPixelWidth = $30;
+ idPixelHeight = $3A;
+ idDefaultDuration = $3E383;
+ idSamplingFrequency = $35;
+ idChannels = $1F;
+ idCluster = $F43B675;
+
+function GetNumber(var ptr:pbyte):int64;
+begin
+ if (ptr^ and $80)<>0 then
+ result:=ptr^ and $7F
+ else if (ptr^ and $40)<>0 then
+ begin
+ result:=(ptr^ and $3F) shl 8; inc(ptr);
+ result:=result+ptr^;
+ end
+ else if (ptr^ and $20)<>0 then
+ begin
+ result:=(ptr^ and $1F) shl 16; inc(ptr);
+ result:=result+(ptr^ shl 8); inc(ptr);
+ result:=result+ptr^;
+ end
+ else if (ptr^ and $10)<>0 then
+ begin
+ result:=(ptr^ and $0F) shl 24; inc(ptr);
+ result:=result+(ptr^ shl 16); inc(ptr);
+ result:=result+(ptr^ shl 8); inc(ptr);
+ result:=result+ptr^;
+ end
+ else if (ptr^ and $08)<>0 then
+ begin
+ result:=int64(ptr^ and $07) shl 32; inc(ptr);
+ result:=result+(ptr^ shl 24); inc(ptr);
+ result:=result+(ptr^ shl 16); inc(ptr);
+ result:=result+(ptr^ shl 8); inc(ptr);
+ result:=result+ptr^;
+ end
+ else if (ptr^ and $04)<>0 then
+ begin
+ result:=int64(ptr^ and $03) shl 40; inc(ptr);
+ result:=result+(int64(ptr^) shl 32); inc(ptr);
+ result:=result+(ptr^ shl 24); inc(ptr);
+ result:=result+(ptr^ shl 16); inc(ptr);
+ result:=result+(ptr^ shl 8); inc(ptr);
+ result:=result+ptr^;
+ end
+ else if (ptr^ and $02)<>0 then
+ begin
+ result:=int64(ptr^ and $01) shl 48; inc(ptr);
+ result:=result+(int64(ptr^) shl 40); inc(ptr);
+ result:=result+(int64(ptr^) shl 32); inc(ptr);
+ result:=result+(ptr^ shl 24); inc(ptr);
+ result:=result+(ptr^ shl 16); inc(ptr);
+ result:=result+(ptr^ shl 8); inc(ptr);
+ result:=result+ptr^;
+ end
+ else if (ptr^ and $01)<>0 then
+ begin
+ inc(ptr);
+ result:= (int64(ptr^) shl 48); inc(ptr);
+ result:=result+(int64(ptr^) shl 40); inc(ptr);
+ result:=result+(int64(ptr^) shl 32); inc(ptr);
+ result:=result+(ptr^ shl 24); inc(ptr);
+ result:=result+(ptr^ shl 16); inc(ptr);
+ result:=result+(ptr^ shl 8); inc(ptr);
+ result:=result+ptr^;
+ end
+ else
+ result:=0;
+ inc(ptr);
+end;
+
+function GetInt(var ptr:pbyte;len:integer):int64;
+var
+ i:integer;
+begin
+ result:=0;
+ for i:=0 to len-1 do
+ begin
+ result:=(result shl 8)+ptr^;
+ inc(ptr);
+ end;
+end;
+
+function GetFloat(var ptr:pbyte):single;
+var
+ i:dword;
+ f:single absolute i;
+begin
+ i:=( ptr^ shl 24); inc(ptr);
+ inc(i,ptr^ shl 16); inc(ptr);
+ inc(i,ptr^ shl 8); inc(ptr);
+ inc(i,ptr^); inc(ptr);
+ result:=f;
+end;
+
+function ReadMKV(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ id,len:integer;
+ ptr:pByte;
+ buf:array [0..16383] of byte;
+ trktype,scale:integer;
+ ls:PAnsiChar;
+ tmp:integer;
+ lTotal:real;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ BlockRead(f,buf,SizeOf(buf));
+ ptr:=@buf;
+ trktype:=0;
+ lTotal:=0;
+ scale:=1;
+ repeat
+ id :=GetNumber(ptr);
+ len:=GetNumber(ptr);
+ if id=idEBML then // just check
+ begin
+ result:=true;
+ inc(ptr,len);
+ end
+ else if id=idCluster then
+ break
+ else if id=idSegment then // do nothing
+ else if id=idInfo then // do nothing
+ else if id=idTracks then // do nothing
+ else if id=idTrackEntry then // do nothing
+ else if id=idVideo then // do nothing
+ else if id=idAudio then // do nothing
+ else if id=idTimecodeScale then
+ scale:=GetInt(ptr,len)
+ else if id=idDuration then
+ lTotal:=GetFloat(ptr)
+ else if id=idTrackType then
+ begin
+ tmp:=trktype;
+ trktype:=GetInt(ptr,len); // 1-video,2-audio
+ if (tmp=2) and (trktype=2) then
+ break;
+ end
+ else if (id=idCodecPrivate) and (trktype=1) then
+ begin
+ inc(ptr,16);
+ // 4 - ? (40=size included?)
+ // width,height
+ // 2 - ?
+ // 2 - bitperpixel?
+ Info.codec:=ptr^; inc(ptr);
+ Info.codec:=Info.codec+(ptr^ shl 8 ); inc(ptr);
+ Info.codec:=Info.codec+(ptr^ shl 16); inc(ptr);
+ Info.codec:=Info.codec+(ptr^ shl 24);
+ inc(ptr,len-19);
+ end
+ else if (id=idName) and (Info.title=NIL) then
+ begin
+ mGetMem(ls,len+1);
+ move(ptr^,ls^,len);
+ ls[len]:=#0;
+ AnsiToWide(ls,Info.title);
+ mFreeMem(ls);
+ inc(ptr,len);
+ end
+ else if id=idPixelWidth then
+ Info.width:=GetInt(ptr,len)
+ else if id=idPixelHeight then
+ Info.height:=GetInt(ptr,len)
+ else if id=idDefaultDuration then
+ begin
+ if trktype=1 then
+ begin
+ Info.fps:=(GetInt(ptr,len) div 1000);
+ if Info.fps<>0 then
+ Info.fps:=100000000 div Info.fps;
+ end
+ else
+ begin
+ GetInt(ptr,len);
+ end;
+ end
+ else if id=idSamplingFrequency then
+ Info.khz:=round(GetFloat(ptr)) div 1000
+ else if id=idChannels then
+ Info.channels:=GetInt(ptr,len)
+ else
+ inc(ptr,len);
+ until pAnsiChar(ptr)>=(PAnsiChar(@buf)+SizeOf(buf));
+ Info.total:=trunc(lTotal/(1000000000/scale));
+ CloseHandle(f);
+end;
+
+var
+ LocalFormatLink:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLink.Next:=FormatLink;
+
+ LocalFormatLink.This.proc :=@ReadMKV;
+ LocalFormatLink.This.ext :='MKV';
+ LocalFormatLink.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_mp3.pas b/plugins/Watrack/formats/fmt_mp3.pas
new file mode 100644
index 0000000000..5d6c94745a
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_mp3.pas
@@ -0,0 +1,460 @@
+{MP3 file process}
+unit fmt_MP3;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadMP3(var Info:tSongInfo):boolean; cdecl;
+function ReadMPG(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format;
+
+const
+ ScanSize = 16*1024; // block size to search header
+type
+ tMP3FrameHdr = record
+ Version :integer;
+ Layer :cardinal;
+ Bitrate :cardinal;
+ Samplerate:cardinal;
+ Channel :cardinal; //Stereo, Joint, Dual, Mono
+ Length :cardinal;
+ CRC :boolean;
+ _Private :boolean;
+ Copyright :boolean;
+ Original :boolean;
+ isVBR :boolean;
+ end;
+
+// ........ ........ 111..... 11111111 syncword
+// ........ ........ ...xx... ........ version (11=1, 10=2, 00=2.5)
+// ........ ........ .....xx. ........ layer (01=III, 10=II, 11=I)
+// ........ ........ .......x ........ crc (0=yes, 1=no)
+// xx...... ........ ........ ........ mode (00=stereo, 10=joint, 01=dual, 11=mono)
+// ..xx.... ........ ........ ........ mode ext (only for joint stereo)
+// ....x... ........ ........ ........ copyright (0=no, 1=yes)
+// .....x.. ........ ........ ........ original (0=orig, 1=copy)
+// ......xx ........ ........ ........ emphasis (not 10)
+// ........ xxxx.... ........ ........ bitrate (not 0000 nor 1111)
+// ........ ....xx.. ........ ........ sampling rate (not 11)
+// ........ ......x. ........ ........ padded (0=no, 1=yes)
+// ........ .......x ........ ........ private bit
+
+const
+ btable:array [0..1,0..2,0..15] of word = (
+ ( //MPEG 2 & 2.5
+ (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0), //Layer III
+ (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0), //Layer II
+ (0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256,0) //Layer I
+ ),( //MPEG 1
+ (0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,0), //Layer III
+ (0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384,0), //Layer II
+ (0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448,0) //Layer I
+ )
+ );
+ stable: array [0..3,0..2] of word = (
+ (32000, 16000, 8000), //MPEG 2.5
+ ( 0, 0, 0), //reserved
+ (22050, 24000, 16000), //MPEG 2
+ (44100, 48000, 32000) //MPEG 1
+ );
+
+procedure TranslateFrameHdr(const block:array of byte;var MP3FrameHdr:tMP3FrameHdr);
+begin
+ FillChar(MP3FrameHdr,SizeOf(MP3FrameHdr),0);
+ if block[0]=$FF then
+ begin
+ with MP3FrameHdr do
+ begin
+ Version :=(block[1] and $18) shr 3;
+ Layer :=(block[1] and $06) shr 1;
+ CRC :=not Odd(block[1]);
+ Bitrate :=btable[Version and 1][Layer-1][block[2] shr 4];
+ Samplerate:=stable[Version][(block[2] and $0C) shr 2];
+ _Private :=odd(block[2]);
+ Channel :=block[3] shr 6;
+ Copyright :=((block[3] and $08) shr 3)<>0;
+ Original :=((block[3] and $04) shr 2)<>0;
+ end;
+ end;
+end;
+
+procedure CheckVBR(f:THANDLE; var hdr:tMP3FrameHdr);
+var
+ pos,apos:cardinal;
+ sign:longint;
+ frames:longint;
+begin
+ pos:=FilePos(f);
+ hdr.Length:=0;
+ if hdr.Version=3 then
+ begin
+ if hdr.Channel=3 then
+ apos:=17
+ else
+ apos:=32;
+ end
+ else if hdr.Channel=3 then
+ apos:=9
+ else
+ apos:=17;
+ Skip(f,apos);
+ BlockRead(f,sign,4);
+ hdr.isVBR:=sign=$676E6958; //Xing
+//calculate length
+ if hdr.isVBR then
+ begin
+ if hdr.Samplerate<>0 then
+ begin
+// Seek(f,pos+36);
+ BlockRead(f,sign,4);
+ if (sign and $01000000)<>0 then
+ begin
+ BlockRead(f,frames,4);
+ frames:=BSwap(frames);
+ hdr.Length:=Round((1152/hdr.Samplerate)*frames/(4-hdr.Version)); //!
+ end;
+ end;
+ end
+ else if hdr.Bitrate<>0 then
+ hdr.Length:=((8*(FileSize(f)-(pos-4))) div 1000) div hdr.Bitrate;
+end;
+
+function SearchStart(f:THANDLE; var l:array of byte):Boolean;
+var
+ CurPos:longint;
+ Buf:array [0..ScanSize] of byte;
+ i,j:integer;
+begin
+ CurPos:=FilePos(f)-4;
+ Seek(f,CurPos);
+ j:=BlockRead(f,Buf,ScanSize);
+ i:=0;
+ while i<j do
+ begin
+ if (i<(j-2)) and (Buf[i]=$FF) and //FF FB E4
+ ((Buf[i+1] and $E0)=$E0) and
+ ((Buf[i+2] and $F0)<>$F0) then
+ begin
+ Seek(f,CurPos+i);
+ BlockRead(f,l,4);
+ result:=true;
+ Exit;
+ end;
+ inc(i);
+ end;
+ result:=false;
+end;
+
+function ReadMP3(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ l:array [0..3] of byte;
+ hdr:tMP3FrameHdr;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ ReadID3v2(f,Info);
+ BlockRead(f,l,4);
+// if l[0]<>$FF then
+ if not SearchStart(f,l) then
+ Exit;
+ TranslateFrameHdr(l,hdr);
+ CheckVBR(f,hdr);
+ Info.kbps :=hdr.Bitrate;
+ Info.khz :=hdr.Samplerate div 1000;
+ Info.total:=hdr.Length;
+ if hdr.Channel=3 then
+ Info.channels:=1
+ else
+ Info.channels:=2;
+ Info.vbr:=ord(hdr.isVBR);
+
+ ReadAPEv2(f,Info);
+ ReadID3v1(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+const
+ mpgAudio = 1;
+ mpgVideo = 2;
+ mpgVersion = 4;
+
+type
+ l2b=array [0..3] of byte;
+
+function ReadDWord(var p:pAnsiChar;endptr:pAnsiChar):integer;
+begin
+ if (p+4)<endptr then
+ begin
+ result:=pDWord(p)^;
+ inc(p,4);
+ end
+ else
+ result:=-1;
+end;
+
+function ReadWord(var p:pAnsiChar;endptr:pAnsiChar):integer;
+begin
+ if (p+2)<endptr then
+ begin
+ result:=pWord(p)^;
+ inc(p,2);
+ end
+ else
+ result:=-1;
+end;
+
+function ReadByte(var p:pAnsiChar;endptr:pAnsiChar):integer;
+begin
+ if p<endptr then
+ begin
+ result:=pByte(p)^;
+ inc(p);
+ end
+ else
+ result:=-1;
+end;
+
+function ChunkRead(var p:pAnsiChar;endptr:pAnsiChar):integer;
+var
+ i:integer;
+begin
+ repeat
+ if ReadByte(p,endptr)=0 then
+ if ReadByte(p,endptr)=0 then
+ begin
+ repeat
+ i:=ReadByte(p,endptr);
+ until i<>0;
+ if i=1 then
+ begin
+ result:=ReadByte(p,endptr) or $100;
+ exit;
+ end;
+ end;
+ until p>=endptr;
+ result:=0;
+end;
+
+const
+ BufSize = 256*1024;
+
+function ReadMPG(var Info:tSongInfo):boolean; cdecl;
+var
+ endptr,buf,p:PAnsiChar;
+ f:THANDLE;
+ BlockType:integer;
+ l:dword;
+ w:word;
+ b:byte;
+ flag:integer;
+ version,layer:integer;
+// vbitrate:integer;
+// FrmCnt:integer;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ flag:=mpgAudio+mpgVideo+mpgVersion;
+
+ mGetMem(buf,BufSize);
+ endptr:=buf+BlockRead(f,buf^,BufSize);
+ CloseHandle(f);
+ p:=buf;
+// FrmCnt:=0;
+ while (flag<>0) and (p<endptr) do
+ begin
+ BlockType:=ChunkRead(p,endptr);
+ case BlockType of
+ $1BA: begin // pack
+ if (flag and mpgVersion)<>0 then
+ begin
+ flag:=flag and not mpgVersion;
+ if (ReadByte(p,endptr) and $C0)=$40 then
+ Info.codec:=$3247504D // MPG2
+ else
+ Info.codec:=$4745504D; // MPEG
+ end;
+ end;
+ $1B3: begin // Video
+ if (flag and mpgVideo)<>0 then
+ begin
+ l:=ReadDWord(p,endptr);
+ flag:=flag and not mpgVideo;
+ Info.width :=((l2b(l)[1] and $F0) shr 4)+(l2b(l)[0] shl 4);
+ Info.height:=((l2b(l)[1] and $0F) shl 8)+l2b(l)[2];
+ case l2b(l)[3] and $F of
+ 1: Info.fps:=2397;
+ 2: Info.fps:=2400;
+ 3: Info.fps:=2500;
+ 4: Info.fps:=2997;
+ 5: Info.fps:=3000;
+ 6: Info.fps:=5000;
+ 7: Info.fps:=5994;
+ 8: Info.fps:=6000;
+ end;
+// BlockRead(f,l,4);
+// vbitrate:=(l2b(l)[0] shl 10)+(l2b(l)[1] shl 2)+(l2b(l)[2] shr 6);
+ end;
+ end;
+ 0,$1B7,$1B9: break;
+{
+ $1E0: begin
+ BlockRead(f,w,2);
+ w:=swap(w);
+ mGetMem(buf,w);
+ BlockRead(f,buf^,w);
+ p:=buf;
+ for l:=0 to w-4 do
+ begin
+ if pdword(p)^=$00010000 then
+ begin
+ inc(FrmCnt);
+ inc(p,4);
+ end
+ else
+ inc(p);
+ end;
+ mFreeMem(buf);
+ end;
+}
+ $1C0: begin // audio
+ w:=swap(ReadWord(p,endptr));
+ if flag and mpgAudio<>0 then
+ begin
+ flag:=flag and not mpgAudio;
+ b:=ReadByte(p,endptr);
+ dec(w);
+ if (b and $C0)=$80 then
+ begin
+ b:=ReadByte(p,endptr);
+ l:=ReadByte(p,endptr);
+ dec(w,2);
+ if (b and $80)<>0 then
+ begin
+ inc(p,5);
+ dec(w,5);
+ dec(l,5);
+ if (b and $40)<>0 then
+ begin
+ inc(p,5);
+ dec(w,5);
+ dec(l,5);
+ end;
+ end;
+ if l>0 then
+ begin
+ inc(p,l);
+ dec(w,l);
+ end;
+ end
+ else
+ begin
+ while (b and $80)<>0 do
+ begin
+ dec(w);
+ if w=0 then break;
+ b:=ReadByte(p,endptr);
+ end;
+ if (b and $40)<>0 then
+ begin
+ inc(p);
+ b:=ReadByte(p,endptr);
+ dec(w,2);
+ end;
+ if (b and $20)<>0 then
+ begin
+ inc(p,4);
+ dec(w,4);
+ if (b and $10)<>0 then
+ begin
+ inc(p,5);
+ dec(w,5);
+ end;
+ end;
+ end;
+ l:=ReadDWord(p,endptr);
+ version:=(l2b(l)[1] and $18) shr 3;
+ layer :=(l2b(l)[1] and $06) shr 1;
+ Info.kbps :=btable[version and 1][layer-1][l2b(l)[2] shr 4];
+ Info.khz :=(stable[version][(l2b(l)[2] and $0C) shr 2]) div 1000;
+ Info.channels:=l2b(l)[3] shr 6;
+ if Info.channels=3 then
+ Info.channels:=1
+ else
+ Info.channels:=2;
+// if w>0 then inc(p,w);
+ end;
+// else
+ inc(p,w);
+ end;
+{
+ $1B5: begin
+ BlockRead(f,l,4);
+ if (l2b(l)[0] and $F0)=$10 then
+ begin
+ vbitrate:=vbitrate+
+ ((((l2b(l)[2] and $1F) shl 7)+(l2b(l)[3] shr 1)) shl 18);
+ end;
+ end;
+}
+{
+ $1BD: begin
+ end;
+}
+ $1C1..$1DF, // audio
+//?? $1E0,
+ $1E1..$1EF, // video
+ $1BB{,$1BD},$1BE,$1BF: begin // system,private,padding,private
+ inc(p,swap(ReadWord(p,endptr)));
+ end;
+ end;
+ end;
+// vbitrate:=(vbitrate*400) div 1000;
+// Info.total:=(FrmCnt*100) div Info.fps;
+ mFreeMem(buf);
+ result:=true;
+end;
+
+var
+ LocalFormatLinkMP3,
+ LocalFormatLinkMPG,
+ LocalFormatLinkMPEG:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkMP3.Next:=FormatLink;
+
+ LocalFormatLinkMP3.This.proc :=@ReadMP3;
+ LocalFormatLinkMP3.This.ext :='MP3';
+ LocalFormatLinkMP3.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkMP3;
+
+ LocalFormatLinkMPG.Next:=FormatLink;
+
+ LocalFormatLinkMPG.This.proc :=@ReadMPG;
+ LocalFormatLinkMPG.This.ext :='MPG';
+ LocalFormatLinkMPG.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkMPG;
+
+ LocalFormatLinkMPEG.Next:=FormatLink;
+
+ LocalFormatLinkMPEG.This.proc :=@ReadMPG;
+ LocalFormatLinkMPEG.This.ext :='MPEG';
+ LocalFormatLinkMPEG.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkMPEG;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_mpc.pas b/plugins/Watrack/formats/fmt_mpc.pas
new file mode 100644
index 0000000000..7d8671dde6
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_mpc.pas
@@ -0,0 +1,90 @@
+{MPC file format}
+unit fmt_MPC;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadMPC(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format;
+
+const
+ DefID = $002B504D;// 'MP+'
+
+function ReadMPC(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ tmp:array [0..5] of dword;
+ samples,TotalFrames:dword;
+ lastframe:dword;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ ReadID3v2(f,Info);
+
+ BlockRead(f,tmp,SizeOf(tmp));
+ if ((tmp[0] and $FFFFFF)=DefID) and
+ (((tmp[0] shr 24) and $0F)>=7) then // sv7-sv8
+ begin
+ Info.kbps:=0;
+ if (tmp[2] and 2)<>0 then
+ Info.channels:=2
+ else
+ Info.channels:=1;
+ case (tmp[2] and $3000) shr 12 of //C000-14?
+ 00: Info.khz:=44100;
+ 01: Info.khz:=48000;
+ 02: Info.khz:=37800;
+ 03: Info.khz:=32000;
+ end;
+ lastframe:=(tmp[5] and $FFF) shr 1;
+ samples:=tmp[1]*1152+lastframe;
+ end
+ else
+ begin //4-6
+ if not ((tmp[0] and $1FFF) and $3FF) in [4..6] then
+ exit;
+ Info.khz:=44100;
+ Info.kbps:=tmp[1] and $1F;
+ if ((tmp[0] and $1FFF) and $3FF)=4 then
+ TotalFrames:=loword(tmp[2])
+ else
+ TotalFrames:=tmp[2];
+ samples:=TotalFrames*1152;
+ end;
+
+ if Info.khz<>0 then
+ Info.total:=samples div Info.khz;
+ Info.khz:=Info.khz div 1000;
+ if (Info.kbps=0) and (samples<>0) then
+// if fs=samples*channels*deep/8 then kbps=khz*deep*channels/1152
+// Info.kbps:=(Info.khz*8)*taginfo.FileSize/1152/samples;
+
+ Info.kbps:=(Info.khz div 8)*FileSize(f) div samples; //!!
+ ReadAPEv2(f,Info);
+ ReadID3v1(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLink:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLink.Next:=FormatLink;
+
+ LocalFormatLink.This.proc :=@ReadMPC;
+ LocalFormatLink.This.ext :='MPC';
+ LocalFormatLink.This.flags:=0;
+
+ FormatLink:=@LocalFormatLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_ofr.pas b/plugins/Watrack/formats/fmt_ofr.pas
new file mode 100644
index 0000000000..73d58b68ff
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_ofr.pas
@@ -0,0 +1,74 @@
+{OFR file}
+unit fmt_OFR;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadOFR(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format;
+
+type
+ tMain = packed record
+ ID :dword; // 'OFR '
+ Size :dword; //15
+ SamplesLo :dword;
+ SamplesHi :word;
+ SampleType :byte;
+ ChannelsMap:byte;
+ Samplerate :dword;
+ Encoder :word;
+ Compression:byte;
+ end;
+
+function ReadOFR(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ Hdr:tMain;
+ Samples:int64;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ ReadID3v2(f,Info);
+ BlockRead(f,Hdr,SizeOf(Hdr));
+ Samples:=Hdr.SamplesLo+Hdr.SamplesHi*$10000;
+ Info.channels:=Hdr.ChannelsMap+1;
+ Info.khz :=Hdr.Samplerate div 1000;
+ Info.total :=(Samples div Info.channels)*Info.khz;
+
+ ReadAPEv2(f,Info);
+ ReadID3v1(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLinkOFR,
+ LocalFormatLinkOFS:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkOFR.Next:=FormatLink;
+
+ LocalFormatLinkOFR.This.proc :=@ReadOFR;
+ LocalFormatLinkOFR.This.ext :='OFR';
+ LocalFormatLinkOFR.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkOFR;
+
+ LocalFormatLinkOFS.Next:=FormatLink;
+
+ LocalFormatLinkOFS.This.proc :=@ReadOFR;
+ LocalFormatLinkOFS.This.ext :='OFS';
+ LocalFormatLinkOFS.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkOFS;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_ogg.pas b/plugins/Watrack/formats/fmt_ogg.pas
new file mode 100644
index 0000000000..4b05b80c2c
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_ogg.pas
@@ -0,0 +1,522 @@
+{OGG, SPX and FLAC file formats}
+unit fmt_OGG;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadOGG(var Info:tSongInfo):boolean; cdecl;
+function ReadSPX(var Info:tSongInfo):boolean; cdecl;
+function ReadfLaC(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format,base64,utils;
+
+const
+ OGGSign = $5367674F; //OggS
+const
+ SpeexID = 'Speex ';
+type
+ tSPEXHeader = packed record
+ speex_string :array [0..7] of AnsiChar;
+ speex_version :array [0..19] of AnsiChar;
+ speex_version_id:dword;
+ header_size :dword; //sizeof(tSPEXHeader)
+ rate :dword;
+ mode :dword;
+ bitstrm_version :dword;
+ nb_channels :dword;
+ bitrate :dword;
+ frame_size :dword;
+ vbr :dword;
+ fpp :dword; //frames_per_packet
+ extra_headers :dword;
+ reserved1 :dword;
+ reserved2 :dword;
+ end;
+type
+ pOGGHdr = ^tOGGHdr;
+ tOGGHdr = packed record
+ ID :dword;
+ Version :byte;
+ HdrType :byte;
+ Granule :Int64; // absolute position
+ BitStrmSN:dword;
+ PageSeqN :dword;
+ CRC :dword;
+ PageSegs :byte;
+ end;
+const
+ strmOGG = 1;
+ strmOGM = 2;
+const
+ VideoD = $65646976;
+ VideoW = $006F;
+ VorbisD = $62726F76;
+ VorbisW = $7369;
+type
+ tOGMInfo = packed record
+ padding :word; // 0
+ codec :dword;
+ size :dword;
+ time_unit :int64; // 1/10000000 sec
+ samples_per_unit:int64; // fps = 10000000*spu/time_unit
+ default_len :dword; // 1
+ buffersize :dword;
+ bit_per_sample :dword;
+ width :dword;
+ height :dword;
+ dummy :dword; // 0
+ end;
+
+//const VorbisStream:array [0..5] of byte = ($76,$6F,$72,$62,$69,$73); // 'vorbis'
+
+type
+ tOGGInfo = packed record
+ version :dword;
+ Channels :byte;
+ samplerate:dword;
+ maxkbps :dword;
+ nominal :dword;
+ minkbps :dword;
+ BlockSizes:byte;
+ dummy :byte;
+ end;
+
+//--------------- fLaC section ---------------
+const
+ fLaCSign = $43614C66; //fLaC
+{
+0 : STREAMINFO
+1 : PADDING
+2 : APPLICATION
+3 : SEEKTABLE
+4 : VORBIS_COMMENT
+5 : CUESHEET
+}
+type
+ MetaHdr = packed record
+ blocktype:byte;
+ blocklen:array [0..2] of byte;
+ end;
+type
+ StreamInfo = packed record
+ MinBlockSize:word;
+ MaxBlocksize:word;
+ MinFrameSize:array [0..2] of byte;
+ MaxFrameSize:array [0..2] of byte;
+ heap:array [0..7] of byte;
+ MD5:array [0..15] of byte;
+ end;
+
+procedure OGGGetComment(ptr:PAnsiChar;size:integer;var Info:tSongInfo);
+var
+ clen,alen,len,values:dword;
+ ls:PAnsiChar;
+ value:PAnsiChar;
+ cover:pByte;
+ ext:dword;
+ extw:int64;
+ c:AnsiChar;
+begin
+ inc(ptr,pdword(ptr)^+4); //vendor
+ values:=pdword(ptr)^; inc(ptr,4);
+ ext:=0;
+ cover:=nil;
+ clen:=0;
+ while values>0 do
+ begin
+ len:=pdword(ptr)^;
+ if len>cardinal(size) then
+ break;
+ dec(size,len);
+ inc(ptr,4);
+ ls:=ptr;
+ c:=ls[len];
+ ls[len]:=#0;
+ alen:=StrScan(ls,'=')-ls+1;
+ if alen>0 then
+ begin
+ ls[alen-1]:=#0;
+ value:=ls+alen;
+
+ if (Info.title =nil) and (lstrcmpia(ls,'TITLE' )=0) then UTF8ToWide(value,Info.title)
+ else if (Info.artist =nil) and (lstrcmpia(ls,'ARTIST' )=0) then UTF8ToWide(value,Info.artist)
+ else if (Info.album =nil) and (lstrcmpia(ls,'ALBUM' )=0) then UTF8ToWide(value,Info.album)
+ else if (Info.genre =nil) and (lstrcmpia(ls,'GENRE' )=0) then UTF8ToWide(value,Info.genre)
+ else if (Info.year =nil) and (lstrcmpia(ls,'DATE' )=0) then UTF8ToWide(value,Info.year)
+ else if (Info.comment=nil) and (lstrcmpia(ls,'COMMENT')=0) then UTF8ToWide(value,Info.comment)
+ else if (Info.lyric =nil) and (lstrcmpia(ls,'LYRICS' )=0) then UTF8ToWide(value,Info.lyric)
+
+ else if (Info.track=0) and (lstrcmpia(ls,'TRACKNUMBER')=0) then Info.track:=StrToInt(value)
+
+ else if (cover=nil) and (lstrcmpia(ls,'COVERART')=0) then clen:=Base64Decode(value,cover)
+ else if lstrcmpia(ls,'COVERARTMIME')=0 then ext:=GetImageType(nil,value);
+ end;
+ dec(values);
+ inc(ptr,len);
+ ptr^:=c;
+ end;
+
+ if cover<>nil then
+ begin
+ if ext=0 then
+ ext:=GetImageType(cover);
+ if ext<>0 then
+ begin
+ FastAnsiToWideBuf(PAnsiChar(@ext),pWideChar(@extw));
+ Info.cover:=SaveTemporaryW(cover,clen,PWideChar(@extw));
+ end;
+ mFreeMem(cover);
+ end;
+
+end;
+
+function CalcSize(num:integer;var arr:array of byte):integer;
+var
+ i:integer;
+begin
+ result:=0;
+ for i:=0 to num-1 do
+ begin
+ inc(result,arr[i]);
+ if arr[i]<$FF then break;
+ end;
+end;
+
+function ReadSPX(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ OGGHdr:tOGGHdr;
+ SPXHdr:tSPEXHeader;
+ buf:array [0..255] of byte;
+ ptr:PAnsiChar;
+ size:integer;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ BlockRead(f,OGGHdr,SizeOf(tOGGHdr));
+ Skip(f,OGGHdr.PageSegs);
+ if OGGHdr.ID=OGGSign then
+ begin
+ BlockRead(f,SPXHdr,SizeOf(SPXHdr));
+ if SPXHdr.speex_string<>SpeexID then
+ begin
+ CloseHandle(f);
+ exit;
+ end;
+ Info.khz:=SPXHdr.rate div 1000;
+ Info.vbr:=SPXHdr.vbr;
+ if integer(SPXHdr.bitrate)<>-1 then
+ Info.kbps:=SPXHdr.bitrate div 1000;
+
+ BlockRead(f,OGGHdr,SizeOf(tOGGHdr));
+ BlockRead(f,buf,OGGHdr.PageSegs);
+ size:=CalcSize(OGGHdr.PageSegs,buf);
+ GetMem(ptr,size+1);
+ BlockRead(f,ptr^,size);
+ OGGGetComment(ptr,size,Info);
+ FreeMem(ptr);
+
+ result:=true;
+ end;
+ CloseHandle(f);
+end;
+
+function Compare(const sign:array of byte):integer;
+type
+ conv=packed record
+ d:dword;w:word;
+ end;
+var
+ p:^conv;
+begin
+ p:=@sign;
+ if (p^.d=VideoD) and (p^.w=VideoW) then
+ result:=strmOGM
+ else if (p^.d=VorbisD) and (p^.w=VorbisW) then
+ result:=strmOGG
+ else
+ result:=0;
+end;
+
+function ReadOGG(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ OGGHdr:tOGGHdr;
+ tmp:packed record
+ paktype:byte;
+ sign:array [0..5] of byte;
+ end;
+ OGGInfo:tOGGInfo;
+ OGMInfo:tOGMInfo;
+ fpos:dword;
+ SPXHdr:tSPEXHeader;
+ i,j:integer;
+ DataIndex:integer;
+ buf:array [0..255] of byte;
+ fsize:dword;
+ done:integer;
+ ptr:PAnsiChar;
+ size:integer;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ tmp.paktype:=0;
+ fsize:=FileSize(f);
+ done:=0;
+ while (done<>3) and (tmp.paktype<>5) and (FilePos(f)<fsize) do
+ begin
+ BlockRead(f,OGGHdr,SizeOf(tOGGHdr));
+ if OGGHdr.ID=OGGSign then
+ begin
+ BlockRead(f,buf,OGGHdr.PageSegs);
+ size:=CalcSize(OGGHdr.PageSegs,buf);
+// sum pages to size obtain and number of groups
+// for i:=0 to OGGHdr.PageSegs-1 do
+// only first fragment
+ begin
+ fpos:=FilePos(f);
+ BlockRead(f,tmp,SizeOf(tmp));
+ if tmp.paktype=5 then
+ break;
+ if tmp.paktype=1 then
+ begin
+ case Compare(tmp.sign) of
+ strmOGG: begin
+ BlockRead(f,OGGInfo,SizeOf(OGGInfo));
+ if integer(OGGInfo.nominal)>0 then
+ Info.kbps :=OGGInfo.nominal div 1000;
+ Info.khz :=OGGInfo.samplerate;
+ Info.channels:=OGGInfo.Channels;
+ done:=done or 1;
+ end;
+ strmOGM: begin
+ BlockRead(f,OGMInfo,SizeOf(OGMInfo));
+ Info.codec :=OGMInfo.codec;
+ Info.fps :=round(((10000000*OGMInfo.samples_per_unit) / OGMInfo.time_unit)*100);
+ Info.width :=OGMInfo.width;
+ Info.height:=OGMInfo.height;
+ done:=done or 1;
+ end;
+ end;
+ end
+ else if tmp.paktype=ORD('S') then //maybe SPX
+ begin
+ Seek(f,fpos);
+ BlockRead(f,SPXHdr,SizeOf(SPXHdr));
+ if SPXHdr.speex_string<>SpeexID then
+ begin
+ CloseHandle(f);
+ exit;
+ end;
+ Info.khz:=SPXHdr.rate div 1000;
+ if integer(SPXHdr.bitrate)<>-1 then
+ Info.kbps:=SPXHdr.bitrate div 1000;
+ done:=done or 1;
+ end
+ else if tmp.paktype=3 then
+ begin
+ GetMem(ptr,size+1);
+ BlockRead(f,ptr^,size);
+ OGGGetComment(ptr,size,Info);
+ FreeMem(ptr);
+ done:=done or 2;
+ end
+ else
+ continue;
+ result:=true;
+ end;
+ end;
+ end;
+ // try to get length
+ DataIndex:=FileSize(f)-10;
+ for i:=1 to 50 do
+ begin
+ dec(DataIndex,SizeOf(buf)-10);
+ Seek(f,DataIndex);
+ BlockRead(f,buf,SizeOf(buf));
+ { Get number of PCM samples from last Ogg packet header }
+ j:=SizeOf(buf)-10;
+ repeat
+ if pOGGHdr(@buf[j])^.ID=OGGSign then
+ begin
+ if j>(SizeOf(buf)-SizeOf(tOGGHdr)) then
+ begin
+ Seek(f,DataIndex+j);
+ BlockRead(f,buf,SizeOf(tOGGHdr));
+ j:=0;
+ end;
+ if Info.fps>0 then
+ begin
+ Info.total:=(pOGGHdr(@buf[j])^.Granule*100) div Info.fps;
+ end
+ else if Info.khz<>0 then
+ Info.total:=pOGGHdr(@buf[j])^.Granule div Info.khz;
+ break;
+ end;
+ dec(j);
+ until j=0;
+ if Info.total>0 then break;
+ end;
+ Info.khz:=Info.khz div 1000;
+ CloseHandle(f);
+end;
+
+function ReadfLaC(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ data64:int64;
+ hdr:MetaHdr;
+ frm:StreamInfo;
+ id:dword;
+ flag:integer;
+ size:dword;
+ buf,ptr:PAnsiChar;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ ReadID3v2(f,Info);
+ BlockRead(f,id,SizeOf(id));
+ if id=fLaCSign then
+ begin
+ flag:=0;
+ repeat
+ BlockRead(f,hdr,SizeOf(hdr));
+ size:=hdr.blocklen[2]+(hdr.blocklen[1] shl 8)+(hdr.blocklen[0] shl 16);
+ case (hdr.blocktype and $7F) of
+ 0: begin
+ if flag=0 then
+ begin
+ BlockRead(f,frm,SizeOf(frm));
+ //samplerate eg.44100
+ Info.khz:=((frm.heap[0] shl 12)+(frm.heap[1] shl 4)+(frm.heap[2] shr 4));
+ Info.channels:=((frm.heap[2] and $F) shr 1)+1;
+ //bits per SAMPLE now
+ Info.kbps:=(frm.heap[2] and 1) shl 4+(frm.heap[3] shr 4)+1;
+ data64:=((frm.heap[3] and $F) shl 32)+(frm.heap[4] shl 24)+
+ (frm.heap[5] shl 16)+(frm.heap[6] shl 8)+frm.heap[7];
+
+ if (data64<>0) and (Info.khz<>0) then
+ Info.total:=data64 div Info.khz;
+ Info.kbps:=Info.kbps*8;
+Info.kbps:=trunc(FileSize(f)*8/1000);
+ Info.khz:=Info.khz div 1000;
+ flag:=1;
+ end;
+ end;
+ 4: begin
+ GetMem(buf,size);
+ BlockRead(f,buf^,size);
+ OGGGetComment(buf,size,Info);
+ FreeMem(buf);
+ end;
+ 6: begin
+ if Info.cover=nil then
+ begin
+ GetMem(buf,size);
+ BlockRead(f,buf^,size);
+ ptr:=buf;
+ id:=BSwap(pdword(ptr)^);
+ case id of
+ 0,3,4,6: begin
+ inc(ptr,4);
+ id:=BSwap(pdword(ptr)^); // mime size
+ inc(ptr,4);
+ flag:=GetImageType(nil,ptr);
+ inc(ptr,id+4*5); // width, height, depth etc.
+ id:=BSwap(pdword(ptr)^); // image size
+ inc(ptr,4);
+ if flag=0 then
+ flag:=GetImageType(pByte(ptr));
+ FastAnsiToWideBuf(PAnsiChar(@flag),pWideChar(@data64));
+ Info.cover:=SaveTemporaryW(ptr,id,PWideChar(@data64));
+ end;
+ end;
+ FreeMem(buf);
+ end
+ else
+ Skip(f,size);
+ end
+ else
+ begin
+ if (hdr.blocktype and $80)<>0 then
+ break;
+ Skip(f,size);
+ end;
+ end;
+ until (hdr.blocktype and $80)<>0;
+ end;
+ ReadID3v1(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLinkOGG,
+ LocalFormatLinkOGA,
+ LocalFormatLinkOGM,
+ LocalFormatLinkSPX,
+ LocalFormatLinkFLA,
+ LocalFormatLinkFLAC:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkOGG.Next:=FormatLink;
+
+ LocalFormatLinkOGG.This.proc :=@ReadOGG;
+ LocalFormatLinkOGG.This.ext :='OGG';
+ LocalFormatLinkOGG.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkOGG;
+
+ LocalFormatLinkOGA.Next:=FormatLink;
+
+ LocalFormatLinkOGA.This.proc :=@ReadOGG;
+ LocalFormatLinkOGA.This.ext :='OGA';
+ LocalFormatLinkOGA.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkOGA;
+
+ LocalFormatLinkOGM.Next:=FormatLink;
+
+ LocalFormatLinkOGM.This.proc :=@ReadOGG;
+ LocalFormatLinkOGM.This.ext :='OGM';
+ LocalFormatLinkOGM.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkOGM;
+
+ LocalFormatLinkSPX.Next:=FormatLink;
+
+ LocalFormatLinkSPX.This.proc :=@ReadSPX;
+ LocalFormatLinkSPX.This.ext :='SPX';
+ LocalFormatLinkSPX.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkSPX;
+
+ LocalFormatLinkFLA.Next:=FormatLink;
+
+ LocalFormatLinkFLA.This.proc :=@ReadfLaC;
+ LocalFormatLinkFLA.This.ext :='FLA';
+ LocalFormatLinkFLA.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkFLA;
+
+ LocalFormatLinkFLAC.Next:=FormatLink;
+
+ LocalFormatLinkFLAC.This.proc :=@ReadfLaC;
+ LocalFormatLinkFLAC.This.ext :='FLAC';
+ LocalFormatLinkFLAC.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkFLAC;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_real.pas b/plugins/Watrack/formats/fmt_real.pas
new file mode 100644
index 0000000000..8d5f5bf72d
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_real.pas
@@ -0,0 +1,335 @@
+{Real file}
+unit fmt_Real;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadReal(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format;
+
+const
+ blk_RMF = $464D522E; // '.RMF'
+ blkPROP = $504F5250; // 'PROP'
+ blkCONT = $544E4F43; // 'CONT' - content
+ blkMDPR = $5250444D; // 'MDPR'
+ blkDATA = $41544144; // 'DATA'
+ blkINDX = $58444E49; // 'INDX'
+ blkRMMD = $444D4D52; // 'RMMD' - comment block
+ blkRMJD = $444A4D52; // 'RMJD'
+ blkRMJE = $454A4D52; // 'RMJE'
+type
+ tChunk = packed record
+ ID:dword;
+ Len:dword; //with Chunk;
+ end;
+
+type
+ pPROP = ^tPROP;
+ tPROP = packed record
+ w1 :word;
+ l1,l2 :dword;
+ l3,l4 :dword;
+ un1 :dword; // or 2+2
+ filetotal :dword; // msec
+ l5 :dword;
+ InfoDataSize:dword;
+ Infosize :dword;
+ w2 :word; // always 2 ?
+ w :word; // chunks+1?
+ end;
+
+procedure SkipStr(var p:PAnsiChar;alen:integer);
+var
+ len:integer;
+begin
+ if alen=2 then
+ len:=(ord(p[0]) shl 8)+ord(p[1])
+ else
+ len:=ord(p[0]);
+ inc(p,alen);
+// if len>0 then
+ inc(p,len);
+end;
+
+function ReadStr(var p:PAnsiChar;alen:integer):PAnsiChar;
+var
+ len:integer;
+begin
+ if alen=2 then
+ len:=(ord(p[0]) shl 8)+ord(p[1])
+ else
+ len:=ord(p[0]);
+ inc(p,alen);
+ if len>0 then
+ begin
+ mGetMem(result,len+1);
+ move(p^,result^,len);
+ result[len]:=#0;
+ inc(p,len);
+ end
+ else
+ result:=nil;
+end;
+
+function GetWord(var p:PAnsiChar):word;
+begin
+ result:=(ord(p[0]) shl 8)+ord(p[1]);
+ inc(p,2);
+end;
+
+function GetLong(var p:PAnsiChar):dword;
+begin
+ result:=(ord(p[0]) shl 24)+(ord(p[1]) shl 16)+(ord(p[2]) shl 8)+ord(p[3]);
+ inc(p,4);
+end;
+
+function ReadReal(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ chunk:tChunk;
+ p,buf:PAnsiChar;
+ ls:PAnsiChar;
+ ver:integer;
+ fsize:cardinal;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ fsize:=FileSize(f);
+ while FilePos(f)<fsize do
+ begin
+ BlockRead(f,chunk,SizeOf(chunk));
+ chunk.Len:=BSwap(chunk.Len);
+ if (not (AnsiChar(chunk.ID and $FF) in ['A'..'Z','a'..'z','.'])) or
+ (chunk.Len<SizeOf(chunk)) then
+ break;
+ if (chunk.ID=blkPROP) or (chunk.ID=blkCONT) or (chunk.ID=blkMDPR) then
+ begin
+ mGetMem(buf,chunk.Len-SizeOf(chunk));
+ p:=buf;
+ BlockRead(f,buf^,chunk.Len-SizeOf(chunk));
+ if chunk.ID=blkPROP then
+ begin
+ inc(p,22);
+{
+ GetWord(p); // 0
+ GetLong(p); // min total bps?
+ GetLong(p); // max total bps?
+ GetLong(p); // a samples?
+ GetLong(p); // b samples?
+ GetLong(p); // c (samplesize?)
+}
+ Info.total:=GetLong(p) div 1000;
+{
+ GetLong(p); // X
+ GetLong(p); // used data size (w/o INDX and tags)
+ GetLong(p); // offset to DATA chunk
+ GetWord(p); // number of MDPR chunks
+ GetWord(p); // 2-9, 3-11
+}
+ end
+ else if chunk.ID=blkCONT then
+ begin
+ SkipStr(p,2); // rating?
+ ls:=ReadStr(p,2); // title
+ AnsiToWide(ls,Info.title);
+ mFreeMem(ls);
+ ls:=ReadStr(p,2); // author
+ AnsiToWide(ls,Info.artist);
+ mFreeMem(ls);
+{
+ SkipStr(p,2); // copyright
+ SkipStr(p,2); // description
+}
+ end
+ else if chunk.ID=blkMDPR then
+ begin //stream or logical info
+ GetLong(p); // MDPR block number (from 0)
+ if Info.kbps=0 then
+ Info.kbps:=GetLong(p) div 1000 // a stream bps
+ else
+ GetLong(p); // a stream bps
+ inc(p,24);
+{
+ GetLong(p); // a stream bps
+ GetLong(p); // b smp
+ GetLong(p); // b smp
+ GetLong(p); // 0
+ GetLong(p); // X
+ GetLong(p); //StreamLen
+}
+ SkipStr(p,1); //BlockName - usually 'Audio Stream'
+ ls:=ReadStr(p,1); //BlockMime
+ if StrCmp(ls,'audio/x-pn-realaudio')=0 then
+ begin
+ inc(p,20);
+{
+ GetLong(p); // stream dataLen;
+ GetLong(p); // type = $2E$72$61$FD
+ GetWord(p); // binary version? [4/5]
+ GetWord(p); // 0
+ GetLong(p); // last byte = ASC version $2E$72$61$($30+ver.)
+ GetWord(p);
+ GetWord(p);
+}
+ ver:=GetWord(p); // =version?
+ inc(p,30);
+{
+ GetLong(p); // datalen incl +2 (ver?)
+ GetWord(p); // ? 18,19,1,7
+ GetWord(p); // 0
+ GetWord(p); // un1
+ GetLong(p); //
+ GetLong(p); //
+ GetLong(p); //
+ GetWord(p); //
+ GetWord(p); // un2=un1
+ GetWord(p); //
+ GetWord(p); // 60 [93] (0 for ra4)
+}
+ if ver=5 then
+ begin
+ Info.khz:=GetLong(p) div 1000;
+ inc(p,8);
+{
+ GetLong(p); // equ KHZ
+ GetLong(p); // bits/channel?
+}
+ Info.channels:=GetWord(p);
+{
+ GetLong(p); // 'genr'
+ GetLong(p); // codec name
+ GetWord(p); // $01 $07
+ GetLong(p); // 0
+ GetWord(p); // channel data len (16-stereo,8-mono)
+ GetWord(p); // $01 $00
+ GetWord(p); // $00 $03[mono-2]
+ GetWord(p); // $04 [mono-2] $00
+ GetWord(p); //
+ if Info.channels=2 then
+ begin
+ GetLong(p); // 0
+ GetWord(p); // 01
+ GetWord(p); // 03
+ end
+}
+ end
+ else
+ begin
+ Info.khz:=GetWord(p) div 1000;
+ GetLong(p); // bits/channel?
+ Info.channels:=GetWord(p);
+{
+ SkipStr(p,1); // codec
+ SkipStr(p,1); // codec
+ GetWord(p); // $01 $07
+ inc(p,5);
+}
+ end
+ end;
+{
+ if StrCmp(tmpstr,'logical-fileinfo')=0 then
+ begin
+ GetLong(p); // a block len w/o
+ GetLong(p); // a block len with
+ GetLong(p); // 0
+ GetLong(p); // number of nodes
+ for i:=0 to Nodes-1 do
+ begin
+ GetLong(p); // node len with len dword
+ GetWord(p);
+ SkipStr(p,1); // node name
+ GetLong(p); // value type? 2 - asciiz
+ SkipStr(p,2); //node value
+ end;
+ end;
+}
+
+// if StrCmp(tmpstr,'Video Stream')=0 then
+ if StrCmp(ls,'video/x-pn-realvideo')=0 then
+ begin
+ GetLong(p); //stream dataLen;
+ Info.kbps:=GetLong(p); //override kbps
+ GetLong(p); //VIDO=vidtype
+ Info.codec:=ord(p[0])+(ord(p[1]) shl 8)+
+ (ord(p[2]) shl 16)+(ord(p[3]) shl 24); //codec ex.'RV30'
+ inc(p,4);
+ Info.width:=GetWord(p); //width
+ Info.height:=GetWord(p); //height
+ GetWord(p); //fps or colordeep
+ GetWord(p); //alt.width ?
+ GetWord(p); //alt. height ?
+ Info.fps:=GetWord(p)*100; //fps
+ {}
+ end;
+
+ mFreeMem(ls);
+ end;
+ mFreeMem(buf);
+ end
+ else if chunk.ID=blkRMMD then //comment
+ begin
+ Skip(f,chunk.Len-SizeOf(chunk));
+{
+ BlockRead(f,chunk,SizeOf(chunk)); //RJMD
+ chunk.len:=BSwap(chunk.len);
+ BlockRead(f,tmplong,4);
+
+
+ BlockRead(f,chunk,SizeOf(chunk)); //RMJE
+ chunk.len:=BSwap(chunk.len);
+}
+ end
+ else
+ begin
+ if chunk.ID=blk_RMF then
+ if FilePos(f)<>SizeOf(chunk) then // channels-1: ofs=$0A
+ break;
+ Skip(f,chunk.Len-SizeOf(chunk));
+ end;
+ end;
+ ReadID3v1(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLinkRM,
+ LocalFormatLinkRA,
+ LocalFormatLinkRAM:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkRM.Next:=FormatLink;
+
+ LocalFormatLinkRM.This.proc :=@ReadReal;
+ LocalFormatLinkRM.This.ext :='RM';
+ LocalFormatLinkRM.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkRM;
+
+ LocalFormatLinkRA.Next:=FormatLink;
+
+ LocalFormatLinkRA.This.proc :=@ReadReal;
+ LocalFormatLinkRA.This.ext :='RA';
+ LocalFormatLinkRA.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkRA;
+
+ LocalFormatLinkRAM.Next:=FormatLink;
+
+ LocalFormatLinkRAM.This.proc :=@ReadReal;
+ LocalFormatLinkRAM.This.ext :='RAM';
+ LocalFormatLinkRAM.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkRAM;
+end;
+
+initialization
+ InitLink;
+
+end.
diff --git a/plugins/Watrack/formats/fmt_tta.pas b/plugins/Watrack/formats/fmt_tta.pas
new file mode 100644
index 0000000000..c13b329fe2
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_tta.pas
@@ -0,0 +1,65 @@
+{TTA file}
+unit fmt_TTA;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadTTA(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format;
+
+const
+ TTA1_SIGN = $31415454;
+type
+ tTTAHeader = packed record
+ id :dword;
+ format :word;
+ channels :word;
+ bitspersample:word;
+ samplerate :dword;
+ datalength :dword;
+ crc32 :dword;
+ end;
+
+function ReadTTA(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ hdr:tTTAHeader;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ ReadID3v2(f,Info);
+ BlockRead(f,hdr,SizeOf(tTTAHeader));
+ if hdr.id<>TTA1_SIGN then
+ exit;
+ Info.channels:=hdr.channels;
+ Info.khz :=hdr.samplerate;
+ Info.kbps :=hdr.bitspersample div 1000; //!!
+ if hdr.samplerate<>0 then
+ Info.total:=hdr.datalength div hdr.samplerate;
+ ReadID3v1(f,Info);
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLink:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLink.Next:=FormatLink;
+
+ LocalFormatLink.This.proc :=@ReadTTA;
+ LocalFormatLink.This.ext :='TTA';
+ LocalFormatLink.This.flags:=0;
+
+ FormatLink:=@LocalFormatLink;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_wav.pas b/plugins/Watrack/formats/fmt_wav.pas
new file mode 100644
index 0000000000..98d8e18fb8
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_wav.pas
@@ -0,0 +1,146 @@
+{WAV processing}
+unit fmt_WAV;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadWAV(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,tags,srv_format;
+
+const
+ wavRIFF = $46464952;
+ wavWAVE = $45564157;
+ wavfmt_ = $20746D66;
+ wavfact = $74636166;
+ wavdata = $61746164;
+type
+ tWAVChunk = packed record
+ id :dword;
+ size:dword;
+ end;
+type
+ tWAVFormatChunk = packed record
+ Codec :word;
+ Channels :word;
+ SampleRate :dword;
+ AvgBPS :dword;
+ BlockAlign :word;
+ BitsPerSample:word;
+ end;
+
+const
+ WavPackID = $6B707677;
+type
+// ckID :dword; // "wvpk"
+// ckSize :dword; // size of entire frame (minus 8, of course)
+ tWavPackHeader = packed record
+ version :word; // 0x403 for now
+ track_no :byte; // track number (0 if not used, like now)
+ index_no :byte; // track sub-index (0 if not used, like now)
+ total_samples:dword; // for entire file (-1 if unknown)
+ block_index :dword; // index of first sample in block (to file begin)
+ block_samples:dword; // # samples in This block
+ flags :dword; // various flags for id and decoding
+ crc :dword; // crc for actual decoded data
+ end;
+
+function ReadWAV(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ chunk:tWAVChunk;
+ fmtchunk:tWAVFormatChunk;
+ tmp:dword;
+ WPH:tWavPackHeader;
+ fsize:dword;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+ BlockRead(f,chunk,SizeOf(chunk));
+ if chunk.id=WavPackID then
+ begin
+ BlockRead(f,WPH,SizeOf(tWavPackHeader));
+ BlockRead(f,tmp,2); //!! $1621 33,22
+ BlockRead(f,chunk,SizeOf(chunk));
+ end
+ else
+ begin
+ WPH.version:=0;
+ integer(WPH.total_samples):=-1;
+ end;
+ if chunk.id<>wavRIFF then
+ exit;
+ BlockRead(f,chunk,SizeOf(dword));
+ if chunk.id<>wavWAVE then
+ exit;
+ BlockRead(f,chunk,SizeOf(chunk));
+ if chunk.id<>wavfmt_ then
+ exit;
+ BlockRead(f,fmtchunk,SizeOf(tWAVFormatChunk));
+ Info.channels:=fmtchunk.Channels;
+ Info.khz :=fmtchunk.SampleRate div 1000;
+ if chunk.size>SizeOf(tWAVFormatChunk) then
+ Skip(f,chunk.size-SizeOf(tWAVFormatChunk));
+ fsize:=FileSize(f);
+ while FilePos(f)<fsize do
+ begin
+ BlockRead(f,chunk,SizeOf(chunk));
+ if chunk.id=wavfact then
+ begin
+ BlockRead(f,tmp,4);
+ break;
+ end;
+ if chunk.id=wavdata then
+ begin
+ tmp:=chunk.size;
+ break;
+ end;
+ Skip(f,chunk.size);
+ end;
+ if WPH.version<>0 then
+ begin
+ ReadAPEv2(f,Info);
+ ReadID3v1(f,Info);
+ end;
+ if integer(WPH.total_samples)=-1 then
+ if (fmtchunk.BitsPerSample<>0) and (fmtchunk.Channels<>0) then
+ WPH.total_samples:=(tmp*8) div (fmtchunk.Channels*fmtchunk.BitsPerSample);
+ if fmtchunk.SampleRate<>0 then
+ Info.total:= WPH.total_samples div fmtchunk.SampleRate;
+ if Info.total<>0 then
+ Info.kbps:=tmp*8 div Info.total div 1000;
+
+ CloseHandle(f);
+ result:=true;
+end;
+
+var
+ LocalFormatLinkWAV,
+ LocalFormatLinkWV:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkWAV.Next:=FormatLink;
+
+ LocalFormatLinkWAV.This.proc :=@ReadWAV;
+ LocalFormatLinkWAV.This.ext :='WAV';
+ LocalFormatLinkWAV.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkWAV;
+
+ LocalFormatLinkWV.Next:=FormatLink;
+
+ LocalFormatLinkWV.This.proc :=@ReadWAV;
+ LocalFormatLinkWV.This.ext :='WV';
+ LocalFormatLinkWV.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkWV;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/fmt_wma.pas b/plugins/Watrack/formats/fmt_wma.pas
new file mode 100644
index 0000000000..ed575147ac
--- /dev/null
+++ b/plugins/Watrack/formats/fmt_wma.pas
@@ -0,0 +1,438 @@
+{WMA file format}
+unit fmt_WMA;
+{$include compilers.inc}
+
+interface
+uses wat_api;
+
+function ReadWMA(var Info:tSongInfo):boolean; cdecl;
+
+implementation
+uses windows,common,io,srv_format,utils;
+
+const
+ ASF_Header_Object :tGUID='{75B22630-668E-11CF-A6D9-00AA0062CE6C}';
+
+ ASF_Header_Extension_Object :tGUID='{5FBF03B5-A92E-11CF-8EE3-00C00C205365}';
+ ASF_Content_Description_Object :tGUID='{75B22633-668E-11CF-A6D9-00AA0062CE6C}';
+ ASF_Extended_Content_Description_Object:tGUID='{D2D0A440-E307-11D2-97F0-00A0C95EA850}';
+ ASF_File_Properties_Object :tGUID='{8CABDCA1-A947-11CF-8EE4-00C00C205365}';
+ ASF_Stream_Properties_Object :tGUID='{B7DC0791-A9B7-11CF-8EE6-00C00C205365}';
+
+ ASF_Metadata_Library_Object :tGUID='{44231C94-9498-49D1-A141-1D134E457054}';
+ ASF_Audio_Media :tGUID='{F8699E40-5B4D-11CF-A8FD-00805F5C442B}';
+ ASF_Video_Media :tGUID='{BC19EFC0-5B4D-11CF-A8FD-00805F5C442B}';
+
+type
+ tSize=Int64;
+
+function CompareGUID(const guid1,guid2:tGUID):boolean;
+var
+ i:integer;
+ p1,p2:PAnsiChar;
+begin
+ p1:=PAnsiChar(@guid1);
+ p2:=PAnsiChar(@guid2);
+ for i:=0 to 15 do
+ begin
+ if p1^<>p2^ then
+ begin
+ result:=false;
+ exit;
+ end;
+ inc(p1);
+ inc(p2);
+ end;
+ result:=true;
+end;
+
+function ReadGUID(var buf:PAnsiChar; var guid:pGUID):dword;
+var
+ size:tSize;
+begin
+ guid:=pointer(buf);
+ inc(buf,SizeOf(tGUID));
+ move(buf^,size,SizeOf(size));
+ inc(buf,SizeOf(size));
+ result:=size-SizeOf(tGUID)-SizeOf(size);
+end;
+
+procedure ReadWMATagStr(var dst:pWideChar;ptr:PAnsiChar;alen:word);
+begin
+ if pword(ptr)^<>0 then
+ begin
+ mGetMem(dst,alen);
+ move(pWideChar(ptr{+2})^,dst^,alen);
+ end;
+end;
+
+function ReadWMATagStr1(var dst:pWideChar;var ptr:PAnsiChar;value:boolean=true):integer;
+var
+ len,typ:word;
+begin
+ if value then
+ begin
+ typ:=pword(ptr)^;
+ inc(ptr,2); //value type
+ end
+ else
+ typ:=0;
+ len:=pword(ptr)^;
+ result:=-1;
+ dst:=nil;
+ if len<>0 then
+ begin
+ if typ=0 then
+ begin
+ mGetMem(dst,len);
+ move(PAnsiChar(ptr+2)^,PAnsiChar(dst)^,len);
+ end
+ else
+ begin
+ result:=pword(ptr+2)^;
+ if typ<5 then
+ result:=pword(ptr+4)^*$10000+result;
+ end;
+ end;
+ inc(ptr,len+2);
+end;
+
+procedure ProcessPicture(ptr:PAnsiChar;var Info:tSongInfo);
+var
+ extw:int64;
+ aSize:dword;
+begin
+ if Info.cover<>nil then exit;
+ case ptr^ of
+ #0,#3,#4,#6: ;
+ else
+ exit;
+ end;
+ inc(ptr);
+ aSize:=pdword(ptr)^; inc(ptr,4);
+ extw:=GetImageTypeW(nil,pWideChar(ptr));
+ while pWideChar(ptr)^<>#0 do inc(ptr,2); inc(ptr,2); // mime
+ while pWideChar(ptr)^<>#0 do inc(ptr,2); inc(ptr,2); // descr
+
+ if extw=0 then
+ extw:=GetImageTypeW(pByte(ptr));
+ Info.cover:=SaveTemporaryW(ptr,aSize,pWideChar(@extw));
+end;
+
+procedure ReadHdrExtended(ptr:PAnsiChar;size:dword;var Info:tSongInfo);
+var
+ buf:PAnsiChar;
+ ls:pWideChar;
+ cnt,tmp:integer;
+ tmpguid:pGUID;
+ lsize:dword;
+begin
+ inc(ptr,SizeOf(tGUID)+2);
+ size:=pdword(ptr)^; inc(ptr,4);
+ while size>0 do
+ begin
+ if Info.cover<>nil then break;
+ lsize:=ReadGUID(ptr,tmpguid);
+ dec(size,lsize+SizeOf(tGUID)+SizeOf(tSize));
+ if CompareGUID(tmpguid^,ASF_Metadata_Library_Object) then
+ begin
+ buf:=ptr;
+ cnt:=pdword(buf)^; inc(buf,2);
+ while cnt>0 do
+ begin
+ inc(buf,4); // lang & stream
+ {tmp:=pword (buf)^;} inc(buf,2); // namelen
+ {tmp:=pword (buf)^;} inc(buf,2); // datatype
+ tmp:=pdword(buf)^; inc(buf,4); // datalen
+ ls:=PWideChar(buf);
+ while pWideChar(buf)^<>#0 do inc(buf,2); inc(buf,2);
+ if lstrcmpiw(ls,'WM/Picture')=0 then
+ begin
+ ProcessPicture(buf,Info);
+ inc(buf,tmp);
+ end;
+ dec(cnt);
+ end;
+ end;
+ inc(ptr,lsize);
+ end;
+end;
+
+procedure ReadExtended(ptr:PAnsiChar;size:dword;var Info:tSongInfo);
+var
+ ls,ls1,ls2:pWideChar;
+ cnt,tmp:integer;
+begin
+ cnt:=pword(ptr)^; inc(ptr,2);
+ while cnt>0 do
+ begin
+ dec(cnt);
+ ReadWMATagStr1(ls,ptr,false);
+ if lstrcmpiw(ls,'WM/AlbumTitle')=0 then
+ ReadWMATagStr1(Info.album,ptr)
+ else if (Info.lyric=nil) and (lstrcmpiw(ls,'WM/Lyrics')=0) then
+ ReadWMATagStr1(Info.lyric,ptr)
+ else if (Info.lyric=nil) and (lstrcmpiw(ls,'WM/Lyrics_Synchronised')=0) then
+ begin
+ inc(ptr,2+2);
+ inc(ptr); // timestamp type
+ if ptr^=#1 then // lyric
+ begin
+ inc(ptr);
+ tmp:=pdword(ptr)^; inc(ptr,4);
+ mGetMem(ls2,tmp);
+ Info.lyric:=ls2;
+ ls1:=pWideChar(ptr);
+ inc(ptr,tmp);
+ while ls1^<>#0 do // description
+ begin
+ inc(ls1);
+ dec(tmp,SizeOf(WideChar));
+ end;
+ inc(ls1);
+ dec(tmp,SizeOf(WideChar));
+ while tmp>0 do
+ begin
+ if PAnsiChar(ls1)^=#$0A then
+ begin
+ inc(PAnsiChar(ls1));
+ ls2^:=#$0A;
+ dec(tmp);
+ inc(ls2);
+ end;
+ while ls1^<>#0 do
+ begin
+ ls2^:=ls1^; inc(ls2); inc(ls1);
+ dec(tmp,SizeOf(WideChar));
+ end;
+ inc(ls1,1+2); // terminator + timestamp
+ dec(tmp,SizeOf(WideChar)+4);
+ end;
+ ls2^:=#0;
+// ptr:=PAnsiChar(ls1);
+ end
+ end
+ else if lstrcmpiw(ls,'WM/Genre')=0 then
+ ReadWMATagStr1(Info.genre,ptr)
+ else if lstrcmpiw(ls,'WM/Year')=0 then
+ begin
+ tmp:=ReadWMATagStr1(Info.year,ptr);
+ if tmp<>-1 then
+ IntToStr(Info.year,tmp);
+ end
+ else if lstrcmpiw(ls,'WM/Track')=0 then
+ begin
+ tmp:=ReadWMATagStr1(ls1,ptr);
+ if tmp=-1 then
+ begin
+ Info.track:=StrToInt(ls1)+1;
+ mFreeMem(ls1);
+ end
+ else
+ Info.track:=tmp;
+ end
+ else if lstrcmpiw(ls,'WM/TrackNumber')=0 then
+ begin
+ tmp:=ReadWMATagStr1(ls1,ptr);
+ if tmp=-1 then
+ begin
+ Info.track:=StrToInt(ls1);
+ mFreeMem(ls1);
+ end
+ else
+ Info.track:=tmp;
+ end
+ else if lstrcmpiw(ls,'WM/Picture')=0 then
+ begin
+ inc(ptr,2); // data type
+ tmp:=pword(ptr)^; inc(ptr,2);
+ ProcessPicture(ptr,Info);
+ inc(ptr,tmp);
+ end
+ else
+ inc(ptr,4+pword(ptr+2)^);
+ mFreeMem(ls);
+ end;
+end;
+
+procedure ReadFileProp(ptr:PAnsiChar;var Info:tSongInfo);
+type
+ pFileProp = ^tFileProp;
+ tFileProp = packed record
+ FileGUID :tGUID;
+ FileSize :tSize;
+ Creation :tSize;
+ Packets :tSize;
+ Play :tSize;
+ Send :tSize;
+ PreRoll :tSize;
+ Flags :dword;
+ minpacket :dword;
+ maxpacket :dword;
+ maxbitrate:dword;
+ end;
+begin
+ Info.total:=pFileProp(ptr)^.Play div 10000000;
+end;
+
+procedure ReadStreamProp(ptr:PAnsiChar;size:dword;var Info:tSongInfo);
+type
+ pAudio = ^tAudio;
+ tAudio=packed record // WAVEFORMATEX
+ Codec :word;
+ Channels :word;
+ Samples :dword;
+ AvgBPS :dword;
+ BlockAlign :word;
+ BitsPerSample:word;
+ size :word;
+ end;
+ pVideo = ^tVideo;
+ tVideo = packed record
+ width :dword;
+ height :dword;
+ reserved:byte;
+ size :word;
+ bitmap :BITMAPINFOHEADER;
+ end;
+ Prefix = packed record
+ StreamType :tGUID;
+ ECGUID :tGUID; // Error Correction
+ TimeOffset :int64;
+ DataLength :dword;
+ ECDataLength:dword;
+ Flags :word;
+ Reserved :dword;
+ end;
+
+var
+ tmpguid:pGUID;
+begin
+ tmpguid:=pointer(ptr);
+ inc(ptr,SizeOf(Prefix)); //ofset to Type-Specific Data
+ if CompareGUID(tmpguid^,ASF_Audio_Media) then
+ begin
+ Info.channels:=pAudio(ptr)^.Channels;
+ Info.khz :=pAudio(ptr)^.Samples div 1000;
+ Info.kbps :=(pAudio(ptr)^.AvgBPS*8) div 1000;
+ end
+ else if CompareGUID(tmpguid^,ASF_Video_Media) then
+ begin
+ Info.width :=pVideo(ptr)^.bitmap.biWidth; // pVideo(ptr)^.width
+ Info.height:=pVideo(ptr)^.bitmap.biHeight; // pVideo(ptr)^.height
+ Info.codec :=pVideo(ptr)^.bitmap.biCompression;
+ end
+end;
+
+procedure ReadContent(ptr:PAnsiChar;var Info:tSongInfo);
+type
+ pContent = ^tContent;
+ tContent = packed record
+ TitleLength :word;
+ AuthorLength :word;
+ CopyrightLength :word;
+ DescriptionLength:word;
+ RatingLength :word;
+ end;
+var
+ cont:pContent;
+begin
+ cont:=pointer(ptr);
+ inc(ptr,SizeOf(tContent));
+ if cont^.TitleLength>0 then //title
+ begin
+ ReadWMATagStr(Info.title,ptr,cont^.TitleLength);
+ inc(ptr,cont^.TitleLength);
+ end;
+ if cont^.AuthorLength>0 then //artist
+ begin
+ ReadWMATagStr(Info.artist,ptr,cont^.AuthorLength);
+ inc(ptr,cont^.AuthorLength);
+ end;
+ inc(ptr,cont^.CopyrightLength); //copyright
+ if cont^.DescriptionLength>0 then //comment
+ ReadWMATagStr(Info.comment,ptr,cont^.DescriptionLength);
+end;
+
+function ReadWMA(var Info:tSongInfo):boolean; cdecl;
+var
+ f:THANDLE;
+ tmpguid:pGUID;
+ size:int64;
+ buf1,buf2:PAnsiChar;
+ HdrObjects:dword;
+ base:tGUID;
+begin
+ result:=false;
+ f:=Reset(Info.mfile);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ exit;
+
+ BlockRead(f,base,SizeOf(tGUID));
+ if CompareGUID(base,ASF_Header_Object) then
+ begin
+ BlockRead(f,size,SizeOf(size));
+ dec(size,SizeOf(tGUID)+SizeOf(size));
+
+ GetMem(buf1,size);
+ buf2:=buf1;
+ BlockRead(f,buf1^,size);
+ HdrObjects:=pdword(buf2)^; inc(buf2,6);
+ while HdrObjects>0 do
+ begin
+ size:=ReadGUID(buf2,tmpguid);
+ if CompareGUID(tmpguid^,ASF_Content_Description_Object) then
+ ReadContent(buf2,Info)
+ else if CompareGUID(tmpguid^,ASF_Extended_Content_Description_Object) then
+ ReadExtended(buf2,size,Info)
+ else if CompareGUID(tmpguid^,ASF_Header_Extension_Object) then
+ ReadHdrExtended(buf2,size,Info)
+ else if CompareGUID(tmpguid^,ASF_File_Properties_Object) then
+ ReadFileProp(buf2,Info)
+ else if CompareGUID(tmpguid^,ASF_Stream_Properties_Object) then
+ ReadStreamProp(buf2,size,Info);
+ inc(buf2,size);
+ dec(HdrObjects);
+ end;
+ FreeMem(buf1);
+
+ result:=true;
+ end;
+ CloseHandle(f);
+end;
+
+var
+ LocalFormatLinkWMA,
+ LocalFormatLinkWMV,
+ LocalFormatLinkASF:twFormat;
+
+procedure InitLink;
+begin
+ LocalFormatLinkWMA.Next:=FormatLink;
+
+ LocalFormatLinkWMA.This.proc :=@ReadWMA;
+ LocalFormatLinkWMA.This.ext :='WMA';
+ LocalFormatLinkWMA.This.flags:=0;
+
+ FormatLink:=@LocalFormatLinkWMA;
+
+ LocalFormatLinkWMV.Next:=FormatLink;
+
+ LocalFormatLinkWMV.This.proc :=@ReadWMA;
+ LocalFormatLinkWMV.This.ext :='WMV';
+ LocalFormatLinkWMV.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkWMV;
+
+ LocalFormatLinkASF.Next:=FormatLink;
+
+ LocalFormatLinkASF.This.proc :=@ReadWMA;
+ LocalFormatLinkASF.This.ext :='ASF';
+ LocalFormatLinkASF.This.flags:=WAT_OPT_VIDEO;
+
+ FormatLink:=@LocalFormatLinkASF;
+end;
+
+initialization
+ InitLink;
+end.
diff --git a/plugins/Watrack/formats/tag_apev2.inc b/plugins/Watrack/formats/tag_apev2.inc
new file mode 100644
index 0000000000..34ab7f2ad7
--- /dev/null
+++ b/plugins/Watrack/formats/tag_apev2.inc
@@ -0,0 +1,124 @@
+{APE tag}
+{$IFDEF Interface}
+function ReadAPEv2(buf:PAnsiChar;var Info:tSongInfo;count:integer=0):longint; overload;
+function ReadAPEv2(f:THANDLE;var Info:tSongInfo):longint; overload;
+{$ELSE}
+const
+ APESign = 'APETAGEX';
+type
+ pAPEHeader = ^tAPEHeader;
+ tAPEHeader = packed record
+ ID:array [0..7] of AnsiChar;
+ Version:dword;
+ TagSize:dword; //footer + all items
+ ItemCount:dword;
+ TagFlags:dword;
+ Reserved:array [0..7] of byte;
+ end;
+
+procedure ReadAPEValue(const buf:PAnsiChar;var dst:pWideChar;ver:dword);
+begin
+ if dst=nil then
+ if ver>1000 then
+ UTF8ToWide(buf,dst)
+ else
+ AnsiToWide(buf,dst);
+end;
+
+function ReadAPEv2(buf:PAnsiChar;var Info:tSongInfo;count:integer=0):longint;
+var
+ APE:pAPEHeader;
+ len:integer;
+ ptr,key:PAnsiChar;
+ flag:dword;
+ cf:THANDLE;
+ buf0,buf1:array [0..MAX_PATH-1] of AnsiChar;
+ b:AnsiChar;
+// extw:array [0..7] of WideChar;
+begin
+ result:=0;
+ APE:=pointer(buf);
+ if APE.ID=APESign then
+ begin
+ inc(buf,SizeOf(tAPEHeader));
+ count:=APE.ItemCount;
+ end;
+ while count>0 do
+ begin
+ len :=pdword(buf)^; inc(buf,4);
+ flag:=pdword(buf)^; inc(buf,4);
+ key:=buf;
+ while buf^<>#0 do inc(buf); inc(buf);
+
+ ptr:=buf+len;
+ b:=ptr^;
+ ptr^:=#0;
+ if lstrcmpia(key,'TITLE' )=0 then ReadAPEValue(buf,Info.title ,APE.Version)
+ else if lstrcmpia(key,'ARTIST' )=0 then ReadAPEValue(buf,Info.artist ,APE.Version)
+ else if lstrcmpia(key,'ALBUM' )=0 then ReadAPEValue(buf,Info.album ,APE.Version)
+ else if lstrcmpia(key,'COMMENT')=0 then ReadAPEValue(buf,Info.comment,APE.Version)
+ else if lstrcmpia(key,'GENRE' )=0 then ReadAPEValue(buf,Info.genre ,APE.Version)
+ else if lstrcmpia(key,'YEAR' )=0 then ReadAPEValue(buf,Info.year ,APE.Version)
+ else if lstrcmpia(key,'TRACK' )=0 then if Info.track=0 then Info.track:=StrToInt(buf)
+ else if lstrcmpia(key,'LYRICS' )=0 then ReadAPEValue(buf,Info.lyric ,APE.Version)
+ //!! must preserve multipart lyric
+ else if (lstrcmpia(key,'Cover Art (Front)')=0) or
+ (lstrcmpia(key,'Cover Art (Back)' )=0) or
+ (lstrcmpia(key,'APIC' )=0) then
+ begin
+ if Info.cover=nil then
+ begin
+ while buf^<>#0 do inc(buf); inc(buf); // point to data now
+ flag:=GetImageType(pByte(buf));
+ if flag<>0 then
+ begin
+{
+ FastAnsiToWideBuf(PAnsiChar(@flag),pWideChar(@extw));
+ Info.Cover:=SaveTemporaryW(buf,ptr-buf,PWideChar(@extw));
+}
+ GetTempPathA(SizeOf(buf0),buf0);
+ GetTempFileNameA(buf0,'wat',GetCurrentTime,buf1);
+ ChangeExt(buf1,PAnsiChar(@flag));
+
+ cf:=ReWrite(PAnsiChar(@buf1));
+ BlockWrite(cf,buf^,ptr-buf);
+ CloseHandle(cf);
+ AnsiToWide(PAnsiChar(@buf1),Info.cover);
+ end;
+ end;
+ end;
+ ptr^:=b;
+ buf:=ptr;
+ dec(count);
+ end;
+end;
+
+function ReadAPEv2(f:THANDLE;var Info:tSongInfo):longint;
+var
+ APE:tAPEHeader;
+ buf:PAnsiChar;
+ fpos:dword;
+ TagID:array [1..3] of AnsiChar;
+begin
+ result:=0;
+ fpos:=FileSize(f);
+ Seek(f,fpos-SizeOf(TID3v1Tag));
+ BlockRead(f,TagID,3);
+ if TagID=TAG1Sign then
+ dec(fpos,SizeOf(TID3v1Tag));
+ Seek(f,fpos-SizeOf(APE));
+ BlockRead(f,APE,SizeOf(APE));
+ // footer must be copied as header
+ if APE.ID=APESign then
+ begin
+ if (APE.TagFlags and $20000000)=0 then //Footer
+ begin
+ Seek(f,fpos-APE.TagSize{-SizeOf(APE)});// without header but with footer
+ GetMem(buf,APE.TagSize);
+ BlockRead(f,buf^,APE.TagSize);
+ result:=ReadAPEv2(buf,Info,APE.ItemCount);
+ FreeMem(buf);
+ end;
+ end;
+end;
+{$ENDIF}
diff --git a/plugins/Watrack/formats/tag_id3v1.inc b/plugins/Watrack/formats/tag_id3v1.inc
new file mode 100644
index 0000000000..bd1db906bb
--- /dev/null
+++ b/plugins/Watrack/formats/tag_id3v1.inc
@@ -0,0 +1,175 @@
+{ID3v1 tag}
+{$IFDEF Interface}
+const
+ TAG1Sign = 'TAG';
+type
+ TID3v1Tag = packed record
+ ID: array [0..2] of AnsiChar;
+ Title: array [0..29] of AnsiChar;
+ Artist: array [0..29] of AnsiChar;
+ Album: array [0..29] of AnsiChar;
+ Year: array [0..3] of AnsiChar;
+ Comment: array [0..28] of AnsiChar;
+ Track: byte;
+ Genre: byte;
+ end;
+
+function ReadID3v1(f:THANDLE; var Info:tSongInfo):longint;
+{$ELSE}
+const
+ Lyric1End = 'LYRICSEND';
+ LyricStart = 'LYRICSBEGIN';
+ Lyric2End = 'LYRICS200';
+ LyricEndLen = Length(Lyric1End);
+const
+ fIND = $494E44;
+ fLYR = $4C5952;
+ fEAL = $45414C;
+ fEAR = $454152;
+ fETT = $455454;
+ fIMG = $494D47;
+ fINF = $494E46;
+
+procedure ID3v1_TagCorrect(var dst:pWideChar;const tag:array of AnsiChar);
+var
+ i:integer;
+ s:array [0..31] of AnsiChar;
+begin
+ i:=High(tag);
+ move(tag,s,i+1);
+ while (i>0) and (tag[i]<=' ') do dec(i);
+ if i>0 then
+ begin
+ s[i+1]:=#0;
+ AnsiToWide(s,dst);
+ end;
+end;
+
+procedure ID3v1_GetField(ptr:PAnsiChar; var dst:pWideChar; len:integer);
+var
+ txtfield:array [0..250] of AnsiChar;
+begin
+ if dst=nil then
+ begin
+ move(ptr^,txtfield,len);
+ txtfield[len]:=#0;
+ AnsiToWide(txtfield,dst);
+ end;
+end;
+
+procedure ID3v1_CheckLyric(var Info:tSongInfo;f:THANDLE;ofs:integer);
+const
+ maxlen = 5100;
+var
+ tagHdr:array [0..9] of AnsiChar;
+ buf:array [0..maxlen] of AnsiChar;
+ ptr,ptr1:PAnsiChar;
+ i,size:integer;
+ field:dword;
+ c:dword;
+begin
+ Seek(f,ofs);
+ BlockRead(f,tagHdr,LyricEndLen);
+ tagHdr[9]:=#0;
+ if StrCmp(tagHdr,Lyric1End,LyricEndLen)=0 then
+ begin
+ if Info.lyric=nil then
+ begin
+ Seek(f,ofs-maxlen);
+ BlockRead(f,buf,maxlen);
+ buf[maxlen]:=#0;
+ ptr:=@buf;
+ for i:=0 to maxlen-Length(LyricStart) do
+ begin
+ if ptr^='L' then
+ if StrCmp(ptr,LyricStart,Length(LyricStart))=0 then
+ begin
+ AnsiToWide(ptr+Length(LyricStart),Info.lyric);
+ break;
+ end;
+ inc(ptr);
+ end;
+ end;
+ end
+ else if StrCmp(tagHdr,Lyric2End,LyricEndLen)=0 then
+ begin
+ Seek(f,ofs-6);
+ BlockRead(f,buf,6);
+ size:=StrToInt(buf);
+ if size<ofs then
+ begin
+ Seek(f,ofs-size-6);
+ mGetMem(ptr,size+1);
+ BlockRead(f,ptr^,size);
+ if StrCmp(ptr,LyricStart,Length(LyricStart))=0 then
+ begin
+ ptr1:=ptr+Length(LyricStart);
+
+ while ptr1<ptr+size do
+ begin
+ field:=(ORD(ptr1^) shl 16)+(ORD((ptr+1)^) shl 8)+ORD((ptr1+2)^);
+ inc(ptr1,3);
+ move(ptr1^,buf,5);
+ buf[5]:=#0;
+ i:=StrToInt(buf);
+ inc(ptr1,5);
+ case field of
+ fLYR: if Info.lyric=nil then
+ begin
+ c:=pword(ptr1+i)^;
+ pword(ptr1+i)^:=0;
+ if (pword(ptr1)^=$FFFE) or ((pword(ptr1)^=$FEFF)) then
+ begin
+ StrDupW(Info.lyric,pWidechar(ptr1));
+ ChangeUnicode(Info.lyric);
+ end
+ else
+ begin
+ AnsiToWide(ptr1,Info.lyric);
+ end;
+ pword(ptr1+i)^:=c;
+ end;
+ fEAL: ID3v1_GetField(ptr1,Info.album,i);
+ fEAR: ID3v1_GetField(ptr1,Info.artist,i);
+ fETT: ID3v1_GetField(ptr1,Info.title,i);
+// fINF:
+// fIMG:
+ end;
+ inc(ptr1,i);
+ end;
+ end;
+ mFreeMem(ptr);
+ end;
+ end;
+end;
+
+function ReadID3v1(f:THANDLE; var Info:tSongInfo):longint;
+var
+ tag:TID3v1Tag;
+ ofs:integer;
+begin
+ result:=0;
+ ofs:=FileSize(f)-SizeOf(tag);
+ Seek(f,ofs);
+ BlockRead(f,tag,SizeOf(tag));
+ if tag.ID=TAG1Sign then
+ begin
+ if Info.album =nil then ID3v1_TagCorrect(Info.album ,tag.Album);
+ if Info.artist =nil then ID3v1_TagCorrect(Info.artist ,tag.Artist);
+ if Info.title =nil then ID3v1_TagCorrect(Info.title ,tag.Title);
+ if Info.comment=nil then ID3v1_TagCorrect(Info.comment,tag.Comment);
+ if Info.year =nil then ID3v1_TagCorrect(Info.year ,tag.Year);
+ if Info.genre =nil then Info.genre:=GenreName(tag.Genre);
+ if Info.track=0 then
+ begin
+ Info.track:=tag.Track;
+ if Info.track >=32 then Info.track:=0;
+ end;
+ dec(ofs,9);
+ result:=1;
+ end
+ else
+ inc(ofs,SizeOf(tag)-9);
+ ID3v1_CheckLyric(Info,f,ofs); // +skipAPEtag
+end;
+{$ENDIF}
diff --git a/plugins/Watrack/formats/tag_id3v2.inc b/plugins/Watrack/formats/tag_id3v2.inc
new file mode 100644
index 0000000000..b1f833ea2a
--- /dev/null
+++ b/plugins/Watrack/formats/tag_id3v2.inc
@@ -0,0 +1,545 @@
+{ID3v2 tag}
+
+{$IFDEF Interface}
+function ReadID3v2(f:THANDLE; var Info:tSongInfo):longint;
+{$ELSE}
+const
+ frmTRK = $4B5254;
+ frmTT2 = $325454;
+ frmTP1 = $315054;
+ frmTAL = $4C4154;
+ frmTYE = $455954;
+ frmCOM = $4D4F43;
+ frmTCO = $4F4354;
+// frmTCM = $;'; New: 'TCOM'),
+// frmTEN = $;'; New: 'TENC'),
+// frmTCR = $;'; New: 'TCOP'),
+// frmWXX = $;'; New: 'WXXX'),
+ frmTT1 = $315454;
+// frmTLA = $;'; New: 'TLAN'),
+ frmTOA = $414F54;
+ frmULT = $544C55;
+ frmSLT = $544C53;
+ frmTXX = $585854;
+ frmPIC = $434950;
+
+ frmTIT1 = $31544954; // Content group description
+ frmTIT2 = $32544954; // Title/songname/content description
+ frmTIT3 = $33544954; // Subtitle/Description refinement
+ frmTALB = $424C4154; // Album/Movie/Show title
+ frmTOAL = $4C414F54; // Original album/movie/show title
+ frmTRCK = $4B435254; // Track number/Position in set
+ frmTYER = $52455954; // Year
+ frmTDRC = $43524454; // Year
+ frmTORY = $59524F54; // Original release year
+ frmTPE1 = $31455054; // Lead performer(s)/Soloist(s)
+ frmTPE2 = $32455054; // Band/orchestra/accompaniment
+ frmTPE3 = $33455054; // Conductor/performer refinement
+ frmTPE4 = $34455054; // Interpreted, remixed, or otherwise modified by
+ frmTOPE = $45504F54; // Original artist(s)/performer(s)
+ frmTCON = $4E4F4354; // Content type
+ frmCOMM = $4D4D4F43; // Comments
+ frmUSLT = $544C5355; // Unsynchronised lyrics
+ frmSYLT = $544C5953; // Synchronised lyrics
+ frmTXXX = $58585854; // User defined text
+ frmAPIC = $43495041; // Attached picture
+const
+ TAG2Sign = 'ID3';
+const
+ ExtIDHdrMask=$40;
+ FooterPresent=$10;
+type
+ TID3v2TagHdr = packed record
+ ID :array [0..2] of AnsiChar;
+ Version:word;
+ Flags :byte;
+ TagSize:dword;
+ end;
+ PID3v2TagHdr = ^TID3v2TagHdr;
+type
+ tID3v2FrameHdr = packed record
+ ID:dword;
+ Size:dword;
+ Flags:word;
+ end;
+ pID3v2FrameHdr = ^tID3v2FrameHdr;
+ tID3v2FrameHdrOld = packed record
+ ID : array [0..2] of byte; { Frame ID }
+ Size: array [0..2] of Byte; { Size excluding header }
+ end;
+ pID3v2FrameHdrOld = ^tID3v2FrameHdrOld;
+
+var
+ Unsync:boolean;
+
+function ID3v2_Correct(data:dword):dword;
+type
+ l2b=packed record
+ b:array [0..3] of byte;
+ end;
+begin
+ result:=l2b(data).b[3];
+ inc(result,dword(l2b(data).b[0]) shl 21);
+ inc(result,dword(l2b(data).b[1]) shl 14);
+ inc(result,dword(l2b(data).b[2]) shl 7);
+end;
+
+procedure ID3v2_ReadTagStr1(var dst:PWideChar;ptr:PAnsiChar;alen:integer;enc:integer);
+var
+ buf:PAnsiChar;
+begin
+ if (enc=0) or (enc=3) then // ANSI or UTF8
+ begin
+ if ptr^=#0 then
+ alen:=0
+ else
+ while (alen>0) and (ptr[alen-1]=#0) do dec(alen);
+
+ if alen>0 then
+ begin
+{
+ if enc=0 then
+ begin
+ StrDup(buf,ptr,alen);
+ AnsiToWide(buf,dst)
+ mFreeMem(buf);
+ end
+ else
+ UTF8ToWide(buf,dst,alen);
+}
+ StrDup(buf,ptr,alen);
+ if enc=0 then
+ AnsiToWide(buf,dst)
+ else
+ UTF8ToWide(buf,dst);
+ mFreeMem(buf);
+ end
+ end
+ else {if enc<3 then} //Unicode
+ begin
+ if pword(ptr)^>0 then
+ begin
+ alen:=alen div SizeOf(WideChar);
+
+ StrDupW(dst,pWideChar(ptr),alen);
+ ChangeUnicode(dst);
+ end;
+ end;
+end;
+
+procedure ID3v2_ReadTagStr(var dst:PWideChar;ptr:PAnsiChar;alen:integer);
+var
+ enc:byte;
+begin
+ enc:=ORD(ptr^);
+ inc(ptr);
+ dec(alen);
+ if alen>0 then
+ ID3v2_ReadTagStr1(dst,ptr,alen,enc)
+ else
+ dst:=nil;
+end;
+
+procedure ID3v2_CheckLyric(tag:integer; var dst:PWideChar;ptr:PAnsiChar;len:integer);
+var
+ org,org1:PAnsiChar;
+ orgw,ptrw:pWideChar;
+ buf:array [0..127] of AnsiChar;
+ enc:byte;
+begin
+ if dst<>NIL then exit;
+ enc:=ord(ptr^);
+ inc(ptr);
+ if tag=frmUSLT then
+ begin
+ org:=ptr;
+ inc(ptr,3); // language
+ if (enc=0) or (enc=3) then
+ begin
+ while ptr^<>#0 do inc(ptr);
+ inc(ptr);
+ end
+ else
+ begin
+ while pWord(ptr)^<>0 do inc(ptr,2);
+ inc(ptr,2);
+ end;
+ dec(len,ptr-org);
+ ID3v2_ReadTagStr1(dst,ptr,len,enc);
+ end
+ else if tag=frmSYLT then
+ begin
+ inc(ptr,4);
+ if ptr^<>#1 then exit; // 1 - lyric
+ inc(ptr);
+ mGetMem(dst,len-6);
+ FillChar(dst^,len-6,0);
+
+ if (enc=0) or (enc=3) then
+ begin
+ while ptr^<>#0 do
+ begin
+ inc(ptr);
+ dec(len);
+ end;
+ inc(ptr);
+ dec(len);
+ org:=PAnsiChar(dst);
+ while len>0 do
+ begin
+ while ptr^<>#0 do
+ begin
+ org^:=ptr^; inc(org); inc(ptr);
+ dec(len);
+ end;
+ inc(ptr,1+4); // terminator+timestamp
+ dec(len,1+4);
+ end;
+ org:=PAnsiChar(dst);
+ if enc=0 then
+ AnsiToWide(org,dst)
+ else
+ UTF8ToWide(org,dst);
+ mFreeMem(org);
+ end
+ else
+ begin
+ orgw:=dst;
+ ptrw:=pWideChar(ptr);
+ while ptrw^<>#0 do
+ begin
+ inc(ptrw);
+ dec(len,SizeOf(WideChar));
+ end;
+ inc(ptrw);
+ dec(len,SizeOf(WideChar));
+ while len>0 do
+ begin
+ while ptrw^<>#0 do
+ begin
+ orgw^:=ptrw^; inc(orgw); inc(ptrw);
+ dec(len,SizeOf(WideChar));
+ end;
+ inc(ptrw,1+2); // terminator + timestamp
+ dec(len,SizeOf(WideChar)+4);
+ end;
+ end;
+ end
+ else if tag=frmTXXX then
+ begin
+ FillChar(buf,SizeOf(buf),0);
+ org1:=ptr;
+ if (enc=0) or (enc=3) then
+ begin
+ org:=@buf;
+ while ptr^<>#0 do
+ begin
+ org^:=ptr^;
+ inc(org);
+ inc(ptr);
+ end;
+ inc(ptr);
+ if StrCmp(buf,'LYRICS')<>0 then
+ exit;
+ end
+ else
+ begin
+ orgw:=@buf;
+ ptrw:=pWideChar(ptr);
+ while ptrw^<>#0 do
+ begin
+ orgw^:=ptrw^;
+ inc(orgw);
+ inc(ptrw);
+ end;
+ inc(ptrw);
+ if StrCmpW(pWideChar(@buf),'LYRICS')<>0 then
+ exit;
+ ptr:=PAnsiChar(ptrw);
+ end;
+ dec(len,ptr-org1);
+ ID3v2_ReadTagStr1(dst,ptr,len,enc);
+ end;
+end;
+
+procedure ID3v2_CheckCover(tag:integer; var dst:pWideChar;ptr:PAnsiChar;len:integer);
+var
+ org:PAnsiChar;
+ ext:dword;
+ extw:int64;
+ enc:byte;
+begin
+ if dst<>nil then exit;
+ org:=ptr;
+ enc:=ord(ptr^); inc(ptr);
+ if (pdword(ptr)^ and $FFFFFF)=$3E2D2D then exit; // as '-->'
+ if tag=frmAPIC then
+ begin
+ ext:=GetImageType(nil,ptr);
+ repeat inc(ptr) until ptr^=#0; inc(ptr);
+ end
+ else
+ begin
+ ext:=pdword(ptr)^ and $FFFFFF;
+ inc(ptr,3);
+ end;
+
+ if not ord(ptr^) in [0,3,4,6] then exit;
+ inc(ptr);
+ if (enc=0) or (enc=3) then
+ begin
+ while ptr^<>#0 do inc(ptr);
+ inc(ptr);
+ end
+ else
+ begin
+ while pWord(ptr)^<>0 do inc(ptr,2);
+ inc(ptr,2);
+ end;
+ dec(len,ptr-org);
+
+ if ext=0 then
+ ext:=GetImageType(pByte(ptr));
+ if ext<>0 then
+ begin
+ FastAnsiToWideBuf(PAnsiChar(@ext),pWideChar(@extw));
+ dst:=SaveTemporaryW(ptr,len,PWideChar(@extw));
+ end;
+end;
+
+function ID3v2_PreReadTag(var frm:tID3v2FrameHdr;var src:PAnsiChar;ver:integer):PAnsiChar;
+var
+ i:cardinal;
+ dst:PAnsiChar;
+begin
+ mGetMem(result,frm.Size);
+ if Unsync or ((frm.Flags and $0200)<>0) then
+ begin
+ dst:=result;
+ i:=0;
+ while i<frm.Size do
+ begin
+ dst^:=src^;
+ inc(src);
+ if (dst^=#$FF) and (src^=#0) then
+ begin
+ inc(src);
+ if ver=4 then inc(i);
+ end;
+ inc(dst);
+ inc(i);
+ end
+ end
+ else
+ begin
+ move(src^,result^,frm.Size);
+ inc(src,frm.Size);
+ end;
+end;
+
+procedure ID3v2_ReadTag2(ver:integer;tag:PAnsiChar;Size:integer;var Info:tSongInfo);
+type
+ a=array [0..3] of byte;
+var
+ Frm:tID3v2FrameHdr;
+ FrmOld:tID3v2FrameHdrOld;
+ tmp:integer;
+ ls:pWideChar;
+ lp:PAnsiChar;
+ ptr,buf:PAnsiChar;
+ fArtist,fTitle,fAlbum:integer;
+ enc:byte;
+begin
+ lp:=tag+Size;
+ fArtist:=0;
+ fTitle :=0;
+ fAlbum :=0;
+ while tag<lp do
+ begin
+ case ver of
+ 1,2: begin
+ move(tag^,FrmOld,SizeOf(FrmOld));
+ Frm.Flags:=0;
+ Frm.ID:=FrmOld.ID[0]+(FrmOld.ID[1] shl 8)+(FrmOld.ID[2] shl 16);
+ Frm.Size:=(FrmOld.Size[0] shl 16)+(FrmOld.Size[1] shl 8)+FrmOld.Size[2];
+ inc(tag,SizeOf(tID3v2FrameHdrOld));
+ end;
+ 3: begin
+ move(tag^,Frm,SizeOf(Frm));
+ Frm.Size:=BSwap(Frm.Size);
+ inc(tag,SizeOf(tID3v2FrameHdr));
+ end;
+ 4: begin
+ move(tag^,Frm,SizeOf(Frm));
+ Frm.Size:=ID3v2_Correct(Frm.Size);
+ inc(tag,SizeOf(tID3v2FrameHdr));
+ if (Frm.Flags and $0100)<>0 then
+ begin
+ Frm.Size:=ID3v2_Correct(pdword(tag)^);
+ inc(tag,4);
+ end;
+ end;
+ end;
+
+ if Frm.ID=0 then
+ break;
+ if Frm.Size=0 then
+ continue;
+ if (tag+Frm.Size)>lp then
+ break;
+ buf:=ID3v2_PreReadTag(Frm,tag,ver);
+
+ enc:=ord(buf^);
+ case enc of // set priority
+ 0: enc:=1;
+ 1,2: enc:=3;
+ 3: enc:=3; // or 2 if you want
+ end;
+ case Frm.ID of
+ frmUSLT,frmULT: ID3v2_CheckLyric(frmUSLT,Info.lyric,buf,Frm.Size);
+ frmSYLT,frmSLT: ID3v2_CheckLyric(frmSYLT,Info.lyric,buf,Frm.Size);
+ frmTXX,frmTXXX: ID3v2_CheckLyric(frmTXXX,Info.lyric,buf,Frm.Size);
+ frmAPIC,frmPIC: ID3v2_CheckCover(Frm.ID ,Info.cover,buf,Frm.Size);
+
+ frmTPE1,frmTP1: begin
+ if fArtist<(enc+10) then
+ begin
+ fArtist:=enc+10;
+ mFreeMem(Info.artist);
+ ID3v2_ReadTagStr(Info.artist,buf,Frm.Size);
+ end
+ end;
+ frmTIT2,frmTT2: begin
+ if fTitle<(enc+10) then
+ begin
+ fTitle:=enc+10;
+ mFreeMem(Info.title);
+ ID3v2_ReadTagStr(Info.title,buf,Frm.Size);
+ end
+ end;
+ frmTALB,frmTAL: begin
+ if fAlbum<(enc+10) then
+ begin
+ fAlbum:=enc+10;
+ mFreeMem(Info.album);
+ ID3v2_ReadTagStr(Info.album,buf,Frm.Size);
+ end
+ end;
+ frmTYER,frmTDRC,frmTYE: begin
+ if Info.year<>nil then
+ mFreeMem(Info.year);
+ ID3v2_ReadTagStr(Info.year,buf,Frm.Size);
+ end;
+
+ frmTOPE,frmTPE2,frmTOA,frmTPE4: begin
+ if fArtist<enc then
+ begin
+ fArtist:=enc;
+ mFreeMem(Info.artist);
+ ID3v2_ReadTagStr(Info.artist,buf,Frm.Size);
+ end;
+ end;
+ frmTIT1,frmTIT3,frmTT1: begin
+ if fTitle<enc then
+ begin
+ fTitle:=enc;
+ mFreeMem(Info.title);
+ ID3v2_ReadTagStr(Info.title,buf,Frm.Size);
+ end;
+ end;
+ frmTOAL: begin
+ if fAlbum<enc then
+ begin
+ fAlbum:=enc;
+ mFreeMem(Info.album);
+ ID3v2_ReadTagStr(Info.album,buf,Frm.Size);
+ end;
+ end;
+ frmTORY: begin
+ if Info.year=nil then ID3v2_ReadTagStr(Info.year,buf,Frm.Size);
+ end;
+
+ frmTCON,frmTCO: begin
+ if Info.genre=nil then
+ begin
+ ID3v2_ReadTagStr(Info.genre,buf,Frm.Size);
+
+ if Info.genre<>nil then
+ if Info.genre[0]='(' then
+ begin
+ tmp:=StrScanW(Info.genre,')')-Info.genre+1;
+ if tmp=integer(StrLenW(Info.genre)) then
+ begin
+ ls:=GenreName(StrToInt(Info.genre+1));
+ mFreeMem(Info.genre);
+ Info.genre:=ls;
+ end
+ else if tmp>0 then
+ StrCopyW(Info.genre,Info.genre+tmp);
+ end;
+ end;
+ end;
+ frmCOMM,frmCOM: begin //!!
+ if Info.comment=nil then
+ begin
+ ptr:=buf;
+ inc(ptr,3+1); // language
+ if (buf^=#0) or (buf^=#3) then
+ begin
+ while ptr^<>#0 do inc(ptr);
+ inc(ptr);
+ end
+ else
+ begin
+ while pWord(ptr)^<>0 do inc(ptr,2);
+ inc(ptr,2);
+ end;
+ dec(Frm.Size,ptr-buf);
+ ID3v2_ReadTagStr1(Info.comment,ptr,Frm.Size,ord(buf^));
+ end;
+ end;
+ frmTRCK,frmTRK: begin
+ if Info.track=0 then
+ begin
+ ID3v2_ReadTagStr(ls,buf,Frm.Size);
+ Info.track:=StrToInt(ls);
+ mFreeMem(ls);
+ end;
+ end;
+ end;
+ mFreeMem(buf);
+ end;
+end;
+
+function ReadID3v2(f:THANDLE; var Info:tSongInfo):longint;
+var
+ TagHdr:TID3v2TagHdr;
+ Tag2:PAnsiChar;
+ ExtTagSize:dword;
+begin
+ BlockRead(f,TagHdr,SizeOf(TagHdr));
+ if TagHdr.ID=TAG2Sign then
+ begin
+ TagHdr.TagSize:=ID3v2_Correct(TagHdr.TagSize);
+ Unsync:=(TagHdr.Flags and $80)<>0;
+ result:=TagHdr.TagSize;
+// if TagHdr.Version>2 then
+ begin
+ GetMem(Tag2,TagHdr.TagSize);
+ BlockRead(f,Tag2^,TagHdr.TagSize);
+ ID3v2_ReadTag2(TagHdr.Version,Tag2,TagHdr.TagSize,Info);
+ FreeMem(Tag2);
+ end;
+ if (TagHdr.Flags and ExtIDHdrMask)<>0 then
+ begin
+ BlockRead(f,ExtTagSize,SizeOf(ExtTagSize));
+ inc(result,4+ExtTagSize);
+ end;
+ if (TagHdr.Flags and FooterPresent)<>0 then
+ inc(result,10);
+ end
+ else
+ result:=0;
+ Seek(f,result);
+end;
+{$ENDIF}
diff --git a/plugins/Watrack/formats/tags.pas b/plugins/Watrack/formats/tags.pas
new file mode 100644
index 0000000000..fbe0576c59
--- /dev/null
+++ b/plugins/Watrack/formats/tags.pas
@@ -0,0 +1,21 @@
+unit tags;
+{$include compilers.inc}
+interface
+
+uses wat_api,windows;
+
+{$DEFINE Interface}
+{$include tag_id3v2.inc}
+{$include tag_id3v1.inc}
+{$include tag_apev2.inc}
+
+implementation
+
+uses common,io,utils;
+
+{$UNDEF Interface}
+{$include tag_id3v2.inc}
+{$include tag_id3v1.inc}
+{$include tag_apev2.inc}
+
+end. \ No newline at end of file
diff --git a/plugins/Watrack/global.pas b/plugins/Watrack/global.pas
new file mode 100644
index 0000000000..14d915a973
--- /dev/null
+++ b/plugins/Watrack/global.pas
@@ -0,0 +1,86 @@
+{WATrack global datas}
+unit Global;
+
+interface
+
+uses windows,messages,wat_api;
+
+const
+ hwndTooltip:HWND=0;
+
+var
+ UserCP:dword;
+
+const
+ DLGED_INIT = $1000; // dialog init, not activate Apply button
+
+const
+ dsWait = -1;
+ dsEnabled = 0;
+ dsTemporary = 1;
+ dsPermanent = 2;
+
+// --- type definition ---
+type
+ pwModule = ^twModule;
+ twModule = record
+ Next :pwModule;
+ Init :function(aGetStatus:boolean=false):integer;
+ DeInit :procedure(aSetDisable:boolean);
+ AddOption :function(var tmpl:pAnsiChar;var proc:pointer;var name:pAnsiChar):integer;
+ ModuleName:pWideChar;
+ ModuleStat:integer; // filling by the way
+ Button :HWND; // checkboxes for switch on/off
+// AddOption:function(parent:HWND;var Dlg:integer;var name:pWideChar):integer;
+ end;
+
+const
+ PluginName = 'Winamp Track';
+ PluginShort:PAnsiChar = 'WATrack';
+
+const
+ ModuleLink:pwModule=nil;
+
+const
+ DisablePlugin :integer=0;
+ hHookWATStatus:THANDLE=0;
+
+// --- global functions ---
+
+procedure MakeHint (wnd:HWND;id:integer;txt:pAnsiChar);
+procedure MakeHintW(wnd:HWND;id:integer;txt:pWideChar);
+
+implementation
+
+uses common,commctrl,mirutils,m_api;//,templates;
+
+procedure MakeHint(wnd:HWND;id:integer;txt:pAnsiChar);
+var
+ ti:TTOOLINFOW;
+begin
+// FillChar(ti,SizeOf(ti),0);
+ ti.cbSize :=sizeof(TTOOLINFOW);
+ ti.uFlags :=TTF_IDISHWND or TTF_SUBCLASS;
+ ti.hwnd :=wnd;
+ ti.hinst :=hInstance;
+ ti.uId :=GetDlgItem(wnd,id);
+ ti.lpszText:=TranslateA2W(txt);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+ mFreeMem(ti.lpszText);
+end;
+
+procedure MakeHintW(wnd:HWND;id:integer;txt:pWideChar);
+var
+ ti:TTOOLINFOW;
+begin
+// FillChar(ti,SizeOf(ti),0);
+ ti.cbSize :=sizeof(TTOOLINFOW);
+ ti.uFlags :=TTF_IDISHWND or TTF_SUBCLASS;
+ ti.hwnd :=wnd;
+ ti.hinst :=hInstance;
+ ti.uId :=GetDlgItem(wnd,id);
+ ti.lpszText:=TranslateW(txt);
+ SendMessageW(hwndTooltip,TTM_ADDTOOLW,0,lparam(@ti));
+end;
+
+end.
diff --git a/plugins/Watrack/i_cover.inc b/plugins/Watrack/i_cover.inc
new file mode 100644
index 0000000000..48f515882a
--- /dev/null
+++ b/plugins/Watrack/i_cover.inc
@@ -0,0 +1,90 @@
+{any utils}
+function GetCover(var dst:pWideChar;mfile:pWideChar):boolean;
+var
+ line,line1:array [0..511] of WideChar;
+ p,p1:PWideChar;
+ i:integer;
+ fdata:WIN32_FIND_DATAW;
+ hTmp:THANDLE;
+ wr,wr1:pWideChar;
+begin
+ result:=false;
+ dst:=nil;
+ if (CoverPaths=nil) or (CoverPaths^=#0) then exit;
+ p:=CoverPaths;
+ repeat
+ p1:=p;
+ while p^>=' ' do inc(p);
+ i:=p-p1;
+ if i>0 then
+ begin
+ move(p1^,line,i*SizeOf(WideChar));
+ line[i]:=#0;
+ if ServiceExists(MS_WAT_REPLACETEXT)<>0 then
+ wr:=pWideChar(CallService(MS_WAT_REPLACETEXT,0,lparam(@line)))
+ else
+ wr:=@line;
+
+ if isPathAbsolute(wr) then
+ begin
+ hTmp:=FindFirstFileW(wr,fdata);
+ end
+ else
+ begin
+ wr1:=ExtractW(mfile,false);
+ StrCopyW(line,wr1);
+ mFreeMem(wr1);
+ StrCatW(line,wr);
+ hTmp:=FindFirstFileW(line,fdata);
+ end;
+ if dword(hTmp)<>INVALID_HANDLE_VALUE then
+ begin
+ wr1:=ExtractW(line,false);
+ StrCopyW(line1,wr1);
+ mFreeMem(wr1);
+ StrCatW(line1,pWideChar(@fdata.cFileName));
+
+ GetFullPathNameW(line1,SizeOf(line) div SizeOf(WideChar),line,wr1);
+ StrDupW(dst,line);
+ result:=true;
+ FindClose(hTmp); //!!
+ end;
+ if wr<>@line then mFreeMem(wr);
+ if result then break;
+ end;
+ while p^<' ' do
+ begin
+ if p^=#0 then break;
+ inc(p);
+ end;
+ until p^=#0;
+end;
+
+function GetLyric(var dst:pWideChar;mfile:pWideChar):boolean;
+var
+ buf:array [0..511] of WideChar;
+ f:THANDLE;
+ size:integer;
+ tmp:PAnsiChar;
+begin
+ StrCopyW(buf,mfile);
+ ChangeExtW(buf,'txt');
+ f:=Reset(buf);
+ if f=THANDLE(INVALID_HANDLE_VALUE) then
+ begin
+ dst:=nil;
+ result:=false;
+ exit;
+ end;
+ size:=FileSize(f);
+ if size>0 then
+ begin
+ mGetMem(tmp,size+1);
+ BlockRead(f,tmp^,size);
+ tmp[size]:=#0;
+ AnsiToWide(tmp,dst);
+ mFreeMem(tmp);
+ end;
+ CloseHandle(f);
+ result:=true;
+end;
diff --git a/plugins/Watrack/i_gui.inc b/plugins/Watrack/i_gui.inc
new file mode 100644
index 0000000000..dc79632b1e
--- /dev/null
+++ b/plugins/Watrack/i_gui.inc
@@ -0,0 +1,114 @@
+{some visual stuff}
+
+function OnTTBLoaded(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ ttb:m_api.TTBButton;
+begin
+ UnhookEvent(onloadhook);
+
+ FillChar(ttb,SizeOf(ttb),0);
+ ttb.cbSize :=SizeOf(ttb);
+ ttb.dwFlags:=TTBBF_VISIBLE or TTBBF_SHOWTOOLTIP;
+
+ // plugin status button
+ if DisablePlugin<>dsPermanent then
+ ttb.dwFlags:=ttb.dwFlags or TTBBF_PUSHED;
+
+ ttb.hIconDn :=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnEnable));
+ ttb.hIconUp :=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnDisable));
+ ttb.wParamUp :=1;
+// ttb.wParamDown :=0;
+ ttb.pszService:=MS_WAT_PLUGINSTATUS;
+ ttb.name :='WATrack status';
+// ttb.tooltipDn:='Disable Plugin';
+// ttb.tooltipUp:='Enable Plugin';
+ ttbState:=TopToolbar_AddButton(@ttb);
+ if ttbState=THANDLE(-1) then
+ ttbState:=0
+ else
+ CallService(MS_TTB_SETBUTTONOPTIONS,(ttbState shl 16)+TTBO_TIPNAME,
+ tlparam(Translate('Disable Plugin')));
+ result:=0;
+end;
+
+procedure CreateMenus;
+var
+ mi:TCListMenuItem;
+begin
+ FillChar(mi, sizeof(mi), 0);
+ mi.cbSize :=sizeof(mi);
+ mi.szPopupName.a:=PluginShort;
+
+ mi.hIcon :=CallService(MS_SKIN2_GETICON,0,lparam(IcoBtnEnable));
+ mi.szName.a :='Disable Plugin';
+ mi.pszService :=MS_WAT_PLUGINSTATUS;
+ mi.popupPosition:=MenuDisablePos;
+ hMenuDisable:=Menu_AddMainMenuItem(@mi);
+end;
+
+procedure ChangeMenuIcons(f1:cardinal);
+var
+ mi:tClistMenuItem;
+ p:PAnsiChar;
+begin
+ FillChar(mi,sizeof(mi),0);
+ mi.cbSize:=sizeof(mi);
+ mi.flags :=CMIM_NAME+CMIM_FLAGS+CMIM_ICON+f1;
+ if f1<>0 then
+ begin
+ mi.hIcon :=CallService(MS_SKIN2_GETICON,0,lparam(IcoBtnDisable));
+ mi.szName.a:='Enable Plugin';
+ end
+ else
+ begin
+ mi.hIcon :=CallService(MS_SKIN2_GETICON,0,lparam(IcoBtnEnable));
+ mi.szName.a:='Disable Plugin';
+ end;
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuDisable,lparam(@mi));
+
+ if ServiceExists(MS_TTB_SETBUTTONSTATE)<>0 then
+ begin
+ if f1<>0 then
+ begin
+ p:='Enable Plugin';
+ CallService(MS_TTB_SETBUTTONSTATE,ttbState,TTBST_RELEASED)
+ end
+ else
+ begin
+ p:='Disable Plugin';
+ CallService(MS_TTB_SETBUTTONSTATE,ttbState,TTBST_PUSHED);
+ end;
+ CallService(MS_TTB_SETBUTTONOPTIONS,(ttbState shl 16)+TTBO_TIPNAME,
+ lparam(Translate(p)));
+ end;
+end;
+
+function IconChanged(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ mi:TCListMenuItem;
+ ttb:m_api.TTBButton;
+begin
+ result:=0;
+ FillChar(mi,SizeOf(mi),0);
+ mi.cbSize:=sizeof(mi);
+ mi.flags :=CMIM_ICON;
+
+ mi.hIcon:=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnEnable));
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuDisable,tlparam(@mi));
+
+// toptoolbar
+ if ServiceExists(MS_TTB_GETBUTTONOPTIONS)<>0 then
+ begin
+{
+ CallService(MS_TTB_GETBUTTONOPTIONS,(ttbInfo shl 16)+TTBO_ALLDATA,tlparam(@ttb));
+ ttb.hIconUp:=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnInfo));
+ ttb.hIconDn:=ttb.hIconUp;
+ CallService(MS_TTB_SETBUTTONOPTIONS,(ttbInfo shl 16)+TTBO_ALLDATA,tlparam(@ttb));
+}
+ CallService(MS_TTB_GETBUTTONOPTIONS,(ttbState shl 16)+TTBO_ALLDATA,tlparam(@ttb));
+ ttb.hIconDn:=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnEnable));
+ ttb.hIconUp:=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnDisable));
+ CallService(MS_TTB_SETBUTTONOPTIONS,(ttbState shl 16)+TTBO_ALLDATA,tlparam(@ttb));
+ end;
+
+end;
diff --git a/plugins/Watrack/i_opt_0.inc b/plugins/Watrack/i_opt_0.inc
new file mode 100644
index 0000000000..ab17d6ec0d
--- /dev/null
+++ b/plugins/Watrack/i_opt_0.inc
@@ -0,0 +1,91 @@
+{special tab: parts settings}
+
+function DlgProcOptions0(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
+const
+ hasApply:boolean=false;
+var
+ i:integer;
+ ptr:pwModule;
+ wnd:HWND;
+ rc:TRECT;
+begin
+ result:=0;
+ case hMessage of
+ WM_DESTROY: begin
+ if hasApply then
+ begin
+ ptr:=ModuleLink;
+ while ptr<>nil do
+ begin
+ if ptr^.ModuleName<>nil then
+ begin
+ i:=SendMessageW(ptr^.Button,BM_GETCHECK,0,0);
+ if (i=BST_CHECKED) xor (ptr^.ModuleStat<>0) then
+ begin
+ if i=BST_CHECKED then
+ begin
+ ptr^.ModuleStat:=1;
+ if @ptr^.Init<>nil then
+ if ptr^.Init(false)=0 then
+ ptr^.ModuleStat:=0;
+ end
+ else
+ begin
+ ptr^.ModuleStat:=0;
+ if @ptr^.DeInit<>nil then
+ ptr^.DeInit(true);
+ end;
+ end;
+// if ptr^.ModuleStat then
+ end;
+ ptr:=ptr^.Next;
+ end;
+ end;
+ end;
+
+ WM_INITDIALOG: begin
+
+ hasApply:=false;
+
+ ptr:=ModuleLink;
+ i:=0;
+ while ptr<>nil do
+ begin
+ if ptr^.ModuleName<>nil then
+ begin
+ ptr^.Button:=CreateWindowW('BUTTON',TranslateW(ptr^.ModuleName),
+ WS_CHILD+WS_VISIBLE+BS_AUTOCHECKBOX,
+ 14,20+i*20,150,14,Dialog,0,hInstance,nil);
+ SendMessageW(ptr^.Button,WM_SETFONT,GetStockObject(DEFAULT_GUI_FONT),0);
+ if ptr^.ModuleStat<>0 then
+ SendMessageW(ptr^.Button,BM_SETCHECK,BST_CHECKED,0);
+ inc(i);
+ end;
+ ptr:=ptr^.Next;
+ end;
+ if i>0 then
+ begin
+ wnd:=GetDlgItem(Dialog,IDC_MODULEGROUP);
+ GetWindowRect(wnd,rc);
+ SetWindowPos (wnd,0,0,0,rc.Right-rc.Left,(i+1)*20,
+ SWP_NOMOVE+SWP_NOZORDER+SWP_NOACTIVATE);
+ end;
+
+ TranslateDialogDefault(Dialog);
+ end;
+
+ WM_COMMAND: begin
+ if (wParam shr 16)=BN_CLICKED then
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ WM_NOTIFY: begin
+ if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ begin
+ hasApply:=true;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/i_opt_1.inc b/plugins/Watrack/i_opt_1.inc
new file mode 100644
index 0000000000..a41d07d554
--- /dev/null
+++ b/plugins/Watrack/i_opt_1.inc
@@ -0,0 +1,256 @@
+{common options}
+const
+ ChkFmtStr:array [0..3] of pWideChar = ('None','Audio','Video','All');
+
+type
+ TCPTABLE = packed record
+ cpId :cardinal;
+ cpName:PAnsiChar;
+ end;
+const
+ cpNum = 15;
+ cpTable:array [0..cpNum-1] of TCPTABLE = (
+ (cpId: 874;cpName:'Thai'),
+ (cpId: 932;cpName:'Japanese'),
+ (cpId: 936;cpName:'Simplified Chinese'),
+ (cpId: 949;cpName:'Korean'),
+ (cpId: 950;cpName:'Traditional Chinese'),
+ (cpId:1250;cpName:'Central European'),
+ (cpId:1251;cpName:'Cyrillic'),
+ (cpId:1252;cpName:'Latin I'),
+ (cpId:1253;cpName:'Greek'),
+ (cpId:1254;cpName:'Turkish'),
+ (cpId:1255;cpName:'Hebrew'),
+ (cpId:1256;cpName:'Arabic'),
+ (cpId:1257;cpName:'Baltic'),
+ (cpId:1258;cpName:'Vietnamese'),
+ (cpId:1361;cpName:'Korean (Johab)'));
+
+var
+ hCpCombo:hwnd;
+
+function FillCpCombo(astr:PAnsiChar):boolean; stdcall;
+var
+ i:integer;
+ cp:cardinal;
+ iIndex:integer;
+ buf:array [0..63] of WideChar;
+begin
+ result:=true; // MUST be at start
+ cp:=StrToInt(astr);
+ i:=0;
+ while i<cpNum do
+ begin
+ if cpTable[i].cpId=cp then
+ begin
+ iIndex:=SendMessageW(hCpCombo,CB_ADDSTRING,0,
+ lparam(TranslateW(FastAnsiToWideBuf(cpTable[i].cpName,buf))));
+ SendMessage(hCpCombo,CB_SETITEMDATA,iIndex,cpTable[i].cpId);
+ break;
+ end;
+ inc(i);
+ end;
+end;
+
+function DlgProcOptions1(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ btnChkPlayer:bool=false;
+ btnChkFormat:integer=0;
+var
+ tmp:longbool;
+ i,j:cardinal;
+ wnd:HWND;
+ pldescr:array [0..27] of AnsiChar;
+ pldescw:array [0..27] of WideChar;
+ p:pWideChar;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ SetWindowTextW(GetDlgItem(Dialog,IDC_CHK_PLAYER),'None');
+ SetWindowTextW(GetDlgItem(Dialog,IDC_CHK_FORMAT),ChkFmtStr[0]);
+ TranslateDialogDefault(Dialog);
+ DefFillPlayerList(GetDlgItem(Dialog,IDC_PLAYERLIST));
+ DefFillFormatList(GetDlgItem(Dialog,IDC_FORMATLIST));
+
+ i:=mTimer;
+ if (i>=1000) and (i mod 1000=0) then
+ i:=i div 1000;
+
+ MakeHint(Dialog,IDC_TIMER,
+ 'Refresh time (sec) is time to refresh music info, statistic and'+
+ ' status messages. If zero, automatic refresh is disabled. If '+
+ 'value greater than 499, time signify as milliseconds.');
+ SetDlgItemInt(Dialog,IDC_TIMER,i,false);
+
+ MakeHint(Dialog,IDC_CHECKTIME,
+ 'Check file date and time to tag updates while playing.');
+ CheckDlgButton(Dialog,IDC_CHECKTIME,CheckTime);
+
+ MakeHint(Dialog,IDC_IMPLANTANT,
+ 'Use player process injection to obtain info easier. Can provoke antivirus '+
+ 'or firewall alarm.');
+ CheckDlgButton(Dialog,IDC_IMPLANTANT,UseImplant);
+
+ MakeHint(Dialog,IDC_MTHCHECK,
+ 'Use this option if WATrack freeze while player running. Slower processing.');
+ CheckDlgButton(Dialog,IDC_MTHCHECK,MTHCheck);
+
+ MakeHint(Dialog,IDC_TIMEOUT,
+ 'Timeout (msec) for separate thread handles checking.');
+ SetDlgItemInt(Dialog,IDC_TIMEOUT,TimeoutForThread,false);
+
+ MakeHint(Dialog,IDC_KEEPOLD,
+ 'Keep opened file as active, not newly founded.');
+ CheckDlgButton(Dialog,IDC_KEEPOLD,KeepOld);
+
+ MakeHint(Dialog,IDC_CHECKALL,
+ 'Check all marked players for active (started and playing) or stop at first founded');
+ CheckDlgButton(Dialog,IDC_CHECKALL,CheckAll);
+
+// MakeHint(Dialog,IDC_COVERFN,
+// 'Cover filename searching templates');
+ SetDlgItemTextW(Dialog,IDC_COVERFN,CoverPaths);
+
+ MakeHint(Dialog,IDC_APPCOMMAND,
+ 'Emulate multimedia keys presses to control palyer');
+ CheckDlgButton(Dialog,IDC_APPCOMMAND,mmkeyemu);
+
+ hCpCombo:=GetDlgItem(Dialog,IDC_CODEPAGE);
+ EnumSystemCodePages(@FillCpCombo,CP_INSTALLED);
+ SendDlgItemMessageW(Dialog,IDC_CODEPAGE,CB_INSERTSTRING,0,
+ tlparam(TranslateW('System default codepage')));
+
+ CB_SelectData(Dialog,IDC_CODEPAGE,UserCP);
+
+ if UserCP=0 then
+ i:=0
+ else
+ begin
+ i:=SendDlgItemMessage(Dialog,IDC_CODEPAGE,CB_GETCOUNT,0,0)-1;
+ while i>0 do
+ begin
+ if dword(SendDlgItemMessage(Dialog,IDC_CODEPAGE,CB_GETITEMDATA,dword(i),0))=UserCP then
+ break;
+ dec(i);
+ end
+ end;
+ SendDlgItemMessage(Dialog,IDC_CODEPAGE,CB_SETCURSEL,i,0);
+
+ result:=0;
+ end;
+
+ WM_HELP: begin
+ with pHelpInfo(lParam)^ do
+ begin
+ if (iContextType=HELPINFO_WINDOW) and (iCtrlId=IDC_PLAYERLIST) then
+ begin
+ ListView_GetItemTextA(hItemHandle,
+ SendMessage(hItemHandle,LVM_GETNEXTITEM,-1,LVNI_FOCUSED),0,
+ @pldescr,HIGH(pldescr));
+ p:=GetPlayerNote(pldescr);
+ if p=nil then
+ p:='No any special notes for this player';
+ MessageBoxW(0,TranslateW(p),FastAnsiToWideBuf(pldescr,pldescw),0);
+ end;
+ end;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ EN_CHANGE,
+ BN_CLICKED,
+ CBN_SELCHANGE: begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ result:=1;
+ end;
+ end;
+ if (wParam shr 16)=BN_CLICKED then
+ begin
+ case loword(wParam) of
+ IDC_CHK_PLAYER: begin
+ btnChkPlayer:=not btnChkPlayer;
+ if btnChkPlayer then
+ begin
+ SetWindowTextW(GetDlgItem(Dialog,IDC_CHK_PLAYER),TranslateW('All'));
+ tmp:=false;
+ end
+ else
+ begin
+ SetWindowTextW(GetDlgItem(Dialog,IDC_CHK_PLAYER),TranslateW('None'));
+ tmp:=true;
+ end;
+ wnd:=GetDlgItem(Dialog,IDC_PLAYERLIST);
+ j:=ListView_GetItemCount(wnd)-1;
+ for i:=0 to j do
+ ListView_SetCheckState(wnd,i,tmp);
+ end;
+
+ IDC_CHK_FORMAT: begin
+ wnd:=GetDlgItem(Dialog,IDC_FORMATLIST);
+ j:=ListView_GetItemCount(wnd)-1;
+
+ tmp:=btnChkFormat=3;
+ for i:=0 to j do
+ begin
+ if (btnChkFormat=1) or (btnChkFormat=2) then
+ begin
+ if (LV_GetLParam(wnd,i) and WAT_OPT_VIDEO)<>0 then
+ tmp:=btnChkFormat=2
+ else
+ tmp:=btnChkFormat=1;
+ end;
+ ListView_SetCheckState(wnd,i,tmp);
+ end;
+ inc(btnChkFormat);
+ if btnChkFormat=4 then btnChkFormat:=0;
+ SetWindowTextW(GetDlgItem(Dialog,IDC_CHK_FORMAT),TranslateW(ChkFmtStr[btnChkFormat]));
+ end;
+ end;
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ case integer(PNMHdr(lParam)^.code) of
+ LVN_ITEMCHANGED: begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ PSN_APPLY: begin
+ UserCP:=CB_GetData(GetDlgItem(Dialog,IDC_CODEPAGE));
+ i:=GetDlgItemInt(Dialog,IDC_TIMER,tmp,false);
+ if i<500 then
+ i:=i*1000;
+ if i<>mTimer then
+ begin
+ mTimer:=i;
+ StopTimer;
+ StartTimer;
+ end;
+
+ TimeoutForThread:=GetDlgItemInt(Dialog,IDC_TIMEOUT,tmp,false);
+ if TimeoutForThread>=100 then
+ TimeoutForThread:=SysWin.ThreadTimeout;
+
+ CheckTime :=IsDlgButtonChecked(Dialog,IDC_CHECKTIME);
+ UseImplant:=IsDlgButtonChecked(Dialog,IDC_IMPLANTANT);
+ MTHCheck :=IsDlgButtonChecked(Dialog,IDC_MTHCHECK);
+ KeepOld :=IsDlgButtonChecked(Dialog,IDC_KEEPOLD);
+ mmkeyemu :=IsDlgButtonChecked(Dialog,IDC_APPCOMMAND);
+ CheckAll :=IsDlgButtonChecked(Dialog,IDC_CHECKALL);
+
+ mFreeMem(CoverPaths);
+ CoverPaths:=GetDlgText(Dialog,IDC_COVERFN);
+
+ DefCheckPlayerList(GetDlgItem(Dialog,IDC_PLAYERLIST));
+ DefCheckFormatList(GetDlgItem(Dialog,IDC_FORMATLIST));
+ saveopt;
+
+ result:=1;
+ end;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/i_opt_dlg.inc b/plugins/Watrack/i_opt_dlg.inc
new file mode 100644
index 0000000000..e97a3df5f5
--- /dev/null
+++ b/plugins/Watrack/i_opt_dlg.inc
@@ -0,0 +1,57 @@
+{$include i_opt_0.inc}
+{$include i_opt_1.inc}
+
+function OnOptInitialise(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ odp:TOPTIONSDIALOGPAGE;
+ ptr:pwModule;
+ tmpl:pAnsiChar;
+ name:pansiChar;
+ proc:pointer;
+ i:integer;
+begin
+ if hwndTooltip<>0 then
+ DestroyWindow(hwndTooltip);
+ hwndTooltip:=CreateWindowW(TOOLTIPS_CLASS,nil,TTS_ALWAYSTIP,
+ integer(CW_USEDEFAULT),integer(CW_USEDEFAULT),
+ integer(CW_USEDEFAULT),integer(CW_USEDEFAULT),
+ 0,0,hInstance,nil);
+
+ SendMessage(hwndTooltip,TTM_SETMAXTIPWIDTH,0,300);
+
+ FillChar(odp,SizeOf(odp),0);
+ odp.cbSize :=SizeOf(odp);
+ odp.Position :=900003000;
+ odp.hInstance :=hInstance;
+ odp.szTitle.a :=PluginName;
+ odp.szGroup.a :='Plugins';
+
+ odp.flags :=ODPF_BOLDGROUPS or ODPF_EXPERTONLY;
+ odp.pszTemplate:='PARTS';
+ odp.pfnDlgProc :=@DlgProcOptions0;
+ odp.szTab.a :='Modules';
+ CallService(MS_OPT_ADDPAGE,wParam,tlparam(@odp));
+
+ odp.flags :=ODPF_BOLDGROUPS;
+ odp.pszTemplate:='BASIC';
+ odp.pfnDlgProc :=@DlgProcOptions1;
+ odp.szTab.a :='Basic';
+ CallService(MS_OPT_ADDPAGE,wParam,tlparam(@odp));
+
+ ptr:=ModuleLink;
+ while ptr<>nil do
+ begin
+ if (ptr^.ModuleStat<>0) and (@ptr^.AddOption<>nil) then
+ begin
+ i:=ptr^.AddOption(tmpl,proc,name);
+ odp.pszTemplate:=tmpl;
+ odp.pfnDlgProc :=proc;
+ odp.szTab.a :=name;
+ CallService(MS_OPT_ADDPAGE,wParam,tlparam(@odp));
+ if i>0 then continue;
+ end;
+ ptr:=ptr^.Next;
+ end;
+
+ result:=0;
+end;
diff --git a/plugins/Watrack/i_options.inc b/plugins/Watrack/i_options.inc
new file mode 100644
index 0000000000..060751966c
--- /dev/null
+++ b/plugins/Watrack/i_options.inc
@@ -0,0 +1,171 @@
+{Database options}
+const
+ DefaultXStatus = $080B; // TV + Music
+const
+ defhotkey = (HOTKEYF_CONTROL+HOTKEYF_ALT )*256+VK_F5;
+ definshotkey = (HOTKEYF_CONTROL+HOTKEYF_SHIFT)*256+VK_F7;
+
+const
+ defcoverpaths = 'cover.jpg'#13#10'..\cover.jpg'#13#10'*.jpg'#13#10'..\*.jpg';
+
+const
+ WATFormats:PAnsiChar = 'formats/';
+const
+ WATPlayers :PAnsiChar = 'players/';
+
+const
+ opt_disable :PAnsiChar = 'disableplugin';
+
+ opt_InsHotKey :PAnsiChar = 'inshotkey';
+ opt_HotKey :PAnsiChar = 'hotkey';
+ opt_Timer :PAnsiChar = 'timer';
+ opt_UserCP :PAnsiChar = 'usercp';
+ opt_CheckTime :PAnsiChar = 'checktime';
+ opt_coverpaths:PAnsiChar = 'coverpaths';
+ opt_Implantant:PAnsiChar = 'useimplantant';
+ opt_MTHCheck :PAnsiChar = 'mthcheck';
+ opt_KeepOld :PAnsiChar = 'keepold';
+ opt_mmkeyemu :PAnsiChar = 'mmkeyemu';
+ opt_CheckAll :PAnsiChar = 'checkall';
+
+ opt_ThTimeout :PAnsiChar = 'thtimeout';
+
+procedure _loadopt;
+begin
+ DisablePlugin:=DBReadByte(0,PluginShort,opt_disable,0);
+ if DisablePlugin<>dsPermanent then
+ DisablePlugin:=dsEnabled;
+
+ inshotkey :=DBReadWord(0,PluginShort,opt_InsHotKey ,definshotkey);
+ globhotkey :=DBReadWord(0,PluginShort,opt_HotKey ,defhotkey);
+ CheckTime :=DBReadByte(0,PluginShort,opt_CheckTime ,BST_CHECKED);
+ UseImplant :=DBReadByte(0,PluginShort,opt_Implantant,BST_UNCHECKED);
+ MTHCheck :=DBReadByte(0,PluginShort,opt_MTHCheck ,BST_CHECKED);
+ KeepOld :=DBReadByte(0,PluginShort,opt_KeepOld ,BST_UNCHECKED);
+ CheckAll :=DBReadByte(0,PluginShort,opt_CheckAll ,BST_UNCHECKED);
+ mTimer :=DBReadWord(0,PluginShort,opt_Timer ,3000);
+ if mTimer<500 then
+ mTimer:=mTimer*1000;
+ UserCP :=DBReadWord(0,PluginShort,opt_UserCP ,CP_ACP);
+ CoverPaths :=DBReadUnicode(0,PluginShort,opt_coverpaths,defcoverpaths);
+
+ mmkeyemu :=DBReadByte (0,PluginShort,opt_mmkeyemu ,BST_UNCHECKED);
+
+ TimeoutForThread:=DBReadByte(0,PluginShort,opt_ThTimeout,SysWin.ThreadTimeout);
+end;
+
+procedure _saveopt;
+begin
+ DBWriteWord(0,PluginShort,opt_InsHotKey ,inshotkey);
+ DBWriteWord(0,PluginShort,opt_HotKey ,globhotkey);
+ DBWriteByte(0,PluginShort,opt_ThTimeout ,TimeoutForThread);
+ DBWriteByte(0,PluginShort,opt_CheckTime ,CheckTime);
+ DBWriteByte(0,PluginShort,opt_Implantant,UseImplant);
+ DBWriteByte(0,PluginShort,opt_MTHCheck ,MTHCheck);
+ DBWriteByte(0,PluginShort,opt_KeepOld ,KeepOld);
+ DBWriteByte(0,PluginShort,opt_CheckAll ,CheckAll);
+ DBWriteWord(0,PluginShort,opt_Timer ,mTimer);
+ DBWriteWord(0,PluginShort,opt_UserCP ,UserCP);
+
+ DBWriteUnicode(0,PluginShort,opt_coverpaths,CoverPaths);
+
+ DBWriteByte (0,PluginShort,opt_mmkeyemu ,mmkeyemu);
+end;
+
+function enumwp(desc:PAnsiChar;lParam:LPARAM):bool; stdcall;
+var
+ i:integer;
+ buf:array [0..63] of AnsiChar;
+begin
+ i:=CallService(MS_WAT_PLAYER,WAT_ACT_GETSTATUS,tlparam(desc));
+ if i=WAT_RES_ENABLED then
+ i:=1
+ else
+ i:=0;
+ StrCopy(StrCopyE(buf,WATPlayers),desc);
+ DBWriteByte(0,PluginShort,buf,i);
+ result:=true;
+end;
+
+procedure WritePlayers;
+begin
+ EnumPlayers(@enumwp,0);
+end;
+
+function enumrp(desc:PAnsiChar;lParam:LPARAM):bool; stdcall;
+var
+ i:integer;
+ buf:array [0..63] of AnsiChar;
+begin
+ StrCopy(StrCopyE(buf,WATPlayers),desc);
+ i:=DBReadByte(0,PluginShort,buf,1);
+ if i=1 then
+ i:=WAT_ACT_ENABLE
+ else
+ i:=WAT_ACT_DISABLE;
+ CallService(MS_WAT_PLAYER,i,tlparam(desc));
+ result:=true;
+end;
+
+procedure ReadPlayers;
+begin
+ EnumPlayers(@enumrp,0);
+{!! p:=DBReadString(0,PluginShort,opt_DefPlayer,nil);
+ CallService(MS_WAT_PLAYER,WAT_ACT_SETACTIVE,dword(p));
+ mFreeMem(p);
+}
+end;
+
+function enumwf(ext:PAnsiChar;lParam:LPARAM):bool; stdcall;
+var
+ i:integer;
+ buf:array [0..63] of AnsiChar;
+begin
+ i:=CallService(MS_WAT_FORMAT,WAT_ACT_GETSTATUS,tlparam(ext));
+ if i=WAT_RES_ENABLED then
+ i:=1
+ else
+ i:=0;
+ StrCopy(StrCopyE(buf,WATFormats),ext);
+ DBWriteByte(0,PluginShort,buf,i);
+ result:=true;
+end;
+
+procedure WriteFormats;
+begin
+ EnumFormats(@enumwf,0);
+end;
+
+function enumrf(ext:PAnsiChar;lParam:LPARAM):bool; stdcall;
+var
+ i:integer;
+ buf:array [0..63] of AnsiChar;
+begin
+ StrCopy(StrCopyE(buf,WATFormats),ext);
+ i:=DBReadByte(0,PluginShort,buf,1);
+ if i=1 then
+ i:=WAT_ACT_ENABLE
+ else
+ i:=WAT_ACT_DISABLE;
+ CallService(MS_WAT_FORMAT,i,tlparam(ext));
+ result:=true;
+end;
+
+procedure ReadFormats;
+begin
+ EnumFormats(@enumrf,0);
+end;
+
+procedure saveopt;
+begin
+ _saveopt;
+ WriteFormats;
+ WritePlayers;
+end;
+
+procedure loadopt;
+begin
+ _loadopt;
+ ReadPlayers;
+ ReadFormats;
+end;
diff --git a/plugins/Watrack/i_timer.inc b/plugins/Watrack/i_timer.inc
new file mode 100644
index 0000000000..f37092291b
--- /dev/null
+++ b/plugins/Watrack/i_timer.inc
@@ -0,0 +1,26 @@
+{Timer related procedures}
+
+procedure TimerProc(wnd:HWND;uMsg:uint;idEvent:uint_ptr;dwTime:dword); stdcall;
+begin
+ case DisablePlugin of
+ dsEnabled : CallService(MS_WAT_GETMUSICINFO,WAT_INF_CHANGES,0);
+ dsTemporary: DisablePlugin:=dsWait;
+ end;
+end;
+
+procedure StartTimer;
+begin
+ if mTimer>0 then
+ hTimer:=SetTimer(0,0,mTimer,@TimerProc)
+ else
+ hTimer:=0;
+end;
+
+procedure StopTimer;
+begin
+ if hTimer<>0 then
+ begin
+ KillTimer(0,hTimer);
+ hTimer:=0;
+ end;
+end;
diff --git a/plugins/Watrack/i_vars.inc b/plugins/Watrack/i_vars.inc
new file mode 100644
index 0000000000..955170fdfa
--- /dev/null
+++ b/plugins/Watrack/i_vars.inc
@@ -0,0 +1,37 @@
+{variables}
+var
+ SongInfoA:tSongInfoA;
+ SongInfo :tSongInfo;
+ WorkSI :tSongInfo;
+var
+ hEvent:THANDLE;
+ hGFI,
+ hWI,
+ hGMI,
+ hPS,
+ hPB,
+ hWATI,
+ hWC,
+ hFMT,
+ hPLR,
+ hRGS,
+ wsic,
+ hHookWATLoaded:THANDLE;
+ opthook:cardinal;
+ onloadhook:cardinal;
+ hHookShutdown:cardinal;
+ inshotkey:cardinal;
+ globhotkey:cardinal;
+ hTimer:cardinal;
+ ttbState,
+ hMenuDisable:THANDLE;
+var
+ CoverPaths:PWideChar;
+ MTHCheck,
+ KeepOld,
+ UseImplant,
+ CheckAll,
+ CheckTime:dword;
+ mmkeyemu: dword;
+ mTimer:dword;
+ TimeoutForThread:cardinal;
diff --git a/plugins/Watrack/icons/GO/GoAsm.Exe b/plugins/Watrack/icons/GO/GoAsm.Exe
new file mode 100644
index 0000000000..cb0f7e8c92
--- /dev/null
+++ b/plugins/Watrack/icons/GO/GoAsm.Exe
Binary files differ
diff --git a/plugins/Watrack/icons/GO/GoLink.exe b/plugins/Watrack/icons/GO/GoLink.exe
new file mode 100644
index 0000000000..01e2964d6d
--- /dev/null
+++ b/plugins/Watrack/icons/GO/GoLink.exe
Binary files differ
diff --git a/plugins/Watrack/icons/GO/GoRC.exe b/plugins/Watrack/icons/GO/GoRC.exe
new file mode 100644
index 0000000000..10ea26c30f
--- /dev/null
+++ b/plugins/Watrack/icons/GO/GoRC.exe
Binary files differ
diff --git a/plugins/Watrack/icons/GO/icons.bat b/plugins/Watrack/icons/GO/icons.bat
new file mode 100644
index 0000000000..e45dfd4ab9
--- /dev/null
+++ b/plugins/Watrack/icons/GO/icons.bat
@@ -0,0 +1,8 @@
+:@echo off
+GoRC /r /d incpath="%2" icons.rc
+:GoRC /r icons.rc
+GoAsm watrack_buttons.asm
+GoLink /dll watrack_buttons.obj icons.res
+del *.obj
+del *.res
+move watrack_buttons.dll ..\..\..\bin \ No newline at end of file
diff --git a/plugins/Watrack/icons/GO/icons.rc b/plugins/Watrack/icons/GO/icons.rc
new file mode 100644
index 0000000000..b50bba6a22
--- /dev/null
+++ b/plugins/Watrack/icons/GO/icons.rc
@@ -0,0 +1,58 @@
+#include "waticons.h"
+LANGUAGE 0,0
+
+IDI_PREV_NORMAL ICON "previous.ico"
+IDI_PLAY_NORMAL ICON "play.ico"
+IDI_PAUSE_NORMAL ICON "pause.ico"
+IDI_STOP_NORMAL ICON "stop.ico"
+IDI_NEXT_NORMAL ICON "next.ico"
+
+IDI_PREV_HOVERED ICON "previous_hovered.ico"
+IDI_PLAY_HOVERED ICON "play_hovered.ico"
+IDI_PAUSE_HOVERED ICON "pause_hovered.ico"
+IDI_STOP_HOVERED ICON "stop_hovered.ico"
+IDI_NEXT_HOVERED ICON "next_hovered.ico"
+
+IDI_PREV_PRESSED ICON "previous_pressed.ico"
+IDI_PLAY_PRESSED ICON "play_pressed.ico"
+IDI_PAUSE_PRESSED ICON "pause_pressed.ico"
+IDI_STOP_PRESSED ICON "stop_pressed.ico"
+IDI_NEXT_PRESSED ICON "next_pressed.ico"
+
+IDI_VOLDN_NORMAL ICON "volume_down.ico"
+IDI_VOLUP_NORMAL ICON "volume_up.ico"
+IDI_VOLDN_HOVERED ICON "volume_down_hovered.ico"
+IDI_VOLUP_HOVERED ICON "volume_up_hovered.ico"
+IDI_VOLDN_PRESSED ICON "volume_down_pressed.ico"
+IDI_VOLUP_PRESSED ICON "volume_up_pressed.ico"
+
+IDI_SLIDER_NORMAL ICON "slider.ico"
+IDI_SLIDER_HOVERED ICON "slider_hovered.ico"
+IDI_SLIDER_PRESSED ICON "slider_pressed.ico"
+
+IDI_PLUGIN_ENABLE ICON "enable.ico"
+IDI_PLUGIN_DISABLE ICON "disable.ico"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,0,0,2
+ PRODUCTVERSION 0,0,0,2
+ FILEFLAGSMASK 0x3F
+ FILEOS 4
+ FILETYPE 2
+ FILESUBTYPE 0
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "FileDescription", "Solid indexed and truecolor"
+ VALUE "FileVersion", "0.0.0.2"
+ VALUE "OriginalFilename", "watrack_buttons.dll"
+ VALUE "ProductName", "WATrack buttons icons"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation",0,1200
+ END
+END
diff --git a/plugins/Watrack/icons/GO/waticons.h b/plugins/Watrack/icons/GO/waticons.h
new file mode 100644
index 0000000000..bad8cadea2
--- /dev/null
+++ b/plugins/Watrack/icons/GO/waticons.h
@@ -0,0 +1,35 @@
+#define IDI_PREV_NORMAL 1
+#define IDI_PREV_HOVERED 2
+#define IDI_PREV_PRESSED 3
+
+#define IDI_PLAY_NORMAL 4
+#define IDI_PLAY_HOVERED 5
+#define IDI_PLAY_PRESSED 6
+
+#define IDI_PAUSE_NORMAL 7
+#define IDI_PAUSE_HOVERED 8
+#define IDI_PAUSE_PRESSED 9
+
+#define IDI_STOP_NORMAL 10
+#define IDI_STOP_HOVERED 11
+#define IDI_STOP_PRESSED 12
+
+#define IDI_NEXT_NORMAL 13
+#define IDI_NEXT_HOVERED 14
+#define IDI_NEXT_PRESSED 15
+
+#define IDI_VOLDN_NORMAL 16
+#define IDI_VOLDN_HOVERED 17
+#define IDI_VOLDN_PRESSED 18
+
+#define IDI_VOLUP_NORMAL 19
+#define IDI_VOLUP_HOVERED 20
+#define IDI_VOLUP_PRESSED 21
+
+#define IDI_SLIDER_NORMAL 22
+#define IDI_SLIDER_HOVERED 23
+#define IDI_SLIDER_PRESSED 24
+
+
+#define IDI_PLUGIN_ENABLE 100
+#define IDI_PLUGIN_DISABLE 101
diff --git a/plugins/Watrack/icons/GO/watrack_buttons.asm b/plugins/Watrack/icons/GO/watrack_buttons.asm
new file mode 100644
index 0000000000..27ed04d7b5
--- /dev/null
+++ b/plugins/Watrack/icons/GO/watrack_buttons.asm
@@ -0,0 +1,5 @@
+.code
+start:
+ mov al, 1
+ ret
+
diff --git a/plugins/Watrack/icons/MASM/icons.bat b/plugins/Watrack/icons/MASM/icons.bat
new file mode 100644
index 0000000000..9cb2911d33
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/icons.bat
@@ -0,0 +1,8 @@
+@echo off
+if /i '%1' == 'buttons' (set iconres=icons) else set iconres=iconspl
+porc /i%2 %iconres%.rc /Foicons.res
+poasm watrack.asm
+polink /DLL /RELEASE /NODEFAULTLIB /NOENTRY /NOLOGO /OUT:watrack_%1.dll watrack.obj icons.res
+del *.obj
+del *.res
+move watrack_%1.dll ..\..\..\bin \ No newline at end of file
diff --git a/plugins/Watrack/icons/MASM/icons.rc b/plugins/Watrack/icons/MASM/icons.rc
new file mode 100644
index 0000000000..b50bba6a22
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/icons.rc
@@ -0,0 +1,58 @@
+#include "waticons.h"
+LANGUAGE 0,0
+
+IDI_PREV_NORMAL ICON "previous.ico"
+IDI_PLAY_NORMAL ICON "play.ico"
+IDI_PAUSE_NORMAL ICON "pause.ico"
+IDI_STOP_NORMAL ICON "stop.ico"
+IDI_NEXT_NORMAL ICON "next.ico"
+
+IDI_PREV_HOVERED ICON "previous_hovered.ico"
+IDI_PLAY_HOVERED ICON "play_hovered.ico"
+IDI_PAUSE_HOVERED ICON "pause_hovered.ico"
+IDI_STOP_HOVERED ICON "stop_hovered.ico"
+IDI_NEXT_HOVERED ICON "next_hovered.ico"
+
+IDI_PREV_PRESSED ICON "previous_pressed.ico"
+IDI_PLAY_PRESSED ICON "play_pressed.ico"
+IDI_PAUSE_PRESSED ICON "pause_pressed.ico"
+IDI_STOP_PRESSED ICON "stop_pressed.ico"
+IDI_NEXT_PRESSED ICON "next_pressed.ico"
+
+IDI_VOLDN_NORMAL ICON "volume_down.ico"
+IDI_VOLUP_NORMAL ICON "volume_up.ico"
+IDI_VOLDN_HOVERED ICON "volume_down_hovered.ico"
+IDI_VOLUP_HOVERED ICON "volume_up_hovered.ico"
+IDI_VOLDN_PRESSED ICON "volume_down_pressed.ico"
+IDI_VOLUP_PRESSED ICON "volume_up_pressed.ico"
+
+IDI_SLIDER_NORMAL ICON "slider.ico"
+IDI_SLIDER_HOVERED ICON "slider_hovered.ico"
+IDI_SLIDER_PRESSED ICON "slider_pressed.ico"
+
+IDI_PLUGIN_ENABLE ICON "enable.ico"
+IDI_PLUGIN_DISABLE ICON "disable.ico"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,0,0,2
+ PRODUCTVERSION 0,0,0,2
+ FILEFLAGSMASK 0x3F
+ FILEOS 4
+ FILETYPE 2
+ FILESUBTYPE 0
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "FileDescription", "Solid indexed and truecolor"
+ VALUE "FileVersion", "0.0.0.2"
+ VALUE "OriginalFilename", "watrack_buttons.dll"
+ VALUE "ProductName", "WATrack buttons icons"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation",0,1200
+ END
+END
diff --git a/plugins/Watrack/icons/MASM/iconspl.rc b/plugins/Watrack/icons/MASM/iconspl.rc
new file mode 100644
index 0000000000..3b98761d8d
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/iconspl.rc
@@ -0,0 +1,83 @@
+LANGUAGE 0,0
+// Winamp clone
+WANY ICON "wany.ico"
+// 1BY1
+1BY1 ICON "1by1.ico"
+// ALShow
+ALSHOW ICON "alshow.ico"
+// ALSong
+ALSONG ICON "alsong.ico"
+// Apollo
+APOLLO ICON "apollo.ico"
+// AudioPlayer
+AUDIO ICON "audio.ico"
+// BSPlayer
+BS ICON "bs.ico"
+// Core Media Player
+CMP ICON "cmp.ico"
+// Creative Music Source
+CMS ICON "cms.ico"
+// Cowon JetAudio
+COWON ICON "cowon.ico"
+// FLVPlayer
+FLV ICON "flv.ico"
+// Foobar
+FOOBAR ICON "foobar.ico"
+//GOMPlayer
+GOM ICON "gom.ico"
+// Helium
+HELIUM ICON "helium.ico"
+// iTunes
+ITUNES ICON "itunes.ico"
+// JRiver Media Center
+JRMC ICON "jrmc.ico"
+// LightAlloy
+LA ICON "la.ico"
+// Last.fm Player
+LFM ICON "lfm.ico"
+// MusicCube One
+MCONE ICON "mcone.ico"
+// MusikCube
+MCUBE ICON "mcube.ico"
+// Media Commander Express
+MCX ICON "mcx.ico"
+// Music Match Jukebox
+MMATCH ICON "mmatch.ico"
+// Media Monkey
+MMONKEY ICON "mmonkey.ico"
+// Media Player Classic
+MPC ICON "mpc.ico"
+// MPlayer
+MPLAYER ICON "mplayer.ico"
+// MRadio
+MRADIO ICON "mradio.ico"
+// PlayNow
+PLAY ICON "play.ico"
+// Pluton
+PLUTON ICON "pluton.ico"
+// CyberLink PowerDVD
+POWERDVD ICON "powerdvd.ico"
+// Quintessential Player
+QCD ICON "qcd.ico"
+// Quicktime Player
+QT ICON "qt.ico"
+// Real Player Gold
+REAL ICON "real.ico"
+// SAPS
+SAPS ICON "saps.ico"
+// SongBird
+SONGBIRD ICON "songbird.ico"
+// VideoLAN media player
+VLC ICON "vlc.ico"
+// ViPlay
+VP3 ICON "vp3.ico"
+// WiFiRadio
+WIFI ICON "wifi.ico"
+// Winamp
+WINAMP ICON "winamp.ico"
+// Windows Media Player
+WMP ICON "wmp.ico"
+// XM Player
+XM ICON "xm.ico"
+// Zoom Player
+ZOOM ICON "zoom.ico"
diff --git a/plugins/Watrack/icons/MASM/poasm.exe b/plugins/Watrack/icons/MASM/poasm.exe
new file mode 100644
index 0000000000..a5062d4823
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/poasm.exe
Binary files differ
diff --git a/plugins/Watrack/icons/MASM/polink.exe b/plugins/Watrack/icons/MASM/polink.exe
new file mode 100644
index 0000000000..2338218457
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/polink.exe
Binary files differ
diff --git a/plugins/Watrack/icons/MASM/porc.dll b/plugins/Watrack/icons/MASM/porc.dll
new file mode 100644
index 0000000000..18390000ee
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/porc.dll
Binary files differ
diff --git a/plugins/Watrack/icons/MASM/porc.exe b/plugins/Watrack/icons/MASM/porc.exe
new file mode 100644
index 0000000000..ae28631b40
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/porc.exe
Binary files differ
diff --git a/plugins/Watrack/icons/MASM/waticons.h b/plugins/Watrack/icons/MASM/waticons.h
new file mode 100644
index 0000000000..bad8cadea2
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/waticons.h
@@ -0,0 +1,35 @@
+#define IDI_PREV_NORMAL 1
+#define IDI_PREV_HOVERED 2
+#define IDI_PREV_PRESSED 3
+
+#define IDI_PLAY_NORMAL 4
+#define IDI_PLAY_HOVERED 5
+#define IDI_PLAY_PRESSED 6
+
+#define IDI_PAUSE_NORMAL 7
+#define IDI_PAUSE_HOVERED 8
+#define IDI_PAUSE_PRESSED 9
+
+#define IDI_STOP_NORMAL 10
+#define IDI_STOP_HOVERED 11
+#define IDI_STOP_PRESSED 12
+
+#define IDI_NEXT_NORMAL 13
+#define IDI_NEXT_HOVERED 14
+#define IDI_NEXT_PRESSED 15
+
+#define IDI_VOLDN_NORMAL 16
+#define IDI_VOLDN_HOVERED 17
+#define IDI_VOLDN_PRESSED 18
+
+#define IDI_VOLUP_NORMAL 19
+#define IDI_VOLUP_HOVERED 20
+#define IDI_VOLUP_PRESSED 21
+
+#define IDI_SLIDER_NORMAL 22
+#define IDI_SLIDER_HOVERED 23
+#define IDI_SLIDER_PRESSED 24
+
+
+#define IDI_PLUGIN_ENABLE 100
+#define IDI_PLUGIN_DISABLE 101
diff --git a/plugins/Watrack/icons/MASM/watrack.asm b/plugins/Watrack/icons/MASM/watrack.asm
new file mode 100644
index 0000000000..27ed04d7b5
--- /dev/null
+++ b/plugins/Watrack/icons/MASM/watrack.asm
@@ -0,0 +1,5 @@
+.code
+start:
+ mov al, 1
+ ret
+
diff --git a/plugins/Watrack/icons/TASM/RLINK32.DLL b/plugins/Watrack/icons/TASM/RLINK32.DLL
new file mode 100644
index 0000000000..17c21b29e1
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/RLINK32.DLL
Binary files differ
diff --git a/plugins/Watrack/icons/TASM/TASM32.EXE b/plugins/Watrack/icons/TASM/TASM32.EXE
new file mode 100644
index 0000000000..edf16463b9
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/TASM32.EXE
Binary files differ
diff --git a/plugins/Watrack/icons/TASM/TLINK32.EXE b/plugins/Watrack/icons/TASM/TLINK32.EXE
new file mode 100644
index 0000000000..11ced1158c
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/TLINK32.EXE
Binary files differ
diff --git a/plugins/Watrack/icons/TASM/brcc32.exe b/plugins/Watrack/icons/TASM/brcc32.exe
new file mode 100644
index 0000000000..88795df846
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/brcc32.exe
Binary files differ
diff --git a/plugins/Watrack/icons/TASM/icons.bat b/plugins/Watrack/icons/TASM/icons.bat
new file mode 100644
index 0000000000..5dd69d1433
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/icons.bat
@@ -0,0 +1,9 @@
+@echo off
+if /i '%1' == 'buttons' (set iconres=icons) else set iconres=iconspl
+brcc32 %iconres%.rc -i%2 -foicons.res
+tasm32 watrack.asm
+tlink32 -Tpd watrack.obj,watrack_%1.dll,,,,icons.res
+del *.map
+del *.obj
+del *.res
+move watrack_%1.dll ..\..\..\bin \ No newline at end of file
diff --git a/plugins/Watrack/icons/TASM/icons.rc b/plugins/Watrack/icons/TASM/icons.rc
new file mode 100644
index 0000000000..586210d05a
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/icons.rc
@@ -0,0 +1,58 @@
+#include "waticons.h"
+LANGUAGE 0,0
+
+IDI_PREV_NORMAL ICON "previous.ico"
+IDI_PLAY_NORMAL ICON "play.ico"
+IDI_PAUSE_NORMAL ICON "pause.ico"
+IDI_STOP_NORMAL ICON "stop.ico"
+IDI_NEXT_NORMAL ICON "next.ico"
+
+IDI_PREV_HOVERED ICON "previous_hovered.ico"
+IDI_PLAY_HOVERED ICON "play_hovered.ico"
+IDI_PAUSE_HOVERED ICON "pause_hovered.ico"
+IDI_STOP_HOVERED ICON "stop_hovered.ico"
+IDI_NEXT_HOVERED ICON "next_hovered.ico"
+
+IDI_PREV_PRESSED ICON "previous_pressed.ico"
+IDI_PLAY_PRESSED ICON "play_pressed.ico"
+IDI_PAUSE_PRESSED ICON "pause_pressed.ico"
+IDI_STOP_PRESSED ICON "stop_pressed.ico"
+IDI_NEXT_PRESSED ICON "next_pressed.ico"
+
+IDI_VOLDN_NORMAL ICON "volume_down.ico"
+IDI_VOLUP_NORMAL ICON "volume_up.ico"
+IDI_VOLDN_HOVERED ICON "volume_down_hovered.ico"
+IDI_VOLUP_HOVERED ICON "volume_up_hovered.ico"
+IDI_VOLDN_PRESSED ICON "volume_down_pressed.ico"
+IDI_VOLUP_PRESSED ICON "volume_up_pressed.ico"
+
+IDI_SLIDER_NORMAL ICON "slider.ico"
+IDI_SLIDER_HOVERED ICON "slider_hovered.ico"
+IDI_SLIDER_PRESSED ICON "slider_pressed.ico"
+
+IDI_PLUGIN_ENABLE ICON "enable.ico"
+IDI_PLUGIN_DISABLE ICON "disable.ico"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,0,0,2
+ PRODUCTVERSION 0,0,0,2
+ FILEFLAGSMASK $3F
+ FILEOS 4
+ FILETYPE 2
+ FILESUBTYPE 0
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "FileDescription", "Solid indexed and truecolor"
+ VALUE "FileVersion", "0.0.0.2"
+ VALUE "OriginalFilename", "watrack_buttons.dll"
+ VALUE "ProductName", "WATrack buttons icons"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation",0,1200
+ END
+END
diff --git a/plugins/Watrack/icons/TASM/iconspl.rc b/plugins/Watrack/icons/TASM/iconspl.rc
new file mode 100644
index 0000000000..ab7a362869
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/iconspl.rc
@@ -0,0 +1,61 @@
+LANGUAGE 0,0
+
+Player_1BY1 ICON "1by1.ico"
+Player_AIMP ICON "aimp.ico"
+Player_ALSHOW ICON "alshow.ico"
+Player_ALSONG ICON "alsong.ico"
+Player_APOLLO ICON "apollo.ico"
+Player_ASHAMPOO_MEDIA_PLAYER ICON "Ashampoo Media Player.ico"
+Player_AUDIOPLAYER ICON "audio.ico"
+Player_BEHOLDTV ICON "BeholdTV.ico"
+Player_BILLY ICON "Billy.ico"
+Player_BSPLAYER ICON "bsplayer.ico"
+Player_CORE_MEDIA_PLAYER ICON "Core Media Player.ico"
+Player_COWON_JETAUDIO ICON "JetAudio.ico"
+Player_CREATIVE_MEDIA_SOURCE ICON "cms.ico"
+Player_CRYSTAL_PLAYER ICON "Crystal Player.ico"
+Player_CYBERLINK_POWERDVD ICON "Cyberlink PowerDVD.ico"
+Player_EVIL_PLAYER ICON "Evil Player.ico"
+Player_FLVPLAYER ICON "flv.ico"
+Player_FOOBAR2000 ICON "foobar2000.ico"
+Player_GOMPLAYER ICON "GOMPlayer.ico"
+Player_HELIUM_MUSIC_MANAGER ICON "Helium Music Manager.ico"
+Player_ITUNES ICON "iTunes.ico"
+Player_J_RIVER_MEDIA_CENTER ICON "J.River Media Center.ico"
+Player_KMPLAYER ICON "KMPlayer.ico"
+Player_LAST_FM ICON "lastfm.ico"
+Player_LIGHTALLOY ICON "LA.ico"
+Player_MEDIA_COMMANDER_EXPRESS ICON "mcx.ico"
+Player_MEDIAMONKEY ICON "MediaMonkey.ico"
+Player_MOREAMP ICON "MoreAmp.ico"
+Player_MPC ICON "MPC.ico"
+Player_MPLAYER ICON "MPlayer.ico"
+Player_MUSICCUBE_ONE ICON "mcone.ico"
+Player_MUSICMATCH_JUKEBOX ICON "mmatch.ico"
+Player_MUSIKCUBE ICON "MusikCube.ico"
+Player_PLUTON ICON "pluton.ico"
+Player_QCD ICON "QCDPlayer.ico"
+Player_QUICKTIME_PLAYER ICON "QuickTime Player.ico"
+Player_RADLIGHT ICON "RadLight.ico"
+Player_REAL_PLAYER ICON "Real Player.ico"
+Player_SAPS ICON "saps.ico"
+Player_SONGBIRD ICON "SongBird.ico"
+Player_SPIDER_PLAYER ICON "Spider Player.ico"
+Player_ULTRA_PLAYER ICON "Ultra player.ico"
+Player_VIDEOLAN_PLAYER ICON "VLC.ico"
+Player_VIPLAY ICON "vp3.ico"
+Player_VUPLAYER ICON "VUPlayer.ico"
+Player_WIFIRADIO_PLAYER ICON "wifi.ico"
+Player_WINAMP ICON "winamp.ico"
+Player_WINAMP_CLONE ICON "wany.ico"
+Player_WINDVD ICON "WinDVD.ico"
+Player_WMP ICON "WMP 9.ico"
+Player_XMPLAY ICON "XMPlay.ico"
+Player_ZOOM ICON "Zoom Player.ico"
+
+/*
+Player_ ICON ""
+Player_ ICON ""
+Player_ ICON ""
+Player_ ICON ""
+*/
diff --git a/plugins/Watrack/icons/TASM/rw32core.dll b/plugins/Watrack/icons/TASM/rw32core.dll
new file mode 100644
index 0000000000..29ec016027
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/rw32core.dll
Binary files differ
diff --git a/plugins/Watrack/icons/TASM/waticons.h b/plugins/Watrack/icons/TASM/waticons.h
new file mode 100644
index 0000000000..bad8cadea2
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/waticons.h
@@ -0,0 +1,35 @@
+#define IDI_PREV_NORMAL 1
+#define IDI_PREV_HOVERED 2
+#define IDI_PREV_PRESSED 3
+
+#define IDI_PLAY_NORMAL 4
+#define IDI_PLAY_HOVERED 5
+#define IDI_PLAY_PRESSED 6
+
+#define IDI_PAUSE_NORMAL 7
+#define IDI_PAUSE_HOVERED 8
+#define IDI_PAUSE_PRESSED 9
+
+#define IDI_STOP_NORMAL 10
+#define IDI_STOP_HOVERED 11
+#define IDI_STOP_PRESSED 12
+
+#define IDI_NEXT_NORMAL 13
+#define IDI_NEXT_HOVERED 14
+#define IDI_NEXT_PRESSED 15
+
+#define IDI_VOLDN_NORMAL 16
+#define IDI_VOLDN_HOVERED 17
+#define IDI_VOLDN_PRESSED 18
+
+#define IDI_VOLUP_NORMAL 19
+#define IDI_VOLUP_HOVERED 20
+#define IDI_VOLUP_PRESSED 21
+
+#define IDI_SLIDER_NORMAL 22
+#define IDI_SLIDER_HOVERED 23
+#define IDI_SLIDER_PRESSED 24
+
+
+#define IDI_PLUGIN_ENABLE 100
+#define IDI_PLUGIN_DISABLE 101
diff --git a/plugins/Watrack/icons/TASM/watrack.asm b/plugins/Watrack/icons/TASM/watrack.asm
new file mode 100644
index 0000000000..cab1fa249f
--- /dev/null
+++ b/plugins/Watrack/icons/TASM/watrack.asm
@@ -0,0 +1,8 @@
+.386
+.model flat, stdcall
+.code
+start:
+ mov al, 1
+ ret
+end start
+end \ No newline at end of file
diff --git a/plugins/Watrack/icons/iconsets/players/1by1.ico b/plugins/Watrack/icons/iconsets/players/1by1.ico
new file mode 100644
index 0000000000..e8f3e4ae82
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/1by1.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/AIMP.ico b/plugins/Watrack/icons/iconsets/players/AIMP.ico
new file mode 100644
index 0000000000..a0f99889b9
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/AIMP.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Ashampoo Media Player.ico b/plugins/Watrack/icons/iconsets/players/Ashampoo Media Player.ico
new file mode 100644
index 0000000000..8496bf2eb0
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Ashampoo Media Player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/BeholdTV.ico b/plugins/Watrack/icons/iconsets/players/BeholdTV.ico
new file mode 100644
index 0000000000..8430b7723c
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/BeholdTV.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Billy.ico b/plugins/Watrack/icons/iconsets/players/Billy.ico
new file mode 100644
index 0000000000..655f2d97f6
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Billy.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Core Media Player.ico b/plugins/Watrack/icons/iconsets/players/Core Media Player.ico
new file mode 100644
index 0000000000..f5edff45d5
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Core Media Player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Crystal Player.ico b/plugins/Watrack/icons/iconsets/players/Crystal Player.ico
new file mode 100644
index 0000000000..0f0a8d894b
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Crystal Player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Cyberlink PowerDVD.ico b/plugins/Watrack/icons/iconsets/players/Cyberlink PowerDVD.ico
new file mode 100644
index 0000000000..7a26e8c05c
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Cyberlink PowerDVD.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Evil Player.ico b/plugins/Watrack/icons/iconsets/players/Evil Player.ico
new file mode 100644
index 0000000000..d11cda81c5
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Evil Player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/GOMPlayer.ico b/plugins/Watrack/icons/iconsets/players/GOMPlayer.ico
new file mode 100644
index 0000000000..9a2f0fb960
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/GOMPlayer.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Helium Music Manager.ico b/plugins/Watrack/icons/iconsets/players/Helium Music Manager.ico
new file mode 100644
index 0000000000..abdc4ef2b0
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Helium Music Manager.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/J.River Media Center.ico b/plugins/Watrack/icons/iconsets/players/J.River Media Center.ico
new file mode 100644
index 0000000000..2a092c2c7e
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/J.River Media Center.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/JetAudio.ico b/plugins/Watrack/icons/iconsets/players/JetAudio.ico
new file mode 100644
index 0000000000..9e3f536fca
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/JetAudio.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/KMPlayer.ico b/plugins/Watrack/icons/iconsets/players/KMPlayer.ico
new file mode 100644
index 0000000000..aca7ba1514
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/KMPlayer.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/LastFM.ico b/plugins/Watrack/icons/iconsets/players/LastFM.ico
new file mode 100644
index 0000000000..934e7090e2
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/LastFM.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/MediaMonkey.ico b/plugins/Watrack/icons/iconsets/players/MediaMonkey.ico
new file mode 100644
index 0000000000..490e5c10b9
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/MediaMonkey.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/MoreAmp.ico b/plugins/Watrack/icons/iconsets/players/MoreAmp.ico
new file mode 100644
index 0000000000..8b8e560495
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/MoreAmp.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/MusikCube.ico b/plugins/Watrack/icons/iconsets/players/MusikCube.ico
new file mode 100644
index 0000000000..36d266a3d0
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/MusikCube.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/QCDPlayer.ico b/plugins/Watrack/icons/iconsets/players/QCDPlayer.ico
new file mode 100644
index 0000000000..385282a192
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/QCDPlayer.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Quicktime Player.ico b/plugins/Watrack/icons/iconsets/players/Quicktime Player.ico
new file mode 100644
index 0000000000..35268906c1
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Quicktime Player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/RadLight.ico b/plugins/Watrack/icons/iconsets/players/RadLight.ico
new file mode 100644
index 0000000000..be5a1c1499
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/RadLight.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Real Player.ico b/plugins/Watrack/icons/iconsets/players/Real Player.ico
new file mode 100644
index 0000000000..99dc2d4f34
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Real Player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Spider Player.ico b/plugins/Watrack/icons/iconsets/players/Spider Player.ico
new file mode 100644
index 0000000000..c649b35d8b
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Spider Player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Ultra player.ico b/plugins/Watrack/icons/iconsets/players/Ultra player.ico
new file mode 100644
index 0000000000..4a54035ecc
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Ultra player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/VUPlayer.ico b/plugins/Watrack/icons/iconsets/players/VUPlayer.ico
new file mode 100644
index 0000000000..1648195b15
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/VUPlayer.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/WMP 9.ico b/plugins/Watrack/icons/iconsets/players/WMP 9.ico
new file mode 100644
index 0000000000..124a27aea0
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/WMP 9.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/WinDVD.ico b/plugins/Watrack/icons/iconsets/players/WinDVD.ico
new file mode 100644
index 0000000000..79cd1c7391
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/WinDVD.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/XMPlay.ico b/plugins/Watrack/icons/iconsets/players/XMPlay.ico
new file mode 100644
index 0000000000..40952b26a1
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/XMPlay.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/Zoom Player.ico b/plugins/Watrack/icons/iconsets/players/Zoom Player.ico
new file mode 100644
index 0000000000..fa62cb0d68
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/Zoom Player.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/alshow.ico b/plugins/Watrack/icons/iconsets/players/alshow.ico
new file mode 100644
index 0000000000..d01d8846a3
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/alshow.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/alsong.ico b/plugins/Watrack/icons/iconsets/players/alsong.ico
new file mode 100644
index 0000000000..b7585afbfe
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/alsong.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/apollo.ico b/plugins/Watrack/icons/iconsets/players/apollo.ico
new file mode 100644
index 0000000000..b8a76d4569
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/apollo.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/audio.ico b/plugins/Watrack/icons/iconsets/players/audio.ico
new file mode 100644
index 0000000000..7ad8262c54
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/audio.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/bsplayer.ico b/plugins/Watrack/icons/iconsets/players/bsplayer.ico
new file mode 100644
index 0000000000..9d40734e4d
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/bsplayer.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/cms.ico b/plugins/Watrack/icons/iconsets/players/cms.ico
new file mode 100644
index 0000000000..7b71b4cad5
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/cms.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/flv.ico b/plugins/Watrack/icons/iconsets/players/flv.ico
new file mode 100644
index 0000000000..ba0d4cba83
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/flv.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/foobar2000.ico b/plugins/Watrack/icons/iconsets/players/foobar2000.ico
new file mode 100644
index 0000000000..a1b0e4b7a1
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/foobar2000.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/itunes.ico b/plugins/Watrack/icons/iconsets/players/itunes.ico
new file mode 100644
index 0000000000..d4694d2969
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/itunes.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/la.ico b/plugins/Watrack/icons/iconsets/players/la.ico
new file mode 100644
index 0000000000..27c045931c
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/la.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/mcone.ico b/plugins/Watrack/icons/iconsets/players/mcone.ico
new file mode 100644
index 0000000000..be73f7cd30
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/mcone.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/mcx.ico b/plugins/Watrack/icons/iconsets/players/mcx.ico
new file mode 100644
index 0000000000..3532fa5da2
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/mcx.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/mmatch.ico b/plugins/Watrack/icons/iconsets/players/mmatch.ico
new file mode 100644
index 0000000000..ffd2b8ed0a
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/mmatch.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/mpc.ico b/plugins/Watrack/icons/iconsets/players/mpc.ico
new file mode 100644
index 0000000000..4e5d09966d
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/mpc.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/mplayer.ico b/plugins/Watrack/icons/iconsets/players/mplayer.ico
new file mode 100644
index 0000000000..219d59b7b9
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/mplayer.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/pluton.ico b/plugins/Watrack/icons/iconsets/players/pluton.ico
new file mode 100644
index 0000000000..10397ba1f8
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/pluton.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/saps.ico b/plugins/Watrack/icons/iconsets/players/saps.ico
new file mode 100644
index 0000000000..41263a4ef7
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/saps.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/songbird.ico b/plugins/Watrack/icons/iconsets/players/songbird.ico
new file mode 100644
index 0000000000..2876b1ca46
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/songbird.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/vlc.ico b/plugins/Watrack/icons/iconsets/players/vlc.ico
new file mode 100644
index 0000000000..7caef3b91e
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/vlc.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/vp3.ico b/plugins/Watrack/icons/iconsets/players/vp3.ico
new file mode 100644
index 0000000000..b8227fe7e5
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/vp3.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/wany.ico b/plugins/Watrack/icons/iconsets/players/wany.ico
new file mode 100644
index 0000000000..4349576c82
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/wany.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/wifi.ico b/plugins/Watrack/icons/iconsets/players/wifi.ico
new file mode 100644
index 0000000000..022cd7adee
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/wifi.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/players/winamp.ico b/plugins/Watrack/icons/iconsets/players/winamp.ico
new file mode 100644
index 0000000000..7dc5a2a3d9
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/players/winamp.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/disable.ico b/plugins/Watrack/icons/iconsets/true+256-solid/disable.ico
new file mode 100644
index 0000000000..390f0852a2
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/disable.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/enable.ico b/plugins/Watrack/icons/iconsets/true+256-solid/enable.ico
new file mode 100644
index 0000000000..0e20d3a616
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/enable.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/next.ico b/plugins/Watrack/icons/iconsets/true+256-solid/next.ico
new file mode 100644
index 0000000000..5d85a0cbfb
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/next.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/next_hovered.ico b/plugins/Watrack/icons/iconsets/true+256-solid/next_hovered.ico
new file mode 100644
index 0000000000..58dfc4e78b
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/next_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/next_pressed.ico b/plugins/Watrack/icons/iconsets/true+256-solid/next_pressed.ico
new file mode 100644
index 0000000000..304e67c42c
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/next_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/pause.ico b/plugins/Watrack/icons/iconsets/true+256-solid/pause.ico
new file mode 100644
index 0000000000..b719b08229
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/pause.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/pause_hovered.ico b/plugins/Watrack/icons/iconsets/true+256-solid/pause_hovered.ico
new file mode 100644
index 0000000000..6f83916a8f
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/pause_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/pause_pressed.ico b/plugins/Watrack/icons/iconsets/true+256-solid/pause_pressed.ico
new file mode 100644
index 0000000000..8455a55231
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/pause_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/play.ico b/plugins/Watrack/icons/iconsets/true+256-solid/play.ico
new file mode 100644
index 0000000000..e7b8c0360b
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/play.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/play_hovered.ico b/plugins/Watrack/icons/iconsets/true+256-solid/play_hovered.ico
new file mode 100644
index 0000000000..973e042a78
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/play_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/play_pressed.ico b/plugins/Watrack/icons/iconsets/true+256-solid/play_pressed.ico
new file mode 100644
index 0000000000..75c3119eb3
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/play_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/previous.ico b/plugins/Watrack/icons/iconsets/true+256-solid/previous.ico
new file mode 100644
index 0000000000..0b38110f84
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/previous.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/previous_hovered.ico b/plugins/Watrack/icons/iconsets/true+256-solid/previous_hovered.ico
new file mode 100644
index 0000000000..b1e25de6b0
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/previous_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/previous_pressed.ico b/plugins/Watrack/icons/iconsets/true+256-solid/previous_pressed.ico
new file mode 100644
index 0000000000..0b0accd00e
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/previous_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/slider.ico b/plugins/Watrack/icons/iconsets/true+256-solid/slider.ico
new file mode 100644
index 0000000000..785bd748af
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/slider.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/slider_hovered.ico b/plugins/Watrack/icons/iconsets/true+256-solid/slider_hovered.ico
new file mode 100644
index 0000000000..0e20d3a616
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/slider_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/slider_pressed.ico b/plugins/Watrack/icons/iconsets/true+256-solid/slider_pressed.ico
new file mode 100644
index 0000000000..390f0852a2
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/slider_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/stop.ico b/plugins/Watrack/icons/iconsets/true+256-solid/stop.ico
new file mode 100644
index 0000000000..444302bd67
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/stop.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/stop_hovered.ico b/plugins/Watrack/icons/iconsets/true+256-solid/stop_hovered.ico
new file mode 100644
index 0000000000..00eadcab2a
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/stop_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/stop_pressed.ico b/plugins/Watrack/icons/iconsets/true+256-solid/stop_pressed.ico
new file mode 100644
index 0000000000..81ae38790f
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/stop_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/volume_down.ico b/plugins/Watrack/icons/iconsets/true+256-solid/volume_down.ico
new file mode 100644
index 0000000000..44e89abcb3
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/volume_down.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/volume_down_hovered.ico b/plugins/Watrack/icons/iconsets/true+256-solid/volume_down_hovered.ico
new file mode 100644
index 0000000000..082c9c1bf9
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/volume_down_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/volume_down_pressed.ico b/plugins/Watrack/icons/iconsets/true+256-solid/volume_down_pressed.ico
new file mode 100644
index 0000000000..ca48da4d03
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/volume_down_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/volume_up.ico b/plugins/Watrack/icons/iconsets/true+256-solid/volume_up.ico
new file mode 100644
index 0000000000..ebe32ac085
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/volume_up.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/volume_up_hovered.ico b/plugins/Watrack/icons/iconsets/true+256-solid/volume_up_hovered.ico
new file mode 100644
index 0000000000..76bb840dd8
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/volume_up_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true+256-solid/volume_up_pressed.ico b/plugins/Watrack/icons/iconsets/true+256-solid/volume_up_pressed.ico
new file mode 100644
index 0000000000..b9a0e2c9d1
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true+256-solid/volume_up_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/next.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/next.ico
new file mode 100644
index 0000000000..b716875893
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/next.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/next_hovered.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/next_hovered.ico
new file mode 100644
index 0000000000..6a41ff71d4
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/next_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/next_pressed.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/next_pressed.ico
new file mode 100644
index 0000000000..5766059f10
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/next_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/pause.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/pause.ico
new file mode 100644
index 0000000000..612030f3f2
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/pause.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/pause_hovered.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/pause_hovered.ico
new file mode 100644
index 0000000000..681f7e4a24
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/pause_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/pause_pressed.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/pause_pressed.ico
new file mode 100644
index 0000000000..d1f4421b20
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/pause_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/play.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/play.ico
new file mode 100644
index 0000000000..e35113cced
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/play.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/play_hovered.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/play_hovered.ico
new file mode 100644
index 0000000000..591e186361
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/play_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/play_pressed.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/play_pressed.ico
new file mode 100644
index 0000000000..029c30076b
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/play_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/previous.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/previous.ico
new file mode 100644
index 0000000000..4f57e43af3
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/previous.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/previous_hovered.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/previous_hovered.ico
new file mode 100644
index 0000000000..c456ca427f
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/previous_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/previous_pressed.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/previous_pressed.ico
new file mode 100644
index 0000000000..68aa16a1c9
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/previous_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/slider.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/slider.ico
new file mode 100644
index 0000000000..1f5df0b577
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/slider.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/stop.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/stop.ico
new file mode 100644
index 0000000000..c17432d894
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/stop.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/stop_hovered.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/stop_hovered.ico
new file mode 100644
index 0000000000..899030c9c7
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/stop_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/stop_pressed.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/stop_pressed.ico
new file mode 100644
index 0000000000..65f3c17517
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/stop_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/ver.res b/plugins/Watrack/icons/iconsets/true-solid-faith/ver.res
new file mode 100644
index 0000000000..aafbd00b59
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/ver.res
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down.ico
new file mode 100644
index 0000000000..95ce39a7d7
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down_hovered.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down_hovered.ico
new file mode 100644
index 0000000000..a1195d1034
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down_pressed.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down_pressed.ico
new file mode 100644
index 0000000000..9ebd49660b
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_down_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up.ico
new file mode 100644
index 0000000000..e7875083af
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up_hovered.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up_hovered.ico
new file mode 100644
index 0000000000..94332014fa
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up_hovered.ico
Binary files differ
diff --git a/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up_pressed.ico b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up_pressed.ico
new file mode 100644
index 0000000000..edfab79326
--- /dev/null
+++ b/plugins/Watrack/icons/iconsets/true-solid-faith/volume_up_pressed.ico
Binary files differ
diff --git a/plugins/Watrack/icons/make-buttons.bat b/plugins/Watrack/icons/make-buttons.bat
new file mode 100644
index 0000000000..dbca3ae634
--- /dev/null
+++ b/plugins/Watrack/icons/make-buttons.bat
@@ -0,0 +1,4 @@
+:@echo off
+if /i '%1' == '' (set asm=tasm) else set asm=%1
+if /i '%2' == '' (set iconpack=true+256-solid) else set iconpack=%2
+call make.bat buttons %iconpack% %asm% \ No newline at end of file
diff --git a/plugins/Watrack/icons/make-players.bat b/plugins/Watrack/icons/make-players.bat
new file mode 100644
index 0000000000..ec90aa49bb
--- /dev/null
+++ b/plugins/Watrack/icons/make-players.bat
@@ -0,0 +1,2 @@
+@echo off
+call make.bat icons players tasm \ No newline at end of file
diff --git a/plugins/Watrack/icons/make.bat b/plugins/Watrack/icons/make.bat
new file mode 100644
index 0000000000..95f90dcca6
--- /dev/null
+++ b/plugins/Watrack/icons/make.bat
@@ -0,0 +1,16 @@
+:first parameter - 'icons' or 'buttons' - type of iconpack ()
+:second parameter - iconpack name (for buttons mainly)
+:third parameter - assembler? (tasm)
+:@echo off
+if /i '%1' == '' (set pack=buttons) else set pack=%1
+if '%pack%' == 'icons' goto players
+if /i '%2' == '' (set iconpack=true+256-solid) else set iconpack=%2
+goto next
+:players
+if /i '%2' == '' (set iconpack=players) else set iconpack=%2
+:next
+if /i '%3' == '' (set asm=tasm) else set asm=%3
+:@echo off
+cd %asm%
+call icons.bat %pack% ..\iconsets\%iconpack% %4 %5 %6 %7 %8 %9
+cd ..\
diff --git a/plugins/Watrack/icons/waticons.inc b/plugins/Watrack/icons/waticons.inc
new file mode 100644
index 0000000000..0c3c423f0e
--- /dev/null
+++ b/plugins/Watrack/icons/waticons.inc
@@ -0,0 +1,35 @@
+const
+ IDI_PREV_NORMAL = 1;
+ IDI_PREV_HOVERED = 2;
+ IDI_PREV_PRESSED = 3;
+
+ IDI_PLAY_NORMAL = 4;
+ IDI_PLAY_HOVERED = 5;
+ IDI_PLAY_PRESSED = 6;
+
+ IDI_PAUSE_NORMAL = 7;
+ IDI_PAUSE_HOVERED = 8;
+ IDI_PAUSE_PRESSED = 9;
+
+ IDI_STOP_NORMAL = 10;
+ IDI_STOP_HOVERED = 11;
+ IDI_STOP_PRESSED = 12;
+
+ IDI_NEXT_NORMAL = 13;
+ IDI_NEXT_HOVERED = 14;
+ IDI_NEXT_PRESSED = 15;
+
+ IDI_VOLDN_NORMAL = 16;
+ IDI_VOLDN_HOVERED = 17;
+ IDI_VOLDN_PRESSED = 18;
+
+ IDI_VOLUP_NORMAL = 19;
+ IDI_VOLUP_HOVERED = 20;
+ IDI_VOLUP_PRESSED = 21;
+
+ IDI_SLIDER_NORMAL = 22;
+ IDI_SLIDER_HOVERED = 23;
+ IDI_SLIDER_PRESSED = 24;
+
+ IDI_PLUGIN_ENABLE = 100;
+ IDI_PLUGIN_DISABLE = 101;
diff --git a/plugins/Watrack/kolframe/frm.rc b/plugins/Watrack/kolframe/frm.rc
new file mode 100644
index 0000000000..50180b4b53
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm.rc
@@ -0,0 +1,84 @@
+#include "frm_rc.inc"
+
+LANGUAGE 0,0
+
+FRAME DIALOGEX 0, 0, 304, 226, 0
+STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ AUTOCHECKBOX "Use buttons gap" , IDC_BTNGAP , 3, 44, 146, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+
+ LTEXT "Frame refresh time", -1, 47, 2, 100, 14, SS_CENTERIMAGE
+ EDITTEXT IDC_TIMER , 3, 3, 40, 12, ES_RIGHT | ES_NUMBER
+
+ AUTOCHECKBOX "Hide when no player", IDC_HIDEFRAMEPLAYER, 3, 16, 146, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Hide when no music" , IDC_HIDEFRAMEMUSIC , 3, 30, 146, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+
+ AUTOCHECKBOX "Show info in the frame" , IDC_SHOWTEXT , 155, 2, 144, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY | BS_RIGHT | BS_LEFTTEXT
+ AUTOCHECKBOX "Show controls in the frame", IDC_SHOWCTRLS, 155, 16, 144, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY | BS_RIGHT | BS_LEFTTEXT
+ AUTOCHECKBOX "Show volume controls" , IDC_SHOWVOLUM, 155, 30, 144, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY | BS_RIGHT | BS_LEFTTEXT
+ AUTOCHECKBOX "Show trackbar" , IDC_SHOWBAR , 155, 44, 144, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY | BS_RIGHT | BS_LEFTTEXT
+
+ AUTOCHECKBOX "Use Picture",IDC_FRMUSEPIC,3,65,91,14,BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ EDITTEXT IDC_FRMBKPIC, 96, 65, 185, 14
+ PUSHBUTTON "...", IDC_FRMPICBTN, 284, 65, 16, 14
+
+ GROUPBOX "Picture transform", -1, 2, 82, 298, 59
+ AUTOCHECKBOX "Center horizontally" , IDC_CENTERX , 6, 91, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Center vertically" , IDC_CENTERY , 6, 107, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Bottom" , IDC_BOTTOM , 6, 123, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Tile horizontally" , IDC_TILEX , 104, 91, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Tile vertically" , IDC_TILEY , 104, 107, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Right" , IDC_RIGHT , 104, 123, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Stretch to width" , IDC_STRETCHX, 202, 91, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Stretch to height" , IDC_STRETCHY, 202, 107, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Stretch proportionally", IDC_PROP , 202, 123, 96, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+
+ CTEXT "Cover padding", -1, 6, 152, 142, 14, SS_CENTERIMAGE
+ EDITTEXT IDC_PADDING_TOP , 64, 168, 24, 14, ES_RIGHT | ES_NUMBER
+ EDITTEXT IDC_PADDING_LEFT , 50, 184, 24, 14, ES_RIGHT | ES_NUMBER
+ EDITTEXT IDC_PADDING_RIGHT , 78, 184, 24, 14, ES_RIGHT | ES_NUMBER
+ EDITTEXT IDC_PADDING_BOTTOM, 64, 200, 24, 14, ES_RIGHT | ES_NUMBER
+
+ AUTOCHECKBOX "Manual element placement", IDC_MANUALPLACE, 155,144,144,16, BS_VCENTER | BS_MULTILINE | BS_RIGHT | BS_LEFTTEXT
+
+// TBS_TOOLTIPS
+ CONTROL "",IDC_FRMALPHA,"msctls_trackbar32", TBS_BOTTOM|TBS_NOTICKS|$100,160,168,68,11
+ LTEXT "Alpha",-1,230,168,75,11, SS_CENTERIMAGE
+
+ CONTROL "",IDC_FRMCOLOR, "ColourPicker", WS_TABSTOP, 162, 181, 14, 14
+ LTEXT "Background color",-1,178,181,126,14, SS_CENTERIMAGE
+
+ AUTOCHECKBOX "Use cover instead of picture", IDC_USECOVER, 155, 196, 142, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+}
+
+FRAME2 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 "Choose font...", IDC_FRMFONT, 84, 90, 64, 12
+
+ GROUPBOX "Text effect",-1,154,6,142,76
+ AUTORADIOBUTTON "Cut", IDC_EFF_CUT , 158, 16, 136, 12, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Wrap", IDC_EFF_WRAP, 158, 28, 136, 12, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Roll", IDC_EFF_ROLL, 158, 40, 136, 12, NOT WS_TABSTOP
+ AUTORADIOBUTTON "PingPong", IDC_EFF_PONG, 158, 52, 136, 12, NOT WS_TABSTOP
+ AUTOCHECKBOX "Align text to center", IDC_ALCENTER, 158, 66, 136, 12, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+
+ GROUPBOX "Text movement", -1, 6, 6, 142, 76, WS_TABSTOP
+ LTEXT "Text rotation speed (1-20)", -1, 32, 17, 114, 12, SS_CENTERIMAGE
+ LTEXT "Scroll step" , -1, 32, 33, 114, 12, SS_CENTERIMAGE
+ LTEXT "Scroll gap" , -1, 32, 49, 114, 12, SS_CENTERIMAGE
+// LTEXT "Minimum scroll tail" , -1, 32, 65, 114, 12, SS_CENTERIMAGE
+ EDITTEXT IDC_TIMER , 10, 17, 20, 12, ES_RIGHT | ES_NUMBER
+ EDITTEXT IDC_ROLLSTEP, 10, 33, 20, 12, ES_RIGHT | ES_NUMBER
+ EDITTEXT IDC_ROLLGAP , 10, 49, 20, 12, ES_RIGHT | ES_NUMBER
+// EDITTEXT IDC_ROLLTAIL, 10, 65, 20, 12, ES_RIGHT | ES_NUMBER
+
+ CONTROL "M" ,IDC_MACRO_HELP ,"MButtonClass",WS_TABSTOP,284,156,16,16,$18000000
+ RTEXT "Frame Text", -1 , 4, 163, 274, 10
+ EDITTEXT IDC_FRAME_TEXT , 4, 174, 296, 48,
+ ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+}
diff --git a/plugins/Watrack/kolframe/frm.res b/plugins/Watrack/kolframe/frm.res
new file mode 100644
index 0000000000..b978cdb07e
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm.res
Binary files differ
diff --git a/plugins/Watrack/kolframe/frm_data.inc b/plugins/Watrack/kolframe/frm_data.inc
new file mode 100644
index 0000000000..52535d15b2
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_data.inc
@@ -0,0 +1,37 @@
+{Frame data}
+
+const
+ //show controls
+ scButtons = $0001;
+ scTrackBar = $0002;
+ scText = $0004;
+ scVolume = $0008;
+ scGap = $0010;
+ scAll = $000F;
+
+ ppLeft = 0;
+ ppRight = 1;
+ //effects
+ effCut = 0;
+ effWrap = 1;
+ effRoll = 2;
+ effPong = 3;
+
+ // Back bitmap mode
+ frbkCenterX = $0001;
+ frbkCenterY = $0002;
+ frbkCenter = frbkCenterX or frbkCenterY;
+ frbkTileX = $0004;
+ frbkTileY = $0008;
+ frbkTile = frbkTileX or frbkTileY;
+ frbkStretchX = $0010;
+ frbkStretchY = $0020;
+ frbkStretch = frbkStretchX or frbkStretchY;
+ frbkProportional = $0040;
+ frbkBottom = $0080;
+ frbkRight = $0100;
+
+const
+ numbuttons = 7;
+ VolBtnDist = 6;
+ BtnGap = 3;
diff --git a/plugins/Watrack/kolframe/frm_designer.inc b/plugins/Watrack/kolframe/frm_designer.inc
new file mode 100644
index 0000000000..f12c01f05d
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_designer.inc
@@ -0,0 +1,164 @@
+{Frame designer}
+const
+ // trackbar
+ opt_tbleft :pAnsiChar='frame/designer/trackbar/left';
+ opt_tbtop :pAnsiChar='frame/designer/trackbar/top';
+ opt_tbwidth :pAnsiChar='frame/designer/trackbar/width';
+ opt_tbheight:pAnsiChar='frame/designer/trackbar/height';
+ // text block
+ opt_tleft :pAnsiChar='frame/designer/text/left';
+ opt_ttop :pAnsiChar='frame/designer/text/top';
+ opt_twidth :pAnsiChar='frame/designer/text/width';
+ opt_theight :pAnsiChar='frame/designer/text/height';
+ // buttons (with number)
+ opt_bleft :pAnsiChar='frame/designer/buttons/left';
+ opt_btop :pAnsiChar='frame/designer/buttons/top';
+
+procedure TWATFrame.DesignerSaveSettings;
+var
+ i:integer;
+ D:PWATFrameData;
+ lleft,ltop:array [0..63] of AnsiChar;
+ pleft,ptop:PAnsiChar;
+begin
+ D:=CustomData;
+ if D.TrackBar<>nil then
+ begin
+ DBWriteWord(0,PluginShort,opt_tbleft ,D.Trackbar.Left);
+ DBWriteWord(0,PluginShort,opt_tbtop ,D.Trackbar.Top);
+ DBWriteWord(0,PluginShort,opt_tbwidth ,D.Trackbar.Width);
+ DBWriteWord(0,PluginShort,opt_tbheight,D.Trackbar.Height);
+ end;
+
+ if D.TextBlock<>nil then
+ begin
+ DBWriteWord(0,PluginShort,opt_tleft ,D.TextBlock.Left);
+ DBWriteWord(0,PluginShort,opt_ttop ,D.TextBlock.Top);
+ DBWriteWord(0,PluginShort,opt_twidth ,D.TextBlock.Width);
+ DBWriteWord(0,PluginShort,opt_theight,D.TextBlock.Height);
+ end;
+
+ if (D.ShowControls and scButtons)<>0 then
+ begin
+ if D.btnarray[0]<>nil then
+ begin
+ pleft:=StrCopyE(lleft,opt_bleft);
+ ptop :=StrCopyE(ltop ,opt_btop);
+ for i:=0 to HIGH(D.btnarray) do
+ begin
+ IntToStr(pleft,i); DBWriteWord(0,PluginShort,lleft,D.btnarray[i].Left);
+ IntToStr(ptop ,i); DBWriteWord(0,PluginShort,ltop ,D.btnarray[i].Top);
+ end;
+ end;
+ end;
+end;
+
+procedure TWATFrame.DesignerLoadSettings;
+var
+ i:integer;
+ D:PWATFrameData;
+ lleft,ltop:array [0..63] of AnsiChar;
+ pleft,ptop:PAnsiChar;
+ for_check:integer;
+begin
+ D:=CustomData;
+
+ if (D.TrackBar<>nil) and
+ ((D.ShowControls and scTrackbar)<>0) and
+ ((D.Loaded and scTrackbar)=0) then
+ begin
+ D.Loaded:=D.Loaded or scTrackbar;
+ for_check:=DBReadWord(0,PluginShort,opt_tbwidth);
+ if for_check<>0 then
+ begin
+ D.Trackbar.SetPosition(
+ DBReadWord(0,PluginShort,opt_tbleft),
+ DBReadWord(0,PluginShort,opt_tbtop));
+ D.Trackbar.SetSize(
+ for_check,
+ {18}DBReadWord(0,PluginShort,opt_tbheight));
+ end;
+ end;
+
+ if (D.TextBlock<>nil) and
+ ((D.ShowControls and scText)<>0) and
+ ((D.Loaded and scText)=0) then
+ begin
+ D.Loaded:=D.Loaded or scText;
+ for_check:=DBReadWord(0,PluginShort,opt_twidth);
+ if for_check<>0 then
+ begin
+ D.TextBlock.SetPosition(
+ DBReadWord(0,PluginShort,opt_tleft),
+ DBReadWord(0,PluginShort,opt_ttop));
+ D.TextBlock.SetSize(
+ for_check,
+ DBReadWord(0,PluginShort,opt_theight));
+ end;
+ end;
+
+ if ((D.ShowControls and scButtons)<>0) and
+ ((D.Loaded and scButtons)=0) then
+ begin
+ if D.btnarray[0]<>nil then
+ begin
+ D.Loaded:=D.Loaded or scButtons;
+ pleft:=StrCopyE(lleft,opt_bleft);
+ pleft^:='0'; (pleft+1)^:=#0;
+ for_check:=SmallInt(DBReadWord(0,PluginShort,lleft,word(-1)));
+ if for_check>=0 then
+ begin
+ ptop :=StrCopyE(ltop,opt_btop);
+ for i:=0 to HIGH(D.btnarray) do
+ begin
+ IntToStr(pleft,i);
+ IntToStr(ptop ,i);
+ D.btnarray[i].SetPosition(
+ DBReadWord(0,PluginShort,lleft,word(-1)),
+ DBReadWord(0,PluginShort,ltop ,word(-1)));
+ end;
+ end;
+ end;
+ end;
+end;
+
+procedure TWATFrame.CreateDesigner(Sender:PControl;var Mouse:TMouseEventData);
+var
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ if not D.ManualPlacement then exit;
+
+ if D.Designer=nil then
+ D.Designer:=NewDesigner(@self);
+
+ if not D.Designer.Active then
+ begin
+ // Trackbar
+ if D.Trackbar<>nil then
+ begin
+ D.Trackbar.Anchor(false,false,false,false);
+ D.Designer.Connect('Trackbar',D.Trackbar);
+ end;
+ // TextBlock
+ if D.TextBlock<>nil then
+ begin
+ D.TextBlock.Anchor(false,false,false,false);
+ D.Designer.Connect('Panel',D.TextBlock);
+ end;
+ // Icons
+ if (D.ShowControls and scButtons)<>0 then MakeButtonsDesigner;
+
+ D.Designer.Active:=true;
+ end
+ else
+ begin
+ D.Designer.Active:=False;
+
+ DesignerSaveSettings;
+ if D.Trackbar <>nil then D.Designer.Disconnect(D.Trackbar);
+ if D.TextBlock<>nil then D.Designer.Disconnect(D.TextBlock);
+ if (D.ShowControls and scButtons)<>0 then FreeButtonsDesigner;
+ Sender.Update;
+ end;
+end;
diff --git a/plugins/Watrack/kolframe/frm_dlg1.inc b/plugins/Watrack/kolframe/frm_dlg1.inc
new file mode 100644
index 0000000000..19f590af66
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_dlg1.inc
@@ -0,0 +1,283 @@
+{Frame}
+const
+ FSC_BACKGROUND = 1;
+ FSC_BEHAVIOUR = 2;
+ FSC_SHOW = 4;
+// FSC_ALPHA = 8;
+
+function MakePicFilter:PWideChar;
+var
+ buf:array [0..255] of WideChar;
+ size:integer;
+ pc:pWideChar;
+begin
+ FillChar(buf,SizeOf(buf),0);
+ pc:=StrCopyEW(StrCopyEW(buf,TranslateW('All Bitmaps')),' (*.bmp;*.jpg;*.gif;*.png)');
+ pc:=StrCopyEW(pc+1,'*.BMP;*.RLE;*.JPG;*.JPEG;*.GIF;*.PNG');
+ size:=(pc+2-@buf)*SizeOf(WideChar);
+ mGetMem(result,size);
+ move(buf,result^,size);
+end;
+
+procedure SwitchBk(Dialog:hwnd);
+var
+ en:boolean;
+begin
+ en:=IsDlgButtonChecked(Dialog,IDC_FRMUSEPIC)<>BST_UNCHECKED;
+ EnableWindow(GetDlgItem(Dialog,IDC_FRMBKPIC ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_FRMPICBTN),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_CENTERX ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_CENTERY ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_TILEX ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_TILEY ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_STRETCHX ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_STRETCHY ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_PROP ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_BOTTOM ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_RIGHT ),en);
+ EnableWindow(GetDlgItem(Dialog,IDC_USECOVER ),en);
+end;
+
+function FrameViewDlg(Dialog:HWnd; hMessage,wParam,lParam:DWord):integer; stdcall;
+const
+ DlgInited:boolean=false;
+var
+ tmp:cardinal;
+ buf1:PAnsiChar;
+ buf:PAnsiChar;
+ p:PAnsiChar;
+ tmpb:longbool;
+ pcw,tmpPicName:pWideChar;
+ D:PWATFrameData;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ DlgInited:=false;
+
+ TranslateDialogDefault(Dialog);
+ D:=FrameCtrl.CustomData;
+
+ SendDlgItemMessage(Dialog,IDC_FRMALPHA,TBM_SETRANGE,0,MAKELONG(0,255));
+ SendDlgItemMessage(Dialog,IDC_FRMALPHA,TBM_SETPOS,1,D.FrmAlpha);
+
+ if (D.ShowControls and scButtons )<>0 then CheckDlgButton(Dialog,IDC_SHOWCTRLS,BST_CHECKED);
+ if (D.ShowControls and scTrackBar)<>0 then CheckDlgButton(Dialog,IDC_SHOWBAR ,BST_CHECKED);
+ if (D.ShowControls and scText )<>0 then CheckDlgButton(Dialog,IDC_SHOWTEXT ,BST_CHECKED);
+ if (D.ShowControls and scVolume )<>0 then CheckDlgButton(Dialog,IDC_SHOWVOLUM,BST_CHECKED);
+ if (D.ShowControls and scGap )<>0 then CheckDlgButton(Dialog,IDC_BTNGAP ,BST_CHECKED);
+
+ MakeHint(Dialog,IDC_MANUALPLACE,
+ 'Use manual frame elements placement. Doubleclick on free space to start designer.');
+ CheckDlgButton(Dialog,IDC_MANUALPLACE,ORD(D.ManualPlacement));
+
+ CheckDlgButton(Dialog,IDC_HIDEFRAMEPLAYER,ORD(D.HideNoPlayer));
+ CheckDlgButton(Dialog,IDC_HIDEFRAMEMUSIC ,ORD(D.HideNoMusic));
+ EnableWindow(GetDlgItem(Dialog,IDC_HIDEFRAMEMUSIC),D.HideNoPlayer);
+
+ SendDlgItemMessage(Dialog,IDC_FRMCOLOR,CPM_SETCOLOUR,0,D.BkColor);
+ SendDlgItemMessage(Dialog,IDC_FRMCOLOR,CPM_SETDEFAULTCOLOUR,0,GetSysColor(COLOR_BTNFACE));
+ SetDlgItemInt(Dialog,IDC_FRMCOLOR,D.BkColor,false);
+
+ if D.UseBkPicture then
+ CheckDlgButton(Dialog,IDC_FRMUSEPIC,ORD(D.UseBkPicture));
+ if D.BkDefFile=nil then
+ p:=''
+ else
+ p:=D.BkDefFile;
+ SetDlgItemTextA(Dialog,IDC_FRMBKPIC,p);
+ CheckDlgButton(Dialog,IDC_USECOVER,ORD(D.UseCover));
+
+ tmp:=D.UpdInterval;
+ if (tmp>=1000) and (tmp mod 1000=0) then
+ tmp:=tmp div 1000;
+ SetDlgItemInt(Dialog,IDC_TIMER,tmp,false);
+
+ SetDlgItemInt(Dialog,IDC_PADDING_LEFT ,D.padding.left ,false);
+ SetDlgItemInt(Dialog,IDC_PADDING_TOP ,D.padding.top ,false);
+ SetDlgItemInt(Dialog,IDC_PADDING_RIGHT ,D.padding.right ,false);
+ SetDlgItemInt(Dialog,IDC_PADDING_BOTTOM,D.padding.bottom,false);
+
+ if (D.BkMode and frbkCenterX )<>0 then CheckDlgButton(Dialog,IDC_CENTERX ,BST_CHECKED);
+ if (D.BkMode and frbkCenterY )<>0 then CheckDlgButton(Dialog,IDC_CENTERY ,BST_CHECKED);
+ if (D.BkMode and frbkTileX )<>0 then CheckDlgButton(Dialog,IDC_TILEX ,BST_CHECKED);
+ if (D.BkMode and frbkTileY )<>0 then CheckDlgButton(Dialog,IDC_TILEY ,BST_CHECKED);
+ if (D.BkMode and frbkStretchX )<>0 then CheckDlgButton(Dialog,IDC_STRETCHX,BST_CHECKED);
+ if (D.BkMode and frbkStretchY )<>0 then CheckDlgButton(Dialog,IDC_STRETCHY,BST_CHECKED);
+ if (D.BkMode and frbkProportional)<>0 then CheckDlgButton(Dialog,IDC_PROP ,BST_CHECKED);
+ if (D.BkMode and frbkBottom )<>0 then CheckDlgButton(Dialog,IDC_BOTTOM ,BST_CHECKED);
+ if (D.BkMode and frbkRight )<>0 then CheckDlgButton(Dialog,IDC_RIGHT ,BST_CHECKED);
+
+ SwitchBk(Dialog);
+
+ DlgInited:=true;
+ end;
+
+ WM_HSCROLL: begin
+ if DlgInited then
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ WM_COMMAND: begin
+ if (wParam shr 16)=BN_CLICKED then
+ begin
+ case LoWord(wParam) of
+ IDC_HIDEFRAMEPLAYER: begin
+ EnableWindow(GetDlgItem(Dialog,IDC_HIDEFRAMEMUSIC),
+ IsDlgButtonChecked(Dialog,IDC_HIDEFRAMEPLAYER)<>BST_UNCHECKED);
+ end;
+
+ IDC_FRMUSEPIC: begin
+ SwitchBk(Dialog);
+ end;
+
+ IDC_FRMPICBTN: begin
+ pcw:=MakePicFilter;
+ tmpPicName:=GetDlgText(Dialog,IDC_FRMBKPIC);
+ mGetMem(buf,1024);
+ if ShowDlgW(pWideChar(buf),tmpPicName,pcw) then
+ SetDlgItemTextW(Dialog,IDC_FRMBKPIC,pWideChar(buf));
+ mFreeMem(buf);
+ mFreeMem(tmpPicName);
+ mFreeMem(pcw);
+ end;
+ end;
+ end;
+
+ if DlgInited then
+ if ((wParam shr 16)=BN_CLICKED) or
+ ((wParam shr 16)=EN_CHANGE) or
+ ((wParam shr 16)=CPN_COLOURCHANGED) then
+ begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ begin
+ D:=FrameCtrl.CustomData;
+ // Alpha channel
+ tmp:=SendDlgItemMessage(Dialog,IDC_FRMALPHA,TBM_GETPOS,0,0);
+ if tmp<>Cardinal(D.FrmAlpha) then
+ begin
+ D.FrmAlpha:=tmp;
+ if D.FrameId>=0 then
+ FrameCtrl.SetAlpha(D.FrmAlpha);
+ end;
+
+ // show/hide controls
+ tmp:=0;
+ if IsDlgButtonChecked(Dialog,IDC_SHOWCTRLS)<>BST_UNCHECKED then tmp:=tmp or scButtons;
+ if IsDlgButtonChecked(Dialog,IDC_SHOWBAR )<>BST_UNCHECKED then tmp:=tmp or scTrackBar;
+ if IsDlgButtonChecked(Dialog,IDC_SHOWTEXT )<>BST_UNCHECKED then tmp:=tmp or scText;
+ if IsDlgButtonChecked(Dialog,IDC_SHOWVOLUM)<>BST_UNCHECKED then tmp:=tmp or scVolume;
+ if IsDlgButtonChecked(Dialog,IDC_BTNGAP )<>BST_UNCHECKED then tmp:=tmp or scGap;
+ D.ShowControls:=tmp;
+
+ tmp:=IsDlgButtonChecked(Dialog,IDC_MANUALPLACE);
+ // From Auto to Manual = keep position
+ if (tmp<>BST_UNCHECKED) and not D.ManualPlacement then D.Loaded:=$FFFF;
+ D.ManualPlacement:=tmp<>BST_UNCHECKED;
+
+ // Frame background
+ tmpb:=IsDlgButtonChecked(Dialog,IDC_USECOVER)<>BST_UNCHECKED;
+ if tmpb<>D.UseCover then
+ begin
+ D.UseCover:=tmpb;
+ end;
+ tmpb:=IsDlgButtonChecked(Dialog,IDC_FRMUSEPIC)<>BST_UNCHECKED;
+ if tmpb<>D.UseBkPicture then
+ begin
+ D.UseBkPicture:=tmpb;
+ end;
+ tmp:=SendDlgItemMessage(Dialog,IDC_FRMCOLOR,CPM_GETCOLOUR,0,0);
+ if tmp<>D.BkColor then
+ begin
+ D.BkColor:=tmp;
+ end;
+
+ mGetMem(buf1,1024{*SizeOf(WideChar)});
+ buf1^:=#0;
+ buf:=GetDlgText(Dialog,IDC_FRMBKPIC,true);
+ CallService(MS_UTILS_PATHTORELATIVE,dword(buf),dword(buf1));
+ if StrCmp(buf1,D.BkDefFile)<>0 then
+ begin
+ mFreeMem(D.BkDefFile);
+ StrDup(D.BkDefFile,buf1);
+ end;
+ mFreeMem(buf);
+ mFreeMem(buf1);
+
+ // Picture effects
+ tmp:=0;
+ if IsDlgButtonchecked(Dialog,IDC_CENTERX )<>BST_UNCHECKED then tmp:=tmp or frbkCenterX;
+ if IsDlgButtonchecked(Dialog,IDC_CENTERY )<>BST_UNCHECKED then tmp:=tmp or frbkCenterY;
+ if IsDlgButtonchecked(Dialog,IDC_BOTTOM )<>BST_UNCHECKED then tmp:=tmp or frbkBottom;
+ if IsDlgButtonchecked(Dialog,IDC_RIGHT )<>BST_UNCHECKED then tmp:=tmp or frbkRight;
+ if IsDlgButtonchecked(Dialog,IDC_TILEX )<>BST_UNCHECKED then tmp:=tmp or frbkTileX;
+ if IsDlgButtonchecked(Dialog,IDC_TILEY )<>BST_UNCHECKED then tmp:=tmp or frbkTileY;
+ if IsDlgButtonchecked(Dialog,IDC_STRETCHX)<>BST_UNCHECKED then tmp:=tmp or frbkStretchX;
+ if IsDlgButtonchecked(Dialog,IDC_STRETCHY)<>BST_UNCHECKED then tmp:=tmp or frbkStretchY;
+ if IsDlgButtonchecked(Dialog,IDC_PROP )<>BST_UNCHECKED then tmp:=tmp or frbkProportional;
+
+ if tmp<>D.BkMode then
+ begin
+ D.BkMode:=tmp;
+ end;
+
+ // Hide frame option
+ tmpb :=IsDlgButtonChecked(Dialog,IDC_HIDEFRAMEPLAYER)<>BST_UNCHECKED;
+ if tmpb<>D.HideNoPlayer then
+ begin
+ D.HideNoPlayer:=tmpb;
+ end;
+ tmpb:=IsDlgButtonChecked(Dialog,IDC_HIDEFRAMEMUSIC)<>BST_UNCHECKED;
+ if tmpb<>D.HideNoMusic then
+ begin
+ D.HideNoMusic:=tmpb;
+ end;
+
+ // Padding
+ tmp:=GetDlgItemInt(Dialog,IDC_PADDING_LEFT,tmpb,false);
+ if integer(tmp)<>D.padding.left then
+ begin
+ D.padding.left:=tmp;
+ end;
+ tmp:=GetDlgItemInt(Dialog,IDC_PADDING_TOP,tmpb,false);
+ if integer(tmp)<>D.padding.top then
+ begin
+ D.padding.top:=tmp;
+ end;
+ tmp:=GetDlgItemInt(Dialog,IDC_PADDING_RIGHT,tmpb,false);
+ if integer(tmp)<>D.padding.right then
+ begin
+ D.padding.right:=tmp;
+ end;
+ tmp:=GetDlgItemInt(Dialog,IDC_PADDING_BOTTOM,tmpb,false);
+ if integer(tmp)<>D.padding.bottom then
+ begin
+ D.padding.bottom:=tmp;
+ end;
+
+ tmp:=GetDlgItemInt(Dialog,IDC_TIMER,tmpb,false);
+ if tmp>0 then
+ begin
+ if tmp<100 then
+ tmp:=tmp*1000;
+ if tmp<200 then
+ tmp:=200;
+ end;
+
+ if tmp<>D.UpdInterval then
+ begin
+ D.UpdInterval:=tmp;
+ end;
+
+ FrameCtrl.SaveSettings;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/kolframe/frm_dlg2.inc b/plugins/Watrack/kolframe/frm_dlg2.inc
new file mode 100644
index 0000000000..6325e05fcd
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_dlg2.inc
@@ -0,0 +1,172 @@
+{Frame text}
+const
+ MaxTxtScrollSpeed = 20;
+
+function FrameTextDlg(Dialog:HWnd; hMessage,wParam,lParam:DWord):integer; stdcall;
+const
+ DlgInited :boolean=false;
+ TemplateChanged:Boolean=false;
+var
+ tmp,tmp1:integer;
+ tmpb:longbool;
+ pcf:TCHOOSEFONT;
+ lf:LOGFONTW;
+begin
+ result:=0;
+
+ case hMessage of
+ WM_DESTROY: begin
+ // new - if Apply, old - if cancel
+ if FrameCtrl<>nil then // for case when FrameCtrl was destryed already
+ if PWATFrameData(FrameCtrl.CustomData).TextBlock<>nil then
+ PWATFrameData(FrameCtrl.CustomData).TextBlock.FontData:=TextLF;
+ end;
+
+ WM_INITDIALOG: begin
+ DlgInited:=false;
+ TranslateDialogDefault(Dialog);
+ with PWATFrameData(FrameCtrl.CustomData).TextBlock^ do
+ begin
+ case LoByte(Effects) of
+ effWrap: tmp:=IDC_EFF_WRAP;
+ effRoll: tmp:=IDC_EFF_ROLL;
+ effPong: tmp:=IDC_EFF_PONG;
+ else // like effCut
+ tmp:=IDC_EFF_CUT;
+ end;
+ CheckDlgButton(Dialog,tmp,BST_CHECKED);
+
+ SetDlgItemInt(Dialog,IDC_TIMER,UpdateTime,false);
+
+ SetDlgItemInt(Dialog,IDC_ROLLSTEP,RollStep,false);
+ SetDlgItemInt(Dialog,IDC_ROLLGAP ,RollGap ,false);
+ // SetDlgItemInt(Dialog,IDC_ROLLTAIL,RollTail,false);
+
+ CheckDlgButton(Dialog,IDC_ALCENTER,ord((Effects and effCenter)<>0));
+
+ SetDlgItemTextW(Dialog,IDC_FRAME_TEXT,PWATFrameData(FrameCtrl.CustomData).Template);
+ end;
+
+ SendDlgItemMessage(Dialog,IDC_MACRO_HELP,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_SKIN_LOADICON,SKINICON_OTHER_HELP,0));
+
+ TemplateChanged:=false;
+ DlgInited:=true;
+ end;
+
+ WM_COMMAND: begin
+ case (wParam shr 16) of
+ EN_CHANGE: begin
+ if Loword(wParam)=IDC_FRAME_TEXT then
+ TemplateChanged:=True;
+ end;
+
+ BN_CLICKED: begin
+ case LoWord(wParam) of
+ IDC_MACRO_HELP: CallService(MS_WAT_MACROHELP,Dialog,0);
+ IDC_FRMFONT: begin
+ with PWATFrameData(FrameCtrl.CustomData).TextBlock^ do
+ begin
+ lf:=FontData;
+ // lf:=TextLF;
+ FillChar(pcf,sizeOf(pcf),0);
+ with pcf do
+ begin
+ lStructSize:=SizeOf(pcf);
+ lpLogFont:=@lf;
+ Flags:=CF_EFFECTS+CF_FORCEFONTEXIST+CF_LIMITSIZE+CF_NOVERTFONTS+
+ CF_SCREENFONTS+CF_INITTOLOGFONTSTRUCT;
+ rgbColors:=TextColor;
+ nSizeMin:=6;
+ nSizeMax:=32;
+ end;
+ if ChooseFont(pcf) then
+ begin
+ FontData:=lf; // paint directly
+ TextColor:=pcf.rgbColors;
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end
+ else
+ exit;
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ if DlgInited then
+ case wParam shr 16 of
+ BN_CLICKED,
+ EN_CHANGE: begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ begin
+// redraw:=false;
+ with PWATFrameData(FrameCtrl.CustomData).TextBlock^ do
+ begin
+ tmp:=GetDlgItemInt(Dialog,IDC_TIMER,tmpb,false);
+ if tmp>MaxTxtScrollSpeed then
+ tmp:=MaxTxtScrollSpeed;
+
+ if tmp<>UpdateTime then
+ begin
+ UpdateTime:=tmp;
+{
+ if UpdTimer<>0 then
+ KillTimer(FrameWnd,UpdTimer);
+ if (UpdInterval>0) and (FrameWnd<>0) then
+ UpdTimer:=SetTimer(FrameWnd,TMR_TEXT,(MaxTxtScrollSpeed+1-UpdInterval)*100,nil)
+ else
+ UpdTimer:=0;
+}
+ end;
+
+ // Text effects
+ if IsDlgButtonChecked(Dialog,IDC_EFF_CUT )<>BST_UNCHECKED then tmp:=effCut
+ else if IsDlgButtonChecked(Dialog,IDC_EFF_WRAP)<>BST_UNCHECKED then tmp:=effWrap
+ else if IsDlgButtonChecked(Dialog,IDC_EFF_ROLL)<>BST_UNCHECKED then tmp:=effRoll
+ else if IsDlgButtonChecked(Dialog,IDC_EFF_PONG)<>BST_UNCHECKED then tmp:=effPong;
+ if IsDlgButtonChecked(Dialog,IDC_ALCENTER)<>BST_UNCHECKED then
+ tmp:=tmp or effCenter;
+ Effects:=tmp;
+
+ tmp1:=GetDlgItemInt(Dialog,IDC_ROLLSTEP,tmpb,false);
+ if tmp1<>RollStep then
+ begin
+ RollStep:=tmp1;
+ end;
+ tmp1:=GetDlgItemInt(Dialog,IDC_ROLLGAP ,tmpb,false);
+ if tmp1<>RollGap then
+ begin
+ RollGap:=tmp1;
+ end;
+ {
+ tmp1:=GetDlgItemInt(Dialog,IDC_ROLLTAIL,tmpb,false);
+ if tmp1<>RollTail then
+ begin
+ RollTail:=tmp1;
+ end;
+ }
+
+ if TemplateChanged then
+ begin
+ mFreeMem(PWATFrameData(FrameCtrl.CustomData).Template);
+ PWATFrameData(FrameCtrl.CustomData).Template:=GetDlgText(Dialog,IDC_FRAME_TEXT);
+ end;
+
+ TextLF:=FontData; // OK - saving for future?
+
+ SaveTextSettings(TemplateChanged);
+ TemplateChanged:=false;
+ end;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/kolframe/frm_frame.inc b/plugins/Watrack/kolframe/frm_frame.inc
new file mode 100644
index 0000000000..8c3034327c
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_frame.inc
@@ -0,0 +1,497 @@
+{Frame + background}
+
+const
+ WS_EX_LAYERED = $00080000;
+
+function SetLayeredWindowAttributes(Hwnd: THandle; crKey: COLORREF; bAlpha: Byte; dwFlags: DWORD): Boolean; stdcall;
+ external user32 name 'SetLayeredWindowAttributes';
+
+const
+ defFrameText = '%artist% - %title%';
+
+const
+// opt_HiddenByMe:PAnsiChar = 'frame/hiddenbyme';
+ opt_ShowCtrls :PAnsiChar = 'frame/showcontrols';
+ opt_FrmUsePic :PAnsiChar = 'frame/frmusepic';
+ opt_FrmUseCvr :PAnsiChar = 'frame/frmusecover';
+ opt_FrmBkColor:PAnsiChar = 'frame/frmbkcolor';
+ opt_FrmBkPic :PAnsiChar = 'frame/frmbkpic';
+ opt_FrmBkMode :PAnsiChar = 'frame/frmbkmode';
+ opt_FrmAlpha :PAnsiChar = 'frame/frmalpha';
+ opt_HideFrameM:PAnsiChar = 'frame/hideframem';
+ opt_HideFrameP:PAnsiChar = 'frame/hideframep';
+ opt_FrmTimer :PAnsiChar = 'frame/frametimer';
+ opt_PadLeft :PAnsiChar = 'frame/paddingleft';
+ opt_PadTop :PAnsiChar = 'frame/paddingtop';
+ opt_PadRight :PAnsiChar = 'frame/paddingright';
+ opt_PadBottom :PAnsiChar = 'frame/paddingbottom';
+ opt_Manual :PAnsiChar = 'frame/manualplacement';
+
+procedure TWATFrame.ResetFrame;
+var
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ if D.Trackbar <>nil then ResetTrackbar(D.Trackbar);
+ if D.TextBlock<>nil then D.TextBlock.BlockText:=nil;
+// frame back to default
+ RefreshPicture(nil);
+end;
+
+procedure FrameTimerProc(wnd:HWND;uMsg:uint;idEvent:uint_ptr;dwTime:dword); stdcall;
+var
+ psi:pSongInfo;
+ D:PWATFrameData;
+begin
+ D:=FrameCtrl.CustomData;
+
+ if IsFrameHidden(D.FrameId) then
+ begin
+ if not D.wasHidden then
+ begin
+ D.wasHidden:=true;
+ D.TextBlock.UpdateTime:=0;
+ end;
+ exit;
+ end
+ else if D.wasHidden and (D.TextBlock.UpdateTime=0) then
+ begin
+ D.wasHidden:=false;
+ if (D.ShowControls and scText)<>0 then
+ D.TextBlock.UpdateTime:=DBReadWord(0,PluginShort,opt_TxtTimer,10);
+ end;
+
+ if D.Trackbar<>nil then
+ begin
+ if (CallService(MS_WAT_GETMUSICINFO,WAT_INF_CHANGES,dword(@psi))<>WAT_PLS_NOTFOUND) then
+ begin
+ SetTrackBarPosition(D.Trackbar,(psi^.time*1000) div D.UpdInterval)
+ end;
+ end;
+
+ UpdateTextBlock(D,false); // false - check for %percent%/%time%
+
+ FrameCtrl.Update;
+end;
+
+procedure TWATFrame.AdjustFrame;
+var
+ h:integer;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+
+ if D.ManualPlacement then
+ begin
+ if D.Trackbar <>nil then D.Trackbar .Anchor(false,false,false,false);
+ if D.TextBlock<>nil then D.TextBlock.Anchor(false,false,false,false);
+ DesignerLoadSettings;
+ exit;
+ end;
+
+ h:=Height; // or need to get FRAME height
+
+ if D.Trackbar<>nil then
+ begin
+ D.Trackbar.SetSize(Width-16,18);
+ dec(h,D.Trackbar.Height);
+ D.Trackbar.SetPosition(8,h);
+ D.Trackbar.Anchor(true,false,true,true);
+ end;
+
+ if (D.ShowControls and scButtons)<>0 then
+ begin
+ AdjustButtons(h-16-BtnGap);
+ dec(h,16+2*BtnGap);
+ end;
+
+ if D.TextBlock<>nil then
+ begin
+ D.TextBlock.Top :=awkTextPad;
+ D.TextBlock.Height:=h-D.TextBlock.Top;
+ D.TextBlock.Anchor(true,true,true,true);
+ end;
+end;
+
+procedure TWATFrame.SaveSettings;
+var
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ DBWriteByte (0,PluginShort,opt_Manual ,ord(D.ManualPlacement));
+ DBWriteByte (0,PluginShort,opt_HideFrameM,ord(D.HideNoMusic));
+ DBWriteByte (0,PluginShort,opt_HideFrameP,ord(D.HideNoPlayer));
+ DBWriteByte (0,PluginShort,opt_FrmUsePic ,ord(D.UseBkPicture));
+ DBWriteByte (0,PluginShort,opt_FrmUseCvr ,ord(D.UseCover));
+ DBWriteDWord (0,PluginShort,opt_FrmBkColor,D.BkColor);
+ DBWriteWord (0,PluginShort,opt_FrmBkMode ,D.BkMode);
+ DBWriteDWord (0,PluginShort,opt_ShowCtrls ,D.ShowControls);
+ DBWriteByte (0,PluginShort,opt_FrmAlpha ,D.FrmAlpha);
+ DBWriteWord (0,PluginShort,opt_FrmTimer ,D.UpdInterval);
+ DBWriteWord (0,PluginShort,opt_PadLeft ,D.padding.left);
+ DBWriteWord (0,PluginShort,opt_PadTop ,D.padding.top);
+ DBWriteWord (0,PluginShort,opt_PadRight ,D.padding.right);
+ DBWriteWord (0,PluginShort,opt_PadBottom ,D.padding.bottom);
+ DBWriteString(0,PluginShort,opt_FrmBkPic ,D.BkDefFile);
+
+ CheckControls;
+ AdjustFrame;
+ RefreshPicture;
+ InvalidateRect(FrameCtrl.GetWindowHandle,nil,true);
+ FrameCtrl.Update;
+
+ if D.UpdTimer<>0 then // FrameWnd MUST be present
+ begin
+ KillTimer(0,D.UpdTimer);
+ D.UpdTimer:=0;
+ end;
+ if D.UpdInterval>0 then
+ begin
+ D.UpdTimer:=SetTimer(0,0,D.UpdInterval,@FrameTimerProc);
+ end;
+end;
+
+procedure TWATFrame.LoadSettings;
+var
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ D.ManualPlacement:=DBReadByte (0,PluginShort,opt_Manual ,0)<>0;
+ D.HideNoMusic :=DBReadByte (0,PluginShort,opt_HideFrameM,0)<>0;
+ D.HideNoPlayer :=DBReadByte (0,PluginShort,opt_HideFrameP,0)<>0;
+ D.UseBkPicture :=DBReadByte (0,PluginShort,opt_FrmUsePic ,0)<>0;
+ D.UseCover :=DBReadByte (0,PluginShort,opt_FrmUseCvr ,0)<>0;
+ D.BkColor :=DBReadDWord(0,PluginShort,opt_FrmBkColor,$00E0E0E0);
+ D.BkMode :=DBReadWord (0,PluginShort,opt_FrmBkMode ,frbkCenter);
+ D.ShowControls :=DBReadDWord(0,PluginShort,opt_ShowCtrls ,scAll);
+ D.FrmAlpha :=DBReadByte (0,PluginShort,opt_FrmAlpha ,255);
+
+ D.UpdInterval:=DBReadWord(0,PluginShort,opt_FrmTimer,200);
+ if D.UpdInterval<100 then
+ D.UpdInterval:=D.UpdInterval*1000;
+
+ D.padding.left :=DBReadWord(0,PluginShort,opt_PadLeft ,0);
+ D.padding.top :=DBReadWord(0,PluginShort,opt_PadTop ,0);
+ D.padding.right :=DBReadWord(0,PluginShort,opt_PadRight ,0);
+ D.padding.bottom:=DBReadWord(0,PluginShort,opt_PadBottom,0);
+
+ D.BkDefFile:=DBReadString(0,PluginShort,opt_FrmBkPic,nil);
+ //!!!! saving NOT in TextBlock
+ D.Template:=DBReadUnicode(0,PluginShort,opt_FrameText,DefFrameText);
+end;
+
+{$include i_bitmap.inc}
+
+procedure TWATFrame.SetAlpha(value:integer);
+const
+ LWA_COLORKEY = $00000001;
+ LWA_ALPHA = $00000002;
+var
+ wnd:HWND;
+ x:cardinal;
+begin
+ if IsFrameFloated(PWATFrameData(CustomData).FrameId) then
+ begin
+ wnd:=GetParent(FrameCtrl.GetWindowHandle);
+ x:=GetWindowLongW(wnd,GWL_EXSTYLE);
+ if value<>255 then
+ begin
+ if (x and WS_EX_LAYERED)=0 then
+ SetWindowLongW(wnd,GWL_EXSTYLE,x or WS_EX_LAYERED);
+ SetLayeredWindowAttributes(wnd,0,value,LWA_ALPHA);
+ end
+ else if (x and WS_EX_LAYERED)<>0 then
+ SetWindowLongW(wnd,GWL_EXSTYLE,x and not WS_EX_LAYERED);
+ end;
+end;
+
+procedure TWATFrame.FrameResize(Sender: PObj);
+var
+ tmpBmp:HBITMAP;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ if D.BkDC<>0 then
+ begin
+ tmpBmp:=GetCurrentObject(D.BkDC,OBJ_BITMAP);
+ DeleteDC(D.BkDC);
+ D.BkDC:=0;
+ DeleteObject(tmpBmp);
+ end;
+ AdjustFrame;
+end;
+
+procedure BkTimerProc(wnd:HWND;uMsg:uint;idEvent:uint_ptr;dwTime:dword); stdcall;
+var
+ D:PWATFrameData;
+begin
+ D:=FrameCtrl.CustomData;
+ KillTimer(0,D.BkTimer);
+ D.BkTimer:=0;
+ DeleteObject(D.BkBitmap);
+ D.BkBitmap:=0;
+end;
+
+procedure TWATFrame.RefreshPicture(cover:PAnsiChar=nil);
+var
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ if D.BkBitmap<>0 then
+ BkTimerProc(0,0,0,0); // remove old picture
+
+ FrameResize(nil); // clear frame bitmap buffer
+
+ if D.UseBkPicture then
+ D.BkBitmap:=LoadBkPicture(cover,true,D.BkDefFile);
+
+ if D.BkBitmap=HBITMAP(-1) then // same file
+ D.BkBitmap:=0;
+ Update;
+end;
+
+procedure TWATFrame.Paint(Sender: PControl; DC: HDC);
+var
+ rc: TRect;
+ br:HBRUSH;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ GetClientRect(Sender.Handle,rc);
+ if D.UseBkPicture then
+ begin
+ if D.BkDC=0 then
+ begin
+ if D.BkBitmap=0 then
+ begin
+ if (D.BkFile<>nil) and (D.BkFile^<>#0) then
+ D.BkBitmap:=CallService(MS_UTILS_LOADBITMAP,0,dword(D.BkFile));
+ end;
+
+ if D.BkBitmap<>0 then
+ begin
+ PreparePicture(dc,rc);
+ D.BkTimer:=SetTimer(0,0,10000,@BkTimerProc);
+ end;
+ end;
+ if D.BkDC<>0 then
+ begin
+ BitBlt(dc,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,
+ D.BkDC,rc.left,rc.top,SRCCOPY);
+ exit;
+ end;
+ end;
+
+ InflateRect(rc,1,1);
+ br:=CreateSolidBrush(D.BkColor);
+ FillRect(dc,rc,br);
+ DeleteObject(br);
+end;
+
+// JUST LOAD picture, no matter, which transforms
+// Backname = from settings, Covername = from data (higher priority)
+// -1 - same file, 0 - can't load, other - new bitmap
+function TWATFrame.LoadBkPicture(CoverFName:PAnsiChar;check:boolean=false;
+ BackFName:PAnsiChar=nil):integer;
+var
+ tmpstr:PAnsiChar;
+ D:PWATFrameData;
+begin
+ result:=0;
+ D:=CustomData;
+
+ // check the same file, ie only 'next pic'
+ if (CoverFName<>nil) and (CoverFName^<>#0) then
+ begin
+ if check and (StrCmp(CoverFName,D.BkFile)=0) then
+ begin
+ result:=-1;
+ Exit;
+ end;
+
+ result:=CallService(MS_UTILS_LOADBITMAP,0,dword(CoverFName));
+ if result<>0 then
+ begin
+ mFreeMem(D.BkFile);
+ StrDup(D.BkFile,CoverFName);
+ Exit;
+ end;
+ end;
+
+ if (BackFName<>nil) and (BackFName^<>#0) then
+ begin
+ tmpstr:=ParseVarString(BackFName);
+ if (tmpstr<>nil) and (tmpstr^<>#0) then
+ begin
+ if (not check) or (StrCmp(tmpstr,D.BkFile)<>0) then
+ begin
+ result:=CallService(MS_UTILS_LOADBITMAP,0,dword(tmpstr));
+ if result<>0 then
+ begin
+ mFreeMem(D.BkFile);
+ StrDup(D.BkFile,tmpstr);
+ end;
+ end
+ else
+ result:=-1;
+ end;
+ mFreeMem(tmpstr);
+ end;
+end;
+
+procedure TWATFrame.ClearBitmapData;
+var
+ D:PWATFrameData;
+ tmpBmp:HBITMAP;
+begin
+ D:=CustomData;
+
+ if D.BkTimer<>0 then
+ begin
+ KillTimer(0,D.BkTimer);
+ D.BkTimer:=0;
+ end;
+ if D.BkDC<>0 then
+ begin
+ tmpBmp:=GetCurrentObject(D.BkDC,OBJ_BITMAP);
+ DeleteDC(D.BkDC);
+ D.BkDC:=0;
+ DeleteObject(tmpBmp);
+ end;
+ if D.BkBitmap<>0 then
+ begin
+ DeleteObject(D.BkBitmap);
+ D.BkBitmap:=0;
+ end;
+ mFreeMem(D.BkFile);
+end;
+
+procedure TWATFrame.MyDestroy(sender:PObj);
+var
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ if D.UpdTimer<>0 then
+ begin
+ KillTimer(0,D.UpdTimer);
+ D.UpdTimer:=0;
+ end;
+
+ mFreeMem(D.Template);
+ mFreeMem(D.BkDefFile);
+ ClearBitmapData;
+
+ if D.Designer<>nil then
+ begin
+ D.Designer.Free;
+ D.Designer:=nil;
+ end;
+
+end;
+
+procedure TWATFrame.RefreshAllFrameIcons;
+var
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ if (D.ShowControls and scButtons)<>0 then RefreshButtonIcons;
+ if D.Trackbar<>nil then RefreshTrackbarIcons(D.Trackbar);
+end;
+
+procedure TWATFrame.CheckControls;
+var
+ D:PWATFrameData;
+ psi:pSongInfo;
+begin
+ D:=CustomData;
+
+ if (D.ShowControls and scTrackBar)<>0 then
+ begin
+ if D.Trackbar=nil then
+ begin
+ RegisterButtonIcons;
+ D.Trackbar:=MakeNewTrackbar(@self);
+ // for case when TB creating after track start (fastest way)
+ // can use (CallService(MS_WAT_GETMUSICINFO,WAT_INF_CHANGES,dword(@psi))<>WAT_PLS_NOTFOUND)
+ psi:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UNICODE,1));
+ TrackbarSetRange(D.Trackbar,D.UpdInterval,psi^.total);
+ end;
+ end
+ else if D.Trackbar<>nil then
+ begin
+ D.Trackbar.Free;
+ D.Trackbar:=nil;
+ end;
+
+ if (D.ShowControls and scButtons)<>0 then
+ begin
+ if D.btnarray[0]=nil then
+ begin
+ if RegisterButtonIcons then
+ MakeNewButtonGroup;
+ end
+ end
+ else if D.btnarray[0]<>nil then
+ FreeButtons;
+{
+ if (D.ShowControls and scText)<>0 then
+ begin
+}
+ if D.TextBlock=nil then
+ begin
+ D.TextBlock:=MakeTextBlock(@self,D.BkColor);
+ end;
+
+ if (D.ShowControls and scText)<>0 then
+ D.TextBlock.UpdateTime:=DBReadWord(0,PluginShort,opt_TxtTimer,10);
+{
+ end
+ else if D.TextBlock<>nil then
+ begin
+ D.TextBlock.Free;
+ D.TextBlock:=nil;
+ end;
+}
+ if D.UseBkPicture then
+ begin
+ D.BkBitmap:=LoadBkPicture(nil,true,D.BkDefFile);
+ if D.BkBitmap=HBITMAP(-1) then
+ D.BkBitmap:=0;
+ end
+ else
+ ClearBitmapData;
+end;
+
+function CreateFrameWindow(parent:HWND):THANDLE;
+var
+ D:PWATFrameData;
+begin
+ result:=0;
+
+ FrameCtrl:=PWATFrame(NewAlienPanel(parent,esNone));
+ if FrameCtrl<>nil then
+ begin
+ GetMem (D ,SizeOf(TWATFrameData));
+ FillChar(D^,SizeOf(TWATFrameData),0); // clear all including buttons
+ with FrameCtrl^ do
+ begin
+ CustomData:=D;
+ LoadSettings;
+
+ result:=GetWindowHandle;
+
+ CheckControls;
+
+ MinWidth :=80;
+ MinHeight:=30;
+
+ OnPaint :=FrameCtrl.Paint;
+ OnResize :=FrameCtrl.FrameResize;
+// OnMouseDown :=TOnMouse(MakeMethod(nil, @MouseDown));
+ OnMouseDblClk:=FrameCtrl.CreateDesigner;
+ end;
+ FrameCtrl.OnDestroy:=FrameCtrl.MyDestroy;
+// theoretically, must get Resize here.... or after
+// FrameCtrl.AdjustFrame;
+ end;
+end;
diff --git a/plugins/Watrack/kolframe/frm_icogroup.inc b/plugins/Watrack/kolframe/frm_icogroup.inc
new file mode 100644
index 0000000000..2b6e9de6f9
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_icogroup.inc
@@ -0,0 +1,115 @@
+{Panel = group of icons}
+
+procedure TWATFrame.AdjustButtons(atop:integer);
+var
+ i,lWidth,lOffs,gap:integer;
+ lleft:integer;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+
+ if D.btnarray[0]=nil then exit;
+
+ if (D.ShowControls and scGap)<>0 then
+ gap:=BtnGap
+ else
+ gap:=0;
+
+ D.btnarray[0].Visible:=(D.ShowControls and scVolume)<>0;
+ D.btnarray[1].Visible:=(D.ShowControls and scVolume)<>0;
+
+ lWidth:=(Length(D.btnarray)-2)*(16+gap)-gap;
+ if (D.ShowControls and scVolume)<>0 then
+ Inc(lWidth, VolBtnDist+2*(16+gap));
+ lLeft:=(Width-lWidth) div 2;
+
+ lOffs:=0;
+ if (D.ShowControls and scVolume)<>0 then
+ begin
+ D.btnarray[0].Left:=lleft+lOffs;
+ D.btnarray[0].Top :=atop;
+ Inc(lOffs,16+gap);
+ D.btnarray[1].Left:=lleft+lOffs;
+ D.btnarray[1].Top :=atop;
+ Inc(lOffs,16+gap+VolBtnDist);
+ end;
+
+ for i:=2 to HIGH(D.btnarray) do
+ begin
+ D.btnarray[i].Left:=lleft+lOffs;
+ D.btnarray[i].Top :=atop;
+ Inc(lOffs,16+gap);
+ end;
+
+end;
+
+procedure TWATFrame.RefreshButtonIcons;
+var
+ i:integer;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+
+ if D.btnarray[0]<>nil then exit;
+
+ for i:=0 to HIGH(D.btnarray) do
+ D.btnarray[i].RefreshIcon;
+end;
+
+procedure TWATFrame.FreeButtonsDesigner;
+var
+ i:integer;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+
+ if D.btnarray[0]<>nil then exit;
+
+ for i:=0 to HIGH(D.btnarray) do
+ D.Designer.Disconnect(D.btnarray[i]);
+end;
+
+procedure TWATFrame.MakeButtonsDesigner;
+var
+ i:integer;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+
+ if D.btnarray[0]<>nil then exit;
+
+ for i:=0 to HIGH(D.btnarray) do
+ D.Designer.Connect('Button',D.btnarray[i],DESIGNER_NORESIZE);
+end;
+
+procedure TWATFrame.FreeButtons;
+var
+ i:integer;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+
+ if D.btnarray[0]<>nil then exit;
+
+ for i:=0 to HIGH(D.btnarray) do
+ begin
+ D.btnarray[i].Free;
+ D.btnarray[i]:=nil;
+ end;
+end;
+
+procedure TWATFrame.MakeNewButtonGroup;
+var
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+
+ D.btnarray[0]:=CreateIcoButton(@self,waticons.GetIcon,DoAction,WAT_CTRL_VOLDN,300);
+ D.btnarray[1]:=CreateIcoButton(@self,waticons.GetIcon,DoAction,WAT_CTRL_VOLUP,300);
+ D.btnarray[2]:=CreateIcoButton(@self,waticons.GetIcon,DoAction,WAT_CTRL_PREV,2000);
+ D.btnarray[3]:=CreateIcoButton(@self,waticons.GetIcon,DoAction,WAT_CTRL_PLAY);
+ D.btnarray[4]:=CreateIcoButton(@self,waticons.GetIcon,DoAction,WAT_CTRL_PAUSE);
+ D.btnarray[5]:=CreateIcoButton(@self,waticons.GetIcon,DoAction,WAT_CTRL_STOP);
+ D.btnarray[6]:=CreateIcoButton(@self,waticons.GetIcon,DoAction,WAT_CTRL_NEXT,2000);
+end;
+
diff --git a/plugins/Watrack/kolframe/frm_rc.inc b/plugins/Watrack/kolframe/frm_rc.inc
new file mode 100644
index 0000000000..25ac437b3b
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_rc.inc
@@ -0,0 +1,56 @@
+{DLG 5 - frame}
+const
+ IDC_HELP_FORMAT = 1025;
+ IDC_HELP_COLOR = 1026;
+ IDC_HELP_VARIABLES = 1027;
+const
+ IDC_TIMER = 1028;
+ IDC_SHOWCTRLS = 1032;
+ IDC_SHOWTEXT = 1033;
+ IDC_SHOWVOLUM = 1034;
+ IDC_FRMCOLOR = 1036;
+ IDC_FRMUSEPIC = 1037;
+ IDC_FRMBKPIC = 1038;
+ IDC_FRMPICBTN = 1039;
+ IDC_CENTERX = 1040;
+ IDC_CENTERY = 1041;
+ IDC_TILEX = 1042;
+ IDC_TILEY = 1043;
+ IDC_STRETCHX = 1044;
+ IDC_STRETCHY = 1045;
+ IDC_PROP = 1046;
+ IDC_BOTTOM = 1047;
+ IDC_RIGHT = 1048;
+ IDC_FRMALPHA = 1049;
+ IDC_TRACKBAR = 1050;
+ IDC_BTNGAP = 1051;
+ IDC_SHOWBAR = 1052;
+ IDC_USECOVER = 1053;
+
+ IDC_HIDEFRAMEMUSIC = 1054;
+ IDC_HIDEFRAMEPLAYER = 1055;
+
+ IDC_PADDING_LEFT = 1056;
+ IDC_PADDING_TOP = 1057;
+ IDC_PADDING_RIGHT = 1058;
+ IDC_PADDING_BOTTOM = 1059;
+
+ IDC_MANUALPLACE = 1060;
+
+{DLG 51 - frame 2}
+ IDC_FRMTXT = 1031;
+ IDC_EFF_CUT = 1032;
+ IDC_EFF_WRAP = 1033;
+ IDC_EFF_ROLL = 1034;
+ IDC_EFF_PONG = 1035;
+ IDC_ROLLSTEP = 1036;
+ IDC_ROLLGAP = 1037;
+// IDC_ROLLTAIL = 1038;
+ IDC_ALCENTER = 1039;
+ IDC_FRMFONT = 1040;
+
+ IDC_FRAME_TEXT = 1041;
+ IDC_MACRO_HELP = 1042;
+
+{Frame}
+ IDC_FRM_POS = 1032;
diff --git a/plugins/Watrack/kolframe/frm_text.inc b/plugins/Watrack/kolframe/frm_text.inc
new file mode 100644
index 0000000000..66c00a1b2b
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_text.inc
@@ -0,0 +1,90 @@
+{Text}
+
+const
+ TextLF:TLOGFONTW = (
+ lfHeight :-10;
+ lfWidth :0;
+ lfEscapement :0;
+ lfOrientation :0;
+ lfWeight :FW_DONTCARE;
+ lfItalic :0;
+ lfUnderline :0;
+ lfStrikeOut :0;
+ lfCharSet :DEFAULT_CHARSET;
+ lfOutPrecision :OUT_DEFAULT_PRECIS;
+ lfClipPrecision :CLIP_DEFAULT_PRECIS;
+ lfQuality :DEFAULT_QUALITY;
+ lfPitchAndFamily:DEFAULT_PITCH or FF_DONTCARE{;
+ lfFaceName :#0});
+
+const
+ opt_FrmTxtClr :PAnsiChar = 'frame/frametextcolor';
+ opt_FrmFont :PAnsiChar = 'frame/framefont';
+ opt_FrmEffect :PAnsiChar = 'frame/txteffect';
+ opt_RollStep :PAnsiChar = 'frame/rollstep';
+ opt_RollGap :PAnsiChar = 'frame/rollgap';
+// opt_RollTail :PAnsiChar = 'frame/rolltail';
+ opt_AlgnCenter:PAnsiChar = 'frame/aligncenter';
+ opt_TxtTimer :PAnsiChar = 'frame/texttimer';
+ opt_FrameText :PAnsiChar = 'frame/frametext';
+
+procedure UpdateTextBlock(D:PWATFrameData;force:boolean);
+var
+ tmp:pWideChar;
+begin
+ if (D.ShowControls and scText)=0 then exit;
+ if D.TextBlock=nil then exit;
+
+ if not force then
+ begin
+ if (StrPosW(D.Template,'%percent%')=nil) and
+ (StrPosW(D.Template,'%time%' )=nil) then // need to |remake
+ exit;
+ end;
+ tmp:=pWideChar(CallService(MS_WAT_REPLACETEXT,0,dword(D.Template)));
+ D.TextBlock.BlockText:=tmp;
+ mFreeMem(tmp);
+end;
+
+procedure SaveTextSettings(withtemplate:boolean);
+var
+ D:PWATFrameData;
+begin
+ D:=FrameCtrl.CustomData;
+ if D.TextBlock=nil then exit;
+
+// DBWriteByte (0,PluginShort,opt_RollTail ,RollTail);
+ DBWriteDWord(0,PluginShort,opt_FrmTxtClr,D.TextBlock.TextColor); // reaction on chunk?
+ DBWriteByte (0,PluginShort,opt_RollStep ,D.TextBlock.RollStep);
+ DBWriteByte (0,PluginShort,opt_RollGap ,D.TextBlock.RollGap);
+ DBWriteWord (0,PluginShort,opt_FrmEffect,D.TextBlock.Effects);
+ DBWriteWord (0,PluginShort,opt_TxtTimer ,D.TextBlock.UpdateTime);
+
+ DBWriteStruct(0,PluginShort,opt_FrmFont,@TextLF,SizeOf(TLOGFONT));
+
+ if withtemplate then
+ begin
+ DBWriteUnicode(0,PluginShort,opt_FrameText,D.Template);
+ UpdateTextBlock(D,true);
+ end;
+end;
+
+procedure LoadTextSettings(TB:pTextBlock);
+begin
+ if TB=nil then exit;
+// RollTail :=DBReadByte (0,PluginShort,opt_RollTail ,20);
+ TB.RollStep :=DBReadByte (0,PluginShort,opt_RollStep ,2);
+ TB.RollGap :=DBReadByte (0,PluginShort,opt_RollGap ,16);
+ TB.TextColor :=DBReadDWord(0,PluginShort,opt_FrmTxtClr,0);
+ TB.Effects :=DBReadWord (0,PluginShort,opt_FrmEffect,effCut or effCenter);
+ DBReadStruct(0,PluginShort,opt_FrmFont,@TextLF,SizeOf(TextLF));
+ TB.FontData :=TextLF;
+ TB.UpdateTime:=DBReadWord (0,PluginShort,opt_TxtTimer ,10);
+end;
+
+function MakeTextBlock(AOwner:PControl;BkColor:TCOLORREF):pTextBlock;
+begin
+ result:=MakeNewTextBlock(AOwner,BkColor);
+// result.OnMouseDown:=TOnMouse(MakeMethod(nil, @MouseDown));
+ LoadTextSettings(result);
+end;
diff --git a/plugins/Watrack/kolframe/frm_trackbar.inc b/plugins/Watrack/kolframe/frm_trackbar.inc
new file mode 100644
index 0000000000..d6e08c56a7
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_trackbar.inc
@@ -0,0 +1,229 @@
+{Trackbar}
+type
+ pAWKTrackbar = ^tAWKTrackbar;
+ tAWKTrackbar = object(TObj)
+ total:integer;
+ UpdInterval:integer;
+ OldMouseDown,
+ OldMouseUp:TOnMouse;
+
+ procedure CtrlResize(Sender: PObj);
+ procedure Erase(Sender: PControl; DC: HDC);
+ procedure Paint(Sender: PControl; DC: HDC);
+ procedure Scroll(Sender:PTrackbar; Code:Integer);
+ procedure PressButton (Sender: PControl;var Mouse: TMouseEventData);
+ procedure UnPressButton(Sender: PControl;var Mouse: TMouseEventData);
+ procedure DragButton (Sender: PControl;var Mouse: TMouseEventData);
+ end;
+
+procedure ResetTrackbar(Trackbar:PControl);
+begin
+ if Trackbar=nil then exit;
+
+ with pTrackbar(Trackbar)^ do
+ begin
+ RangeMin:=0;
+ RangeMax:=0;
+ Position:=0;
+ end;
+end;
+
+procedure TrackbarSetRange(Trackbar:PTrackbar;timer:integer;total:integer=-1);
+var
+ D:pAWKTrackbar;
+ lpercent:real;
+begin
+ if Trackbar=nil then exit;
+
+ with Trackbar^ do
+ begin
+ D:=pointer(CustomObj);
+ if total<0 then // changing timer only
+ begin
+ total:=D.total;
+ if RangeMax>0 then
+ lpercent:=position/RangeMax
+ else
+ lpercent:=0;
+ end
+ else // for new track
+ begin
+ D.total:=total;
+ lpercent:=0;
+ end;
+ D.UpdInterval:=timer;
+ total:=(total*1000) div timer;
+ RangeMax:=total;
+ LineSize:=total div 100;
+ PageSize:=total div 10;
+ Position:=round(lpercent*total);
+ end;
+end;
+
+procedure SetTrackbarPosition(Trackbar:PTrackbar;pos:integer);
+begin
+ if Trackbar=nil then exit;
+//?? if Sender.ChildCount=0 then exit;
+ if pIcoButton(Trackbar.Children[0]).State<>AST_PRESSED then
+ Trackbar.Position:=pos;
+
+ Trackbar.Update;
+end;
+
+function CoordToPos(Trackbar:PTrackbar;x:integer):integer;
+var
+ range:integer;
+ rmin,rmax:integer;
+ offsetthumb,width:integer;
+ rc:TRect;
+begin
+ result:=0;
+ if Trackbar=nil then exit;
+
+ rmin:=Trackbar.RangeMin;
+ rmax:=Trackbar.RangeMax;
+ range:=rmax-rmin; // logic width
+
+ offsetthumb:=Trackbar.ThumbLen div 2;
+
+ rc:=Trackbar.ChannelRect;
+ width:= (rc.right-rc.left)-(offsetthumb*2)-1;
+ result:=(range*(x-rc.left-offsetthumb)) div width;
+
+ inc(result,rmin);
+ if result>rmax then
+ result:=rmax
+ else if result<rmin then
+ result:=rmin;
+end;
+
+procedure tAWKTrackbar.PressButton(Sender: PControl;var Mouse: TMouseEventData);
+begin
+ pAWKTrackbar(Sender.Parent.CustomObj).OldMouseDown(Sender,Mouse);
+
+ pIcoButton(Sender)^.Action:=PTrackbar(Sender.Parent).Position;
+end;
+
+procedure tAWKTrackbar.UnPressButton(Sender: PControl;var Mouse: TMouseEventData);
+begin
+ pAWKTrackbar(Sender.Parent.CustomObj).OldMouseUp(Sender,Mouse);
+
+ CallService(MS_WAT_PRESSBUTTON,WAT_CTRL_SEEK,
+ pIcoButton(Sender)^.Action*pAWKTrackbar(Sender.Parent.CustomObj).UpdInterval div 1000);
+ pIcoButton(Sender)^.Action:=-1;
+end;
+
+procedure tAWKTrackbar.DragButton(Sender: PControl;var Mouse: TMouseEventData);
+var
+ pos:integer;
+begin
+ with pIcoButton(Sender)^ do
+ if State=AST_PRESSED then
+ begin
+ pos:=CoordToPos(PTrackbar(Sender.Parent),Sender.Left+Mouse.X);
+ if Action<>pos then
+ begin
+ Action:=pos;
+ PTrackbar(Sender.Parent).Position:=pos;
+ end;
+ end;
+end;
+
+procedure tAWKTrackbar.Scroll(Sender:PTrackbar; Code:Integer);
+begin
+ if code=TB_ENDTRACK then
+ begin
+ CallService(MS_WAT_PRESSBUTTON,WAT_CTRL_SEEK,
+ Sender.Position*pAWKTrackbar(Sender.CustomObj).UpdInterval div 1000);
+ end;
+end;
+
+procedure tAWKTrackbar.CtrlResize(Sender: PObj);
+var
+ tmp:integer;
+begin
+ tmp:=PControl(Sender).Parent.Width-16;
+ if (PTrackbar(Sender)^.Width)>tmp then
+ PTrackbar(Sender)^.Width:=tmp;
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ // need to move slider here
+// PControl(Sender).Update;
+end;
+
+procedure tAWKTrackbar.Erase(Sender: PControl; DC: HDC);
+begin
+// Sender.Parent.Update;
+end;
+
+procedure tAWKTrackbar.Paint(Sender: PControl; DC: HDC);
+var
+ rc, rc1:TRECT;
+ w:integer;
+begin
+ SendMessage(Sender.Handle,TBM_GETTHUMBRECT,0,dword(@rc));
+
+ w:=rc.right-rc.left;
+ if w<>16 then
+ rc.left:=rc.left+(w div 2)-8;
+
+ copyRect(rc1,Sender.BoundsRect);
+ rc1.Right :=rc1.Right-rc1.Left-8;
+ rc1.Left :=4;
+ rc1.Top :=7{((rc1.Bottom-rc1.Top) div 2)-2};
+ rc1.Bottom:=rc1.Top+4;
+ DrawEdge(DC,rc1,EDGE_SUNKEN,BF_RECT or BF_ADJUST);
+ if Sender.ChildCount>0 then
+ Sender.Children[0].Left:=rc.Left
+ else
+ begin
+ rc.right:=rc.left+8;
+ DrawFrameControl(DC,rc,DFC_BUTTON,DFCS_BUTTONPUSH);
+ end;
+end;
+
+procedure RefreshTrackbarIcons(Owner:PControl);
+begin
+ if Owner.ChildCount>0 then
+ pIcoButton(Owner.Children[0]).RefreshIcon;
+end;
+
+function MakeNewTrackBar(AOwner:PControl):PTrackbar;
+var
+ D:pAWKTrackbar;
+ btn:pIcoButton;
+begin
+ New(D, Create);
+ result:=NewTrackbar(AOwner,[trbNoTicks,trbBoth,trbNoBorder],D.Scroll);
+
+ with result^ do
+ begin
+ Transparent:=true;
+ CustomObj:=D;
+ SetSize(AOwner.Width-16,18);
+ SetPosition({AOwner.Left+}8,{AOwner.Top+}AOwner.Height-18);
+ Anchor(true,false,true,true);
+ ThumbLen:=16;
+
+ RangeMin:=0;
+ RangeMax:=100;
+
+ btn:=CreateIcoButton(result,GetIcon,DoAction,WAT_CTRL_SEEK);
+
+ if btn<>nil then
+ begin
+ btn.ResetEvent(idx_fOnClick);
+ D.OldMouseDown:=btn.OnMouseDown;
+ btn.OnMouseDown:=D.PressButton;
+ D.OldMouseUp:=btn.OnMouseUp;
+ btn.OnMouseUp :=D.UnPressButton;
+ btn.OnMouseMove:=D.DragButton;
+ end;
+
+ OnResize :=D.CtrlResize;
+ OnEraseBkGnd:=D.Erase;
+ OnPaint :=D.Paint;
+
+// OnScroll :=D.Scroll;
+ end;
+
+end;
diff --git a/plugins/Watrack/kolframe/frm_vars.inc b/plugins/Watrack/kolframe/frm_vars.inc
new file mode 100644
index 0000000000..88dd71f0d1
--- /dev/null
+++ b/plugins/Watrack/kolframe/frm_vars.inc
@@ -0,0 +1,80 @@
+{Frame variables}
+var
+ sic,
+ PlStatusHook:cardinal;
+
+ HiddenByMe:bool;
+
+ FrameHeight:dword;
+
+type
+ PWATFrameData = ^TWATFrameData;
+ TWATFrameData = record
+ BkDC :HDC; // "buffer" DC and associated bitmap
+ BkBitmap :HBITMAP; // original bitmap
+ BkFile :PAnsiChar; // original bitmap filename
+ BkDefFile :PAnsiChar; // default background picture filename
+ BkMode :cardinal;
+ BkTimer :cardinal; // timer to free original picture buffer
+ BkColor :TCOLORREF;
+ padding :TRect;
+
+ ShowControls:dword;
+ UseBkPicture:bool;
+ UseCover :bool;
+ HideNoMusic :bool;
+ HideNoPlayer:bool;
+
+ WasHidden :bool;
+ // not sure what will keep here
+ FrameId :integer;
+ FrmAlpha :integer;
+ UpdInterval :cardinal;
+ UpdTimer :cardinal;
+
+ Template :PWideChar;
+
+ Trackbar :PTrackbar;
+ TextBlock:PTextBlock;
+
+ // Designer section
+ Designer :PDesigner;
+ ManualPlacement:bool;
+ Loaded :dword;
+
+ btnarray:array [0..numbuttons-1] of pIcoButton;
+ end;
+
+ PWATFrame = ^TWATFrame;
+ TWATFrame = object(TControl)
+ procedure Paint(Sender: PControl; DC: HDC);
+ procedure FrameResize(Sender: PObj);
+ procedure RefreshAllFrameIcons;
+ procedure ResetFrame;
+
+ procedure CreateDesigner(Sender:PControl;var Mouse:TMouseEventData);
+ procedure DesignerSaveSettings;
+ procedure DesignerLoadSettings;
+
+ procedure PreparePicture(dc:HDC;rc:TRECT);
+ function LoadBkPicture(CoverFName:PAnsiChar;check:boolean=false;
+ BackFName:PAnsiChar=nil):integer;
+ procedure SaveSettings;
+ procedure LoadSettings;
+ procedure CheckControls;
+ procedure SetAlpha(value:integer);
+ procedure RefreshPicture(cover:PAnsiChar=nil);
+ procedure ClearBitmapData;
+ procedure AdjustFrame;
+ procedure MyDestroy(Sender:PObj);
+
+ procedure AdjustButtons(atop:integer);
+ procedure RefreshButtonIcons;
+ procedure FreeButtonsDesigner;
+ procedure MakeButtonsDesigner;
+ procedure FreeButtons;
+ procedure MakeNewButtonGroup;
+ end;
+
+var
+ FrameCtrl:PWATFrame;
diff --git a/plugins/Watrack/kolframe/i_bitmap.inc b/plugins/Watrack/kolframe/i_bitmap.inc
new file mode 100644
index 0000000000..bee15fdda7
--- /dev/null
+++ b/plugins/Watrack/kolframe/i_bitmap.inc
@@ -0,0 +1,290 @@
+{}
+procedure CalcRect(var src,dst:TRECT;mode:dword);
+var
+ dh, dw:integer;
+begin
+ if (Mode and frbkStretch)=frbkStretch then
+ begin
+ if (Mode and frbkProportional)<>0 then
+ begin
+ if (dst.right*src.bottom)>(src.right*dst.bottom) then
+ begin
+ dh:=dst.bottom;
+ dw:=dh*src.right div src.bottom
+ end
+ else
+ begin
+ dw:=dst.right;
+ dh:=dw*src.bottom div src.right;
+ end;
+ end
+ else
+ begin
+ dw:=dst.right;
+ dh:=dst.bottom;
+ end;
+ end
+ else if (Mode and frbkStretchX)<>0 then
+ begin
+ dw:=dst.right;
+ if (Mode and frbkProportional)<>0 then
+ dh:=dw*src.bottom div src.right
+ else
+ dh:=src.bottom;
+ end
+ else if (Mode and frbkStretchY)<>0 then
+ begin
+ dh:=dst.bottom;
+ if (Mode and frbkProportional)<>0 then
+ dw:=dh*src.right div src.bottom
+ else
+ dw:=src.right;
+ end
+ else
+ begin
+ dw:=src.right;
+ dh:=src.bottom;
+ end;
+
+ if (Mode and frbkBottom)<>0 then
+ begin
+ if dh<=dst.bottom then
+ begin
+ dst.top:=(dst.bottom-dh);
+ end
+ else
+ begin
+ src.top:=(dh-dst.bottom);
+ dh:=dst.bottom;
+ src.bottom:=src.top+dh;
+ end;
+ end;
+
+ if (Mode and frbkRight)<>0 then
+ begin
+ if dw<=dst.right then
+ begin
+ dst.left:=(dst.right-dw);
+ end
+ else
+ begin
+ src.left:=(dw-dst.right);
+ dw:=dst.right;
+ src.right:=src.left+dw;
+ end;
+ end;
+
+ if (Mode and frbkCenterX)<>0 then
+ begin
+ if dw<=dst.right then
+ begin
+ dst.left:=(dst.right-dw) div 2;
+ end
+ else
+ begin
+ src.left:=(dw-dst.right) div 2;
+ dw:=dst.right;
+ src.right:=src.left+dw;
+ end;
+ end;
+
+ if (Mode and frbkCenterY)<>0 then
+ begin
+ if dh<=dst.bottom then
+ begin
+ dst.top:=(dst.bottom-dh) div 2;
+ end
+ else
+ begin
+ src.top:=(dh-dst.bottom) div 2;
+ dh:=dst.bottom;
+ src.bottom:=src.top+dh;
+ end;
+ end;
+ dst.right:=dst.left+dw;
+ dst.bottom:=dst.top+dh;
+end;
+
+function CreateDIB32(dc:HDC;w,h:integer):HBITMAP;
+var
+ pt:pointer;
+ bi:TBITMAPINFO;
+begin
+ FillChar(bi,SizeOf(TBITMAPINFO),0);
+ bi.bmiHeader.biSize :=SizeOf(TBITMAPINFOHEADER);
+ bi.bmiHeader.biWidth :=w;
+ bi.bmiHeader.biHeight :=h;
+ bi.bmiHeader.biPlanes :=1;
+ bi.bmiHeader.biBitCount:=32;
+ result:=CreateDIBSection(dc,bi,DIB_RGB_COLORS,pt,0,0);
+end;
+
+procedure PreMultiplyChanells(hbmp:HBITMAP);
+type
+ tPixel=array [0..3] of Byte;
+var
+ bmp:windows.TBITMAP;
+ flag:bool;
+ pBitmapBits:PByte;
+ Len:dword;
+ bh,bw,y,x,z:integer;
+ pPixel:^tPixel;
+ alpha:dword;
+//f:THANDLE;
+begin
+ GetObject(hbmp,SizeOf(bmp),@bmp);
+ bh:=bmp.bmHeight;
+ bw:=bmp.bmWidth;
+ z:=bw*4;
+ Len:=bh*z;
+
+ mGetMem(pBitmapBits,Len);
+ GetBitmapBits(hbmp,Len,pBitmapBits);
+ flag:=true;
+ for y:=0 to bh-1 do
+ begin
+ pointer(pPixel):=PAnsiChar(pBitmapBits)+z*y;
+
+ for x:=0 to bw-1 do
+ begin
+ if pPixel^[3]<>0 then
+ flag:=false
+ else
+ pPixel^[3]:=255;
+ inc(pByte(pPixel),4);
+ end
+ end;
+
+ if not flag then
+ begin
+ GetBitmapBits(hbmp,Len,pBitmapBits); // alpha not changed
+ for y:=0 to bh-1 do
+ begin
+ pointer(pPixel):=PAnsiChar(pBitmapBits)+z*y;
+
+ for x:=0 to bw-1 do
+ begin
+ alpha:=pPixel^[3];
+ if alpha<255 then
+ begin
+ pPixel^[0]:=dword(pPixel^[0])*alpha div 255;
+ pPixel^[1]:=dword(pPixel^[1])*alpha div 255;
+ pPixel^[2]:=dword(pPixel^[2])*alpha div 255;
+ end;
+ inc(pByte(pPixel),4);
+ end
+ end;
+ end;
+ SetBitmapBits(hbmp,Len,pBitmapBits);
+ mFreeMem(pBitmapBits);
+end;
+
+function FixBitmap(dc:HDC;var hBmp:HBITMAP):HBITMAP;
+var
+ dc24,dc32:HDC;
+ hBitmap32,obmp24,obmp32:HBITMAP;
+ bmpInfo:windows.TBITMAP;
+begin
+ GetObject(hBmp,SizeOf(bmpInfo),@bmpInfo);
+ if bmpInfo.bmBitsPixel<>32 then
+ begin
+ dc32:=CreateCompatibleDC(dc);
+ dc24:=CreateCompatibleDC(dc);
+ hBitmap32:=CreateDIB32(dc,bmpInfo.bmWidth,bmpInfo.bmHeight);
+ obmp24:=SelectObject(dc24,hBmp);
+ obmp32:=SelectObject(dc32,hBitmap32);
+ BitBlt(dc32,0,0,bmpInfo.bmWidth,bmpInfo.bmHeight,dc24,0,0,SRCCOPY);
+ DeleteObject(SelectObject(dc24,obmp24));
+ SelectObject(dc32,obmp32);
+ DeleteDC(dc24);
+ DeleteDC(dc32);
+ hBmp:=hBitmap32;
+ end;
+ PreMultiplyChanells(hBmp);
+ result:=hBmp;
+end;
+
+procedure TWATFrame.PreparePicture(dc:HDC;rc:TRECT);
+var
+ bmpinfo:windows.TBITMAP;
+ src,dst:TRECT;
+ x,y,w,h,dh:integer;
+ br:HBRUSH;
+ hdcbmp:HDC;
+ bf:BLENDFUNCTION;
+ hOld:THANDLE;
+ D:PWATFrameData;
+begin
+ D:=CustomData;
+ D.BkDC:=CreateCompatibleDC(dc);
+
+ FixBitmap(dc,D.BkBitmap);
+
+ DeleteObject(SelectObject(D.BkDC,CreateDIB32(dc,rc.right-rc.left,rc.bottom-rc.top)));
+
+ //fill empty space by BK color
+ br:=CreateSolidBrush(D.BkColor);
+ FillRect(D.BkDC,rc,br);
+ DeleteObject(br);
+
+ CopyRect(dst,rc);
+ hdcbmp:=CreateCompatibleDC(D.BkDC);
+ GetObject(D.BkBitmap,SizeOf(bmpinfo),@bmpinfo);
+ hOld:=SelectObject(hdcbmp,D.BkBitmap);
+
+ SetRect(src,0,0,bmpinfo.bmWidth,bmpinfo.bmHeight);
+
+ if (D.padding.top+D.padding.bottom)<(dst.bottom-dst.top) then
+ dec(dst.bottom,D.padding.top+D.padding.bottom);
+ if (D.padding.left+D.padding.right)<(dst.right-dst.left) then
+ dec(dst.right,D.padding.left+D.padding.right);
+
+ CalcRect(src,dst,D.BkMode); // calculate final picture rect
+
+ w:=1;
+ if (D.BkMode and frbkTileX)<>0 then
+ begin
+ x:=dst.right;
+ while x<rc.right do
+ begin
+ inc(w);
+ inc(x,dst.right);
+ end;
+ end;
+ h:=1;
+ if (D.BkMode and frbkTileY)<>0 then
+ begin
+ y:=dst.bottom;
+ while y<rc.bottom do
+ begin
+ inc(h);
+ inc(y,dst.bottom);
+ end;
+ end;
+
+ bf.BlendOp :=AC_SRC_OVER;
+ bf.BlendFlags :=0;
+ bf.SourceConstantAlpha:=255;
+ bf.AlphaFormat :=1; // AC_SRC_ALPHA introduced in delphi 7
+
+ x:=dst.left+D.padding.left;
+ if x<dst.right then
+ while w>0 do
+ begin
+ dh:=h;
+ y:=dst.top+D.padding.top;
+ if y<dst.bottom then
+ while dh>0 do
+ begin
+ Windows.AlphaBlend(D.BkDC,x,y,dst.right-dst.left,dst.bottom-dst.top,
+ hdcbmp,src.left,src.top,src.right-src.left,src.bottom-src.top,bf);
+ inc(y,dst.bottom);
+ dec(dh);
+ end;
+ inc(x,dst.right);
+ dec(w);
+ end;
+
+ SelectObject(hdcbmp,hOld);
+ DeleteDC(hdcbmp);
+end;
diff --git a/plugins/Watrack/kolframe/kolframe.pas b/plugins/Watrack/kolframe/kolframe.pas
new file mode 100644
index 0000000000..615991d810
--- /dev/null
+++ b/plugins/Watrack/kolframe/kolframe.pas
@@ -0,0 +1,327 @@
+{CList frame}
+unit KOLFrame;
+
+interface
+
+implementation
+
+uses windows,kol,commdlg,messages,common,commctrl, KOLCCtrls,
+ wat_api,wrapper,global,m_api,dbsettings,waticons,mirutils,
+ icobuttons,textblock,kolsizer;
+
+{$R frm.res}
+
+{$include frm_data.inc}
+{$include frm_vars.inc}
+
+procedure MouseDown(DummySelf, Sender:PControl;var Mouse:TMouseEventData);
+var
+ wnd:HWND;
+begin
+ wnd:=GetParent(Sender.GetWindowHandle);
+ SendMessage(wnd,WM_SYSCOMMAND,
+ SC_MOVE or HTCAPTION,MAKELPARAM(Mouse.x,Mouse.y));
+end;
+
+// ---------------- frame functions ----------------
+
+procedure SetFrameTitle(title:pointer;icon:HICON;addflag:integer=FO_UNICODETEXT);
+var
+ D:PWATFrameData;
+begin
+ D:=FrameCtrl.CustomData;
+ CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS,
+ (D.FrameId shl 16)+FO_TBNAME+addflag,dword(title));
+ CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS,(D.FrameId shl 16)+FO_ICON,icon);
+ CallService(MS_CLIST_FRAMES_UPDATEFRAME,D.FrameId,FU_TBREDRAW);
+end;
+
+// -----------------------
+
+function IsFrameMinimized(FrameId:integer):bool;
+begin
+ result:=(CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS,
+ (FrameId shl 16)+FO_FLAGS,0) and F_UNCOLLAPSED)=0;
+end;
+
+function IsFrameFloated(FrameId:integer):bool;
+begin
+ result:=CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS,
+ (FrameId shl 16)+FO_FLOATING,0)>0;
+end;
+
+function IsFrameHidden(FrameId:integer):bool;
+begin
+ result:=(CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS,
+ (FrameId shl 16)+FO_FLAGS,0) and F_VISIBLE)=0;
+end;
+
+procedure HideFrame(FrameId:integer);
+begin
+ if not IsFrameHidden(FrameId) then
+ begin
+ CallService(MS_CLIST_FRAMES_SHFRAME,FrameId,0);
+ HiddenByMe:=true;
+ end;
+end;
+
+function ShowFrame(FrameId:integer):integer;
+begin
+ result:=0;
+ if IsFrameHidden(FrameId) then
+ if HiddenByMe then
+ begin
+ CallService(MS_CLIST_FRAMES_SHFRAME,FrameId,0);
+ HiddenByMe:=false;
+ end
+ else
+ result:=1;
+end;
+
+{$include frm_rc.inc}
+{$include frm_icogroup.inc}
+{$include frm_trackbar.inc}
+{$include frm_text.inc}
+{$include frm_frame.inc}
+{$include frm_designer.inc}
+
+{$include frm_dlg1.inc}
+{$include frm_dlg2.inc}
+
+// ---------------- basic frame functions ----------------
+
+function NewPlStatus(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+const
+ needToChange:boolean=true;
+var
+ bufw:array [0..511] of WideChar;
+// FrameWnd:HWND;
+ Cover:pAnsiChar;
+ D:PWATFrameData;
+begin
+ result:=0;
+// FrameWnd:=FrameCtrl.Form.GetWindowHandle;
+ D:=FrameCtrl.CustomData;
+
+ case wParam of
+ WAT_EVENT_PLAYERSTATUS: begin
+ case Integer(loword(lParam)) of
+ WAT_PLS_NORMAL : exit;
+ WAT_PLS_NOMUSIC : begin
+ if D.HideNoMusic then
+ HideFrame(D.FrameId)
+ else
+ ShowFrame(D.FrameId); // if was hidden with "no player"
+ end;
+ WAT_PLS_NOTFOUND: begin
+ if D.HideNoPlayer then
+ HideFrame(D.FrameId);
+
+ SetFrameTitle(PluginShort,0,0); // frame update code there
+ end;
+ end;
+ FrameCtrl.ResetFrame;
+ end;
+
+ WAT_EVENT_NEWTRACK: begin
+ // cover
+ if D.UseCover then
+ if (pSongInfo(lParam)^.Cover<>nil) and (pSongInfo(lParam)^.Cover^<>#0) then
+ begin
+ GetShortPathNameW(pSongInfo(lParam)^.Cover,bufw,SizeOf(bufw));
+ WideToAnsi(bufw,Cover);
+ FrameCtrl.RefreshPicture(Cover);
+ mFreeMem(Cover);
+ end;
+
+ // trackbar
+ TrackbarSetRange(D.Trackbar,D.UpdInterval,pSongInfo(lParam)^.total);
+
+ if (D.UpdTimer=0) and (D.UpdInterval>0) then
+ D.UpdTimer:=SetTimer(0,0,D.UpdInterval,@FrameTimerProc);
+
+ // text
+ UpdateTextBlock(D,true);
+
+ ShowFrame(D.FrameId);
+ end;
+
+ WAT_EVENT_NEWPLAYER: begin
+ SetFrameTitle(pSongInfo(lParam)^.player,pSongInfo(lParam)^.icon);
+ // new player must call "no music" at least, so we have chance to show frame
+ end;
+
+ WAT_EVENT_PLUGINSTATUS: begin
+ case lParam of
+ dsEnabled: begin
+ ShowFrame(D.FrameId);
+ // plus - start frame and text timers
+ if D.UpdInterval>0 then
+ D.UpdTimer:=SetTimer(0,0,D.UpdInterval,@FrameTimerProc);
+ end;
+
+ dsPermanent: begin
+ HideFrame(D.FrameId);
+
+ // plus - stop frame and text timers
+ if D.UpdTimer<>0 then
+ begin
+ KillTimer(0,D.UpdTimer);
+ D.UpdTimer:=0;
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+function IconChanged(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+begin
+ result:=0;
+ if PWATFrameData(FrameCtrl.CustomData).FrameId<>0 then
+ begin
+ FrameCtrl.RefreshAllFrameIcons;
+ ShowWindow(FrameCtrl.GetWindowHandle,SW_HIDE);
+ ShowWindow(FrameCtrl.GetWindowHandle,SW_SHOW);
+ end;
+end;
+
+//??const opt_FrmHeight :PAnsiChar = 'frame/frmheight';
+
+function CreateFrame(parent:HWND):boolean;
+var
+ CLFrame:TCLISTFrame;
+ rc:TRECT;
+ FrameWnd:HWND;
+begin
+ result:=false;
+ if ServiceExists(MS_CLIST_FRAMES_ADDFRAME)=0 then
+ exit;
+
+ if parent=0 then
+ parent:=CallService(MS_CLUI_GETHWND,0,0);
+
+ FrameWnd:=CreateFrameWindow(parent);
+
+ if FrameWnd<>0 then
+ begin
+ FillChar(CLFrame,SizeOf(CLFrame),0);
+ with CLFrame do
+ begin
+ cbSize :=SizeOf(CLFrame);
+ hWnd :=FrameWnd;
+ hIcon :=0;
+ align :=alTop;
+ GetClientRect(FrameWnd,rc);
+//?? height :=DBReadWord(0,PluginShort,opt_FrmHeight,rc.bottom-rc.top);
+ Flags :=0;//{F_VISIBLE or} F_SHOWTB;
+ name.a :=PluginShort;
+ TBName.a:=PluginShort;
+ end;
+ FrameHeight:=CLFrame.height;
+
+ PWATFrameData(FrameCtrl.CustomData).FrameId:=CallService(MS_CLIST_FRAMES_ADDFRAME,dword(@CLFrame),0);
+ if PWATFrameData(FrameCtrl.CustomData).FrameId>=0 then
+ begin
+ plStatusHook:=HookEvent(ME_WAT_NEWSTATUS,@NewPlStatus);
+ end;
+ end;
+ result:=FrameWnd<>0;
+end;
+
+procedure DestroyFrame;
+var
+ id:Integer;
+begin
+ if (FrameCtrl<>nil) and (PWATFrameData(FrameCtrl.CustomData).FrameId>=0) then
+ begin
+ UnhookEvent(plStatusHook);
+
+ id:=PWATFrameData(FrameCtrl.CustomData).FrameId;
+ FrameCtrl.Free;
+ FrameCtrl:=nil;
+ CallService(MS_CLIST_FRAMES_REMOVEFRAME,Id,0);
+ end;
+end;
+
+const
+ opt_ModStatus:PAnsiChar = 'module/frame';
+
+function GetModStatus:integer;
+begin
+ result:=DBReadByte(0,PluginShort,opt_ModStatus,1);
+end;
+
+procedure SetModStatus(stat:integer);
+begin
+ DBWriteByte(0,PluginShort,opt_modStatus,stat);
+end;
+
+// ---------------- base interface procedures ----------------
+
+function InitProc(aGetStatus:boolean=false):integer;
+begin
+ FrameCtrl:=nil;
+ result:=0;
+ if aGetStatus then
+ begin
+ if GetModStatus=0 then
+ exit;
+ end
+ else
+ SetModStatus(1);
+
+ result:=ord(CreateFrame(0));
+ if result<>0 then
+ sic:=HookEvent(ME_SKIN2_ICONSCHANGED,@IconChanged);
+end;
+
+procedure DeInitProc(aSetDisable:boolean);
+begin
+ if aSetDisable then
+ SetModStatus(0);
+
+ if sic<>0 then UnhookEvent(sic);
+ sic:=0;
+ DestroyFrame;
+end;
+
+function AddOptionsPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+const
+ count:integer=2;
+begin
+ if count=0 then
+ count:=2;
+ if count=2 then
+ begin
+ tmpl:='FRAME';
+ proc:=@FrameViewDlg;
+ name:='Frame (main)';
+ end
+ else
+ begin
+ tmpl:='FRAME2';
+ proc:=@FrameTextDlg;
+ name:='Frame (text)';
+ end;
+
+ dec(count);
+ result:=count;
+end;
+
+var
+ Frame:twModule;
+
+procedure Init;
+begin
+ Frame.Next :=ModuleLink;
+ Frame.Init :=@InitProc;
+ Frame.DeInit :=@DeInitProc;
+ Frame.AddOption :=@AddOptionsPage;
+ Frame.ModuleName:='Frame';
+ ModuleLink :=@Frame;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Watrack/lastfm/i_const.inc b/plugins/Watrack/lastfm/i_const.inc
new file mode 100644
index 0000000000..9a0365e506
--- /dev/null
+++ b/plugins/Watrack/lastfm/i_const.inc
@@ -0,0 +1,17 @@
+const
+ IDC_LOGIN = 1025;
+ IDC_PASS = 1026;
+ IDC_TRIES = 1027;
+
+ IDC_INFO_ARTIST = 1030;
+ IDC_INFO_TRACK = 1031;
+ IDC_INFO_ALBUM = 1032;
+ IDC_LANGUAGE = 1033;
+
+ IDC_DATA_PIC = 1040;
+ IDC_DATA_ARTIST = 1041;
+ IDC_DATA_ALBUM = 1042;
+ IDC_DATA_TRACK = 1043;
+ IDC_DATA_TAGS = 1044;
+ IDC_DATA_INFO = 1045;
+ IDC_ALT = 1046;
diff --git a/plugins/Watrack/lastfm/i_last_api.inc b/plugins/Watrack/lastfm/i_last_api.inc
new file mode 100644
index 0000000000..73328366ba
--- /dev/null
+++ b/plugins/Watrack/lastfm/i_last_api.inc
@@ -0,0 +1,599 @@
+{}
+
+const
+ client_id = 'wat';//'wat'; 'tst'
+ client_ver = '1.0';
+ api_key = '51f5d25159da31b0814609c3a12900e2';
+
+const
+ defreq = 'http://post.audioscrobbler.com/?hs=true&p=1.2.1&c=<client-id>&v=<client-ver>&u=<user>&t=<timestamp>&a=<auth>';
+
+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; notify:bool=false):bool;
+var
+ buf:array [0..32] of AnsiChar;
+ digest:TMD5Hash;
+ stat:mir_md5_state_t;
+ timestamp:array [0..31] of AnsiChar;
+ request:array [0..511] of AnsiChar;
+ tmp,res:pAnsiChar;
+begin
+ result:=false;
+ GetMD5Str(GetMD5(password,StrLen(password),digest),buf);
+ mir_md5_init(@stat);
+ mir_md5_append(@stat,@buf,32);
+ IntToStr(timestamp,GetCurrentTime);
+ mir_md5_append(@stat,@timestamp,StrLen(timestamp));
+ mir_md5_finish(@stat,digest);
+ GetMD5Str(digest,buf);
+ StrCopy(request,defreq);
+ StrReplace(request,'<client-id>' ,client_id);
+ StrReplace(request,'<client-ver>',client_ver);
+ StrReplace(request,'<user>' ,login);
+ StrReplace(request,'<timestamp>' ,timestamp);
+ StrReplace(request,'<auth>' ,buf);
+
+ res:=SendRequest(request,REQUEST_GET);
+ if (res<>nil) and (uint_ptr(res)>$0FFF) then
+ begin
+ if StrCmp(CharReplace(res,#10,#0),'OK')=0 then
+ begin
+ result:=true;
+ tmp:=StrEnd(res)+1; StrDup(session_id,tmp);
+ tmp:=StrEnd(tmp)+1; StrDup(np_url ,tmp);
+ tmp:=StrEnd(tmp)+1; StrDup(sub_url ,tmp);
+ end
+ else if notify then
+ begin
+ tmp:=StrCopyE(request,Translate('Last.fm error: '));
+ if StrCmp(res,'BANNED' )=0 then StrCopy(tmp,Translate('Client is banned'))
+ else if StrCmp(res,'BADAUTH' )=0 then StrCopy(tmp,Translate('Bad Auth. Check login and password'))
+ else if StrCmp(res,'BADTIME' )=0 then StrCopy(tmp,Translate('Bad TimeStamp'))
+ else if StrCmp(res,'FAILED',6)=0 then StrCopy(tmp,res+7);
+ CallService(MS_POPUP_SHOWMESSAGEW,wparam(@request),SM_ERROR);
+ end;
+ mFreeMem(res);
+ 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 SendNowPlaying:integer;
+var
+ si:pSongInfoA;
+ buf :array [0..31 ] of AnsiChar;
+ args :array [0..1023] of AnsiChar;
+ res,pc:PAnsiChar;
+begin
+ result:=-1;
+ if session_id<>nil then
+ begin
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UTF8,0));
+
+ pc:=@args;
+ pc:=StrCopyE(pc,'s='); pc:=StrCopyE(pc,session_id); //'?s='
+ pc:=StrCopyE(pc,'&a=');
+ if si^.artist=nil then pc:=StrCopyE(pc,'Unknown')
+ else pc:=encode(pc,si^.artist);
+ pc:=StrCopyE(pc,'&t=');
+ if si^.title =nil then pc:=StrCopyE(pc,'Unknown')
+ else pc:=encode(pc,si^.title);
+ pc:=StrCopyE(pc,'&l='); if si^.total>0 then pc:=StrCopyE(pc,IntToStr(buf,si^.total));
+ pc:=StrCopyE(pc,'&b='); pc:=encode(pc,si^.album);
+ pc:=StrCopyE(pc,'&n=');
+ if si^.track<>0 then
+ {pc:=}StrCopyE(pc,IntToStr(buf,si^.track));
+
+ res:=SendRequest(np_url,REQUEST_POST,args);
+ if (res<>nil) and (uint_ptr(res)>$0FFF) then
+ begin
+ if StrCmp(CharReplace(res,#10,#0),'OK')=0 then
+ result:=1
+ else if StrCmp(res,'BADSESSION')=0 then
+ result:=-1;
+ mFreeMem(res);
+ end;
+ end;
+end;
+
+function Scrobble:integer;
+var
+ si:pSongInfoA;
+ buf,timestamp:array [0..31] of AnsiChar;
+ args :array [0..1023] of AnsiChar;
+ res,pc:PAnsiChar;
+begin
+ result:=-1;
+ if session_id<>nil then
+ begin
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UTF8,0));
+ IntToStr(timestamp,GetCurrentTime);
+
+ pc:=@args;
+ pc:=StrCopyE(pc,'s=' ); pc:=StrCopyE(pc,session_id);
+ pc:=StrCopyE(pc,'&a[0]=');
+ if si^.artist=nil then pc:=StrCopyE(pc,'Unknown')
+ else pc:=encode(pc,si^.artist);
+ pc:=StrCopyE(pc,'&t[0]=');
+ if si^.title =nil then pc:=StrCopyE(pc,'Unknown')
+ else pc:=encode(pc,si^.title);
+ pc:=StrCopyE(pc,'&i[0]='); pc:=StrCopyE(pc,timestamp);
+ pc:=StrCopyE(pc,'&r[0]=&m[0]=');
+ pc:=StrCopyE(pc,'&l[0]=');
+ if si^.total>0 then
+ begin
+ pc:=StrCopyE(pc,IntToStr(buf,si^.total));
+ pc:=StrCopyE(pc,'&o[0]=P');
+ end
+ else
+ begin
+ pc:=StrCopyE(pc,'&o[0]=R');
+ end;
+ pc:=StrCopyE(pc,'&b[0]='); pc:=encode(pc,si^.album);
+ pc:=StrCopyE(pc,'&n[0]=');
+ if si^.track<>0 then
+ {pc:=}StrCopyE(pc,IntToStr(buf,si^.track));
+
+ res:=SendRequest(sub_url,REQUEST_POST,args);
+ if (res<>nil) and (uint_ptr(res)>$0FFF) then
+ begin
+ if StrCmp(CharReplace(res,#10,#0),'OK')=0 then
+ result:=1
+ else if StrCmp(res,'BADSESSION')=0 then
+ begin
+ result:=-1;
+ end
+ else if StrCmp(res,'FAILED',6)=0 then
+ begin
+ StrCopy(StrCopyE(args,Translate('Last.fm error: ')),res+7);
+ CallService(MS_POPUP_SHOWMESSAGE,wparam(@args),SM_NOTIFY);
+ result:=0;
+ end;
+ mFreeMem(res);
+ end;
+ end;
+end;
+
+//----- Get Info service functions -----
+
+function FullEncode(dst,src:pAnsiChar):PAnsiChar;
+begin
+ while src^<>#0 do
+ begin
+ if src^ in ['A'..'Z','a'..'z','0'..'9'] 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;
+
+var
+ xmlparser:XML_API_W;
+
+function FixInfo(info:pWideChar):pWideChar;
+var
+ pc,ppc:pWideChar;
+ cnt:cardinal;
+ need:boolean;
+begin
+ pc:=info;
+ cnt:=0;
+ need:=false;
+ while pc^<>#0 do
+ begin
+ if pc^=#$0D then
+ begin
+ inc(cnt);
+ inc(pc);
+ if pc^<>#$0A then
+ need:=true;
+ end
+ else
+ inc(pc);
+ end;
+ if need then
+ begin
+ mGetMem(result,(StrLenW(info)+1+cnt)*SizeOf(WideChar));
+ pc:=info;
+ ppc:=result;
+ while pc^<>#0 do
+ begin
+ ppc^:=pc^;
+ if pc^=#$0D then
+ begin
+ inc(ppc);
+ ppc^:=#$0A;
+ end;
+ inc(pc);
+ inc(ppc);
+ end;
+ ppc^:=#0;
+ end
+ else
+ StrDupW(result,info);
+end;
+
+function GetArtistInfo(var data:tLastFMInfo;lang:integer):int;
+var
+ si:pSongInfo;
+ res,pc:pAnsiChar;
+ request:array [0..1023] of AnsiChar;
+ root,actnode,node,nnode:HXML;
+ i:integer;
+ pcw,p,pp:PWideChar;
+ artist:pAnsiChar;
+begin
+ result:=0;
+ if data.artist=nil then
+ begin
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UNICODE,0));
+ pWideChar(artist):=si^.artist;
+ end
+ else
+ pWideChar(artist):=data.artist;
+ if artist=nil then
+ exit;
+ WideToUTF8(pWideChar(artist),artist);
+ pc:=FullEncode(StrCopyE(request,
+ 'http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&api_key='+api_key+'&artist='),
+ artist);
+ mFreeMem(artist);
+ if lang<>0 then
+ StrCopyE(StrCopyE(pc,'&lang='),pAnsiChar(@lang));
+ res:=SendRequest(request,REQUEST_GET);
+ if (res<>nil) and (uint_ptr(res)>$0FFF) then
+ begin
+ UTF8ToWide(res,pcw);
+ mFreeMem(res);
+ xmlparser.cbSize:={XML_API_SIZEOF_V1;//}SizeOf(XML_API_W);
+ CallService(MS_SYSTEM_GET_XI,0,lparam(@xmlparser));
+ with xmlparser do
+ begin
+ i:=StrLenW(pcw)*SizeOf(WideChar);
+ root:=parseString(pcw,@i,nil);
+
+ actnode:=getChild(getChild(root,0),0); // "artist"
+
+ if data.artist=nil then
+ StrDupW(data.artist,getText(GetNthChild(actnode,'name',0)));
+
+ i:=0;
+ repeat
+ node:=GetNthChild(actnode,'image',i);
+ if node=0 then break;
+ if StrCmpW(GetAttrValue(node,'size'),'medium')=0 then
+ begin
+ WideToUTF8(GetText(node),data.image);
+ break;
+ end;
+ inc(i);
+ until false;
+
+ // bio
+ p:=StrPosW(pcw,'<content><![CDATA[');
+ if p<>nil then
+ begin
+ inc(p,18);
+ pp:=StrPosW(p,']]');
+ if pp<> nil then pp^:=#0;
+ data.info:=FixInfo(p);
+ end;
+
+ // similar
+ i:=0;
+ pcw:=pWideChar(@request); pcw^:=#0;
+ node:=GetNthChild(actnode,'similar',0);
+ repeat
+ nnode:=GetNthChild(GetNthChild(node,'artist',i),'name',0);
+ if nnode=0 then break;
+ if pcw<>@request then
+ begin
+ pcw^:=','; inc(pcw);
+ pcw^:=' '; inc(pcw);
+ end;
+ pcw:=StrCopyEW(pcw,GetText(nnode));
+ inc(i);
+ until false;
+ pcw:=#0;
+ StrDupW(data.similar,pWideChar(@request));
+
+ // tags
+ i:=0;
+ pcw:=pWideChar(@request); pcw^:=#0;
+ node:=GetNthChild(actnode,'tags',0);
+ repeat
+ nnode:=GetNthChild(GetNthChild(node,'tag',i),'name',0);
+ if nnode=0 then break;
+ if pcw<>@request then
+ begin
+ pcw^:=','; inc(pcw);
+ pcw^:=' '; inc(pcw);
+ end;
+ pcw:=StrCopyEW(pcw,GetText(nnode));
+ inc(i);
+ until false;
+ pcw:=#0;
+ StrDupW(data.tags,pWideChar(@request));
+ DestroyNode(root);
+ mFreeMem(pcw);
+ end;
+ end;
+end;
+
+function GetAlbumInfo(var data:tLastFMInfo;lang:integer):int;
+var
+ si:pSongInfo;
+ res,pc:pAnsiChar;
+ request:array [0..1023] of AnsiChar;
+ root,actnode,node,nnode:HXML;
+ i:integer;
+ p,pp,pcw:PWideChar;
+ album,artist:pAnsiChar;
+begin
+ result:=0;
+ si:=nil;
+ if data.album=nil then
+ begin
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UNICODE,0));
+ pWideChar(album):=si^.album;
+ end
+ else
+ pWideChar(album):=data.album;
+ if album=nil then
+ exit;
+ WideToUTF8(pWideChar(album),album);
+ pc:=FullEncode(StrCopyE(request,
+ 'http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key='+api_key+'&album='),
+ album);
+ mFreeMem(album);
+ if data.artist=nil then
+ begin
+ if si=nil then
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UNICODE,0));
+ pWideChar(artist):=si^.artist;
+ end
+ else
+ pWideChar(artist):=data.artist;
+ if artist<>nil then
+ begin
+ WideToUTF8(pWideChar(artist),artist);
+ pc:=FullEncode(StrCopyE(pc,'&artist='),artist);
+ mFreeMem(artist);
+ end;
+
+ if lang<>0 then
+ StrCopyE(StrCopyE(pc,'&lang='),pAnsiChar(@lang));
+
+ res:=SendRequest(request,REQUEST_GET);
+ if res<>nil then
+ begin
+ UTF8ToWide(res,pcw);
+ mFreeMem(res);
+ xmlparser.cbSize:={XML_API_SIZEOF_V1;//}SizeOf(XML_API_W);
+ CallService(MS_SYSTEM_GET_XI,0,lparam(@xmlparser));
+ with xmlparser do
+ begin
+ i:=StrLenW(pcw)*SizeOf(WideChar);
+ root:=parseString(pcw,@i,nil);
+
+ actnode:=getChild(getChild(root,0),0); // "album"
+
+ if data.album=nil then
+ StrDupW(data.album,getText(GetNthChild(actnode,'name',0)));
+ StrDupW(data.release,getText(GetNthChild(actnode,'releasedate',0)));
+ if data.artist=nil then
+ StrDupW(data.artist,getText(GetNthChild(actnode,'artist',0)));
+
+ i:=0;
+ repeat
+ node:=GetNthChild(actnode,'image',i);
+ if node=0 then break;
+ if StrCmpW(GetAttrValue(node,'size'),'medium')=0 then
+ begin
+ WideToUTF8(GetText(node),data.image);
+ break;
+ end;
+ inc(i);
+ until false;
+
+ p:=StrPosW(pcw,'<content><![CDATA[');
+ if p<>nil then
+ begin
+ inc(p,18);
+ pp:=StrPosW(p,']]');
+ if pp<> nil then pp^:=#0;
+ data.info:=FixInfo(p);
+ end;
+
+ // tags
+ i:=0;
+ pcw:=pWideChar(@request); pcw^:=#0;
+ node:=GetNthChild(actnode,'toptags',0);
+ repeat
+ nnode:=GetNthChild(GetNthChild(node,'tag',i),'name',0);
+ if nnode=0 then break;
+ if pcw<>@request then
+ begin
+ pcw^:=','; inc(pcw);
+ pcw^:=' '; inc(pcw);
+ end;
+ pcw:=StrCopyEW(pcw,GetText(nnode));
+ inc(i);
+ until false;
+ pcw:=#0;
+ StrDupW(data.tags,pWideChar(@request));
+
+ DestroyNode(root);
+ mFreeMem(pcw);
+ end;
+ end;
+end;
+
+function GetTrackInfo(var data:tLastFMInfo;lang:integer):int;
+var
+ si:pSongInfo;
+ res,pc:pAnsiChar;
+ request:array [0..1023] of AnsiChar;
+ root,actnode,node,anode:HXML;
+ i:integer;
+ p,pp,pcw:PWideChar;
+ title,artist:pAnsiChar;
+begin
+ result:=0;
+ si:=nil;
+ if data.album=nil then
+ begin
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UNICODE,0));
+ pWideChar(title):=si^.title;
+ end
+ else
+ pWideChar(title):=data.title;
+ if title=nil then
+ exit;
+ WideToUTF8(pWideChar(title),title);
+ pc:=FullEncode(StrCopyE(request,
+ 'http://ws.audioscrobbler.com/2.0/?method=track.getinfo&api_key='+api_key+'&track='),
+ title);
+ mFreeMem(title);
+ if data.artist=nil then
+ begin
+ if si=nil then
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,WAT_INF_UNICODE,0));
+ pWideChar(artist):=si^.artist;
+ end
+ else
+ pWideChar(artist):=data.artist;
+ if artist<>nil then
+ begin
+ WideToUTF8(pWideChar(artist),artist);
+ pc:=FullEncode(StrCopyE(pc,'&artist='),artist);
+ mFreeMem(artist);
+ end;
+
+ if lang<>0 then
+ StrCopyE(StrCopyE(pc,'&lang='),pAnsiChar(@lang));
+
+ res:=SendRequest(request,REQUEST_GET);
+ if res<>nil then
+ begin
+ UTF8ToWide(res,pcw);
+ mFreeMem(res);
+ xmlparser.cbSize:={XML_API_SIZEOF_V1;//}SizeOf(XML_API_W);
+ CallService(MS_SYSTEM_GET_XI,0,lparam(@xmlparser));
+ with xmlparser do
+ begin
+ i:=StrLenW(pcw)*SizeOf(WideChar);
+ root:=parseString(pcw,@i,nil);
+
+ actnode:=getChild(getChild(root,0),0); // "track"
+ if data.artist=nil then
+ StrDupW(data.artist,getText(GetNthChild(GetNthChild(actnode,'artist',0),'name',0)));
+
+ anode:=GetNthChild(actnode,'album',i);
+
+ if data.album=nil then
+ StrDupW(data.album,getText(GetNthChild(anode,'title',0)));
+
+ data.trknum:=StrToInt(getAttrValue(anode,'position'));
+ if data.title=nil then
+ StrDupW(data.title,getText(GetNthChild(actnode,'name',0)));
+
+ i:=0;
+ repeat
+ node:=GetNthChild(anode,'image',i);
+ if node=0 then break;
+ if StrCmpW(GetAttrValue(node,'size'),'medium')=0 then
+ begin
+ WideToUTF8(GetText(node),data.image);
+ break;
+ end;
+ inc(i);
+ until false;
+
+ p:=StrPosW(pcw,'<content><![CDATA[');
+ if p<>nil then
+ begin
+ inc(p,18);
+ pp:=StrPosW(p,']]');
+ if pp<> nil then pp^:=#0;
+ data.info:=FixInfo(p);
+ end;
+
+ // tags
+ i:=0;
+ pcw:=pWideChar(@request); pcw^:=#0;
+ node:=GetNthChild(actnode,'toptags',0);
+ repeat
+ anode:=GetNthChild(GetNthChild(node,'tag',i),'name',0);
+ if anode=0 then break;
+ if pcw<>@request then
+ begin
+ pcw^:=','; inc(pcw);
+ pcw^:=' '; inc(pcw);
+ end;
+ pcw:=StrCopyEW(pcw,GetText(anode));
+ inc(i);
+ until false;
+ pcw:=#0;
+ StrDupW(data.tags,pWideChar(@request));
+
+ DestroyNode(root);
+ mFreeMem(pcw);
+ end;
+ end;
+end;
diff --git a/plugins/Watrack/lastfm/i_last_dlg.inc b/plugins/Watrack/lastfm/i_last_dlg.inc
new file mode 100644
index 0000000000..b72545843e
--- /dev/null
+++ b/plugins/Watrack/lastfm/i_last_dlg.inc
@@ -0,0 +1,120 @@
+{}
+const
+ MaxLangs = 11;
+ LangArray:array [0..MaxLangs-1] of record
+ code:array [0..1] of AnsiChar;
+ name:pWideChar;
+ end= (
+ (code:#0#0 ; name: 'no language';),
+ (code:'zh' ; name: 'Chinese' ;),
+ (code:'en' ; name: 'English' ;),
+ (code:'fr' ; name: 'French' ;),
+ (code:'de' ; name: 'German' ;),
+ (code:'hi' ; name: 'Hindi' ;),
+ (code:'it' ; name: 'Italian' ;),
+ (code:'ja' ; name: 'Japanese' ;),
+ (code:'pt' ; name: 'Portuguese' ;),
+ (code:'ru' ; name: 'Russian' ;),
+ (code:'es' ; name: 'Spanish' ;)
+ );
+
+procedure ClearInfo(dlg:HWND);
+begin
+ SetDlgItemTextW(dlg,IDC_DATA_ARTIST,'');
+ SetDlgItemTextW(dlg,IDC_DATA_ALBUM ,'');
+ SetDlgItemTextW(dlg,IDC_DATA_TRACK ,'');
+ SetDlgItemTextW(dlg,IDC_DATA_TAGS ,'');
+ SetDlgItemTextW(dlg,IDC_DATA_INFO ,'');
+end;
+
+procedure ClearData(var data:tLastFMInfo);
+begin
+ mFreeMem(data.artist);
+ mFreeMem(data.album);
+ mFreeMem(data.title);
+ mFreeMem(data.tags);
+ mFreeMem(data.info);
+ mFreeMem(data.image);
+end;
+
+function DlgProcOptions(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ tmp:longbool;
+ bmp,wnd:HWND;
+ lang:integer;
+ data:tLastFMInfo;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ SetDlgItemTextA(Dialog,IDC_LOGIN,lfm_login);
+ SetDlgItemTextA(Dialog,IDC_PASS ,lfm_password);
+ SetDlgItemInt (Dialog,IDC_TRIES,lfm_tries,false);
+ wnd:=GetDlgItem(Dialog,IDC_LANGUAGE);
+ for lang:=0 to MaxLangs-1 do
+ with LangArray[lang] do
+ CB_AddStrDataW(wnd,TranslateW(name),
+ ord(code[0])+(ord(code[1]) shl 8),lang);
+ CB_SelectData(wnd,lfm_lang);
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ BN_CLICKED: begin
+ ClearInfo(Dialog);
+ FillChar(data,SizeOf(data),0);
+ lfm_lang:=CB_GetData(GetDlgItem(Dialog,IDC_LANGUAGE));
+
+ if loword(wParam)=IDC_INFO_ARTIST then
+ begin
+ SetDlgItemTextW(Dialog,IDC_ALT,TranslateW('Similar artists'));
+ GetArtistInfo(data,lfm_lang);
+ SetDlgItemTextW(Dialog,IDC_DATA_ALBUM,data.similar);
+ end
+ else
+ begin
+ SetDlgItemTextW(Dialog,IDC_ALT,TranslateW('Album'));
+ if loword(wParam)=IDC_INFO_TRACK then
+ GetTrackInfo (data,lfm_lang)
+ else
+ GetAlbumInfo (data,lfm_lang);
+ SetDlgItemTextW(Dialog,IDC_DATA_ALBUM,data.album);
+ end;
+
+ SetDlgItemTextW(Dialog,IDC_DATA_ARTIST,data.artist);
+ SetDlgItemTextW(Dialog,IDC_DATA_TRACK ,data.title);
+ SetDlgItemTextW(Dialog,IDC_DATA_TAGS ,data.tags);
+ SetDlgItemTextW(Dialog,IDC_DATA_INFO ,data.info);
+ bmp:=LoadImageURL(data.image,64);
+ if bmp<>0 then
+ DeleteObject(SendDlgItemMessage(Dialog,IDC_DATA_PIC,STM_SETIMAGE,IMAGE_BITMAP,bmp));
+
+ ClearData(data);
+ end;
+ EN_CHANGE:
+ case loword(wParam) of
+ IDC_LOGIN,IDC_PASS,IDC_TRIES:
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ begin
+ mFreeMem(lfm_login ); lfm_login :=GetDlgText(Dialog,IDC_LOGIN,true);
+ mFreeMem(lfm_password); lfm_password:=GetDlgText(Dialog,IDC_PASS ,true);
+ mFreeMem(session_id);
+ mFreeMem(np_url);
+ mFreeMem(sub_url);
+ lfm_tries:=GetDlgItemInt(Dialog,IDC_TRIES,tmp,false);
+ lfm_lang:=CB_GetData(GetDlgItem(Dialog,IDC_LANGUAGE));
+
+ SaveOpt;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/lastfm/i_last_opt.inc b/plugins/Watrack/lastfm/i_last_opt.inc
new file mode 100644
index 0000000000..f18b590a87
--- /dev/null
+++ b/plugins/Watrack/lastfm/i_last_opt.inc
@@ -0,0 +1,44 @@
+{}
+const
+ optLogin :pAnsiChar='lfm/login';
+ optPassword:pAnsiChar='lfm/password';
+ optTries :pAnsiChar='lfm/tries';
+ optScrobble:pAnsiChar='lfm/scrobble';
+ optLanguage:pAnsiChar='lfm/language';
+
+procedure SaveOpt;
+var
+ tmppass:array [0..255] of AnsiChar;
+begin
+ if lfm_password<>nil then
+ begin
+ StrCopy(tmppass,lfm_password);
+ CallService(MS_DB_CRYPT_ENCODESTRING,StrLen(tmppass)+1,lparam(@tmppass));
+ end;
+ DBWriteString(0,PluginShort,optPassword,tmppass);
+ DBWriteString(0,PluginShort,optLogin ,lfm_login);
+ DBWriteByte (0,PluginShort,optTries ,lfm_tries);
+ DBWriteByte (0,PluginShort,optScrobble,lfm_on and 1);
+ DBWriteWord (0,PluginShort,optLanguage,lfm_lang);
+end;
+
+procedure LoadOpt;
+begin
+ lfm_lang :=DBReadWord(0,PluginShort,optLanguage,0);
+ lfm_tries:=DBReadByte(0,PluginShort,optTries ,3);
+ lfm_on :=DBReadByte(0,PluginShort,optScrobble,0);
+ mFreeMem(lfm_login ); lfm_login :=DBReadString(0,PluginShort,optLogin);
+ mFreeMem(lfm_password); lfm_password:=DBReadString(0,PluginShort,optPassword);
+ if lfm_password<>nil then
+ CallService(MS_DB_CRYPT_DECODESTRING,StrLen(lfm_password)+1,lparam(lfm_password));
+ if (lfm_login=nil) or (lfm_password=nil) then
+ CallService(MS_POPUP_SHOWMESSAGEW,
+ wparam(TranslateW('Don''t forget to enter Login and Password to use Last.fm service')),
+ SM_WARNING);
+end;
+
+procedure FreeOpt;
+begin
+ mFreeMem(lfm_login);
+ mFreeMem(lfm_password);
+end;
diff --git a/plugins/Watrack/lastfm/lastfm.ico b/plugins/Watrack/lastfm/lastfm.ico
new file mode 100644
index 0000000000..6ed701e2a5
--- /dev/null
+++ b/plugins/Watrack/lastfm/lastfm.ico
Binary files differ
diff --git a/plugins/Watrack/lastfm/lastfm.pas b/plugins/Watrack/lastfm/lastfm.pas
new file mode 100644
index 0000000000..7f2d90b0dd
--- /dev/null
+++ b/plugins/Watrack/lastfm/lastfm.pas
@@ -0,0 +1,300 @@
+unit lastfm;
+{$include compilers.inc}
+interface
+{$Resource lastfm.res}
+implementation
+
+uses windows, messages, commctrl,
+ common,
+ m_api,dbsettings,wrapper,mirutils,
+ wat_api,global;
+
+const
+ opt_ModStatus:PAnsiChar = 'module/lastfm';
+const
+ IcoLastFM:pAnsiChar = 'WATrack_lasfm';
+var
+ lfm_tries:integer;
+ sic:THANDLE;
+ slastinf:THANDLE;
+ slast:THANDLE;
+const
+ lfm_lang :integer=0;
+ lfm_on :integer=0;
+ hMenuLast :HMENU = 0;
+ lfm_login :pAnsiChar=nil;
+ lfm_password:pAnsiChar=nil;
+ session_id :pAnsiChar=nil;
+ np_url :pAnsiChar=nil;
+ sub_url :pAnsiChar=nil;
+
+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_last_opt.inc}
+{$i i_last_api.inc}
+
+procedure ThScrobble(param:LPARAM); cdecl;
+var
+ count:integer;
+ npisok:bool;
+begin
+ count:=lfm_tries;
+ npisok:=false;
+ while count>0 do
+ begin
+ if not npisok then
+ npisok:=SendNowPlaying>=0;
+ if Scrobble>=0 then break;
+ HandShake(lfm_login,lfm_password, count=1); // just last time
+ dec(count);
+ end;
+ if count=0 then ;
+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 (lfm_login <>nil) and (lfm_login^ <>#0) and
+ (lfm_password<>nil) and (lfm_password^<>#0) then
+ CloseHandle(mir_forkthread(@ThScrobble,nil));
+end;
+
+function NewPlStatus(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ flag:integer;
+ mi:TCListMenuItem;
+begin
+ result:=0;
+ case wParam of
+ WAT_EVENT_NEWTRACK: begin
+ if hTimer<>0 then
+ begin
+ KillTimer(0,hTimer);
+ hTimer:=0;
+ end;
+ if lfm_on=0 then
+ hTimer:=SetTimer(0,0,30000,@TimerProc)
+ end;
+
+ WAT_EVENT_PLUGINSTATUS: begin
+ case lParam of
+ dsEnabled: begin
+ lfm_on:=lfm_on and not 2;
+ flag:=0;
+ end;
+ dsPermanent: begin
+ lfm_on:=lfm_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,hMenuLast,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_last_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(IcoLastFM));
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuLast,tlparam(@mi));
+end;
+
+function SrvLastFMInfo(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ data:tLastFMInfo;
+begin
+ case wParam of
+ 0: result:=GetArtistInfo(data,lParam);
+ 1: result:=GetAlbumInfo (data,lParam);
+ 2: result:=GetTrackInfo (data,lParam);
+ else
+ result:=0;
+ end;
+end;
+
+function SrvLastFM(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(lfm_on) then
+ begin
+ mi.szName.a:='Disable scrobbling';
+ lfm_on:=lfm_on and not 1;
+ end
+ else
+ begin
+ mi.szName.a:='Enable scrobbling';
+ lfm_on:=lfm_on or 1;
+ if hTimer<>0 then
+ begin
+ KillTimer(0,hTimer);
+ hTimer:=0;
+ end;
+ end;
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuLast,tlparam(@mi));
+ result:=ord(not odd(lfm_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_LAST',IMAGE_ICON,16,16,0);
+ sid.pszName :=IcoLastFM;
+ sid.szDescription.a:='LastFM';
+ 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,lparam(IcoLastFM));
+ mi.szName.a :='Disable scrobbling';
+ mi.pszService :=MS_WAT_LASTFM;
+ mi.popupPosition:=500050000;
+ hMenuLast:=Menu_AddMainMenuItem(@mi);
+end;
+
+// ------------ base interface functions -------------
+
+function AddOptionsPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+begin
+ tmpl:='LASTFM';
+ proc:=@DlgProcOptions;
+ name:='LastFM';
+ result:=0;
+end;
+
+var
+ plStatusHook:THANDLE;
+
+function InitProc(aGetStatus:boolean=false):integer;
+begin
+ slastinf:=CreateServiceFunction(MS_WAT_LASTFMINFO,@SrvLastFMInfo);
+ if aGetStatus then
+ begin
+ if GetModStatus=0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ end
+ else
+ begin
+ SetModStatus(1);
+ lfm_on:=lfm_on and not 4;
+ end;
+ result:=1;
+
+ LoadOpt;
+
+ slast:=CreateServiceFunction(MS_WAT_LASTFM,@SrvLastFM);
+ if hMenuLast=0 then
+ CreateMenus;
+ sic:=HookEvent(ME_SKIN2_ICONSCHANGED,@IconChanged);
+ if (lfm_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);
+
+ CallService(MS_CLIST_REMOVEMAINMENUITEM,hMenuLast,0);
+ hMenuLast:=0;
+ 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);
+
+ lfm_on:=lfm_on or 4;
+end;
+
+var
+ last:twModule;
+
+procedure Init;
+begin
+ last.Next :=ModuleLink;
+ last.Init :=@InitProc;
+ last.DeInit :=@DeInitProc;
+ last.AddOption:=@AddOptionsPage;
+ last.ModuleName:='Last.FM';
+ ModuleLink :=@last;
+
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Watrack/lastfm/lastfm.rc b/plugins/Watrack/lastfm/lastfm.rc
new file mode 100644
index 0000000000..320eebe8cc
--- /dev/null
+++ b/plugins/Watrack/lastfm/lastfm.rc
@@ -0,0 +1,38 @@
+#include "i_const.inc"
+
+LANGUAGE 0,0
+
+LASTFM 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 "Content language", -1, 80, 52, 76, 16, SS_CENTERIMAGE
+ COMBOBOX IDC_LANGUAGE, 160, 53, 74, 96, CBS_DROPDOWNLIST | WS_VSCROLL
+
+ PUSHBUTTON "Get Artist Info", IDC_INFO_ARTIST, 4, 166, 72, 16
+ PUSHBUTTON "Get Track Info" , IDC_INFO_TRACK , 4, 186, 72, 16
+ PUSHBUTTON "Get Album Info" , IDC_INFO_ALBUM , 4, 206, 72, 16
+
+ CONTROL "", IDC_DATA_PIC, "STATIC", SS_BITMAP | WS_BORDER, 236, 2, 64, 64
+ RTEXT "Artist", -1 , 0, 70, 76, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_DATA_ARTIST, 80, 71, 220, 14, ES_READONLY | ES_AUTOHSCROLL
+ RTEXT "Album",IDC_ALT, 0, 86, 76, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_DATA_ALBUM , 80, 87, 220, 14, ES_READONLY | ES_AUTOHSCROLL
+ RTEXT "Track" , -1 , 0, 102, 76, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_DATA_TRACK , 80, 103, 220, 14, ES_READONLY | ES_AUTOHSCROLL
+ RTEXT "Tags" , -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, 88,
+ ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL
+}
+
+IDI_LAST ICON "lastfm.ico"
diff --git a/plugins/Watrack/lastfm/lastfm.res b/plugins/Watrack/lastfm/lastfm.res
new file mode 100644
index 0000000000..0ed756fb33
--- /dev/null
+++ b/plugins/Watrack/lastfm/lastfm.res
Binary files differ
diff --git a/plugins/Watrack/lst_formats.inc b/plugins/Watrack/lst_formats.inc
new file mode 100644
index 0000000000..19db34ee40
--- /dev/null
+++ b/plugins/Watrack/lst_formats.inc
@@ -0,0 +1,16 @@
+,fmt_dummy in 'formats\fmt_dummy.pas'
+,fmt_mpc in 'formats\fmt_mpc.pas'
+,fmt_ofr in 'formats\fmt_ofr.pas'
+,fmt_tta in 'formats\fmt_tta.pas'
+,fmt_real in 'formats\fmt_real.pas'
+,fmt_ape in 'formats\fmt_ape.pas'
+,fmt_wav in 'formats\fmt_wav.pas'
+,fmt_flv in 'formats\fmt_flv.pas'
+,fmt_aac in 'formats\fmt_aac.pas'
+,fmt_mkv in 'formats\fmt_mkv.pas'
+,fmt_m4a in 'formats\fmt_m4a.pas'
+,fmt_wma in 'formats\fmt_wma.pas'
+,fmt_avi in 'formats\fmt_avi.pas'
+,fmt_ogg in 'formats\fmt_ogg.pas'
+,fmt_mp3 in 'formats\fmt_mp3.pas'
+,tags in 'formats\tags.pas'
diff --git a/plugins/Watrack/lst_players.inc b/plugins/Watrack/lst_players.inc
new file mode 100644
index 0000000000..759b06cf51
--- /dev/null
+++ b/plugins/Watrack/lst_players.inc
@@ -0,0 +1,17 @@
+,pl_apollo in 'players\pl_apollo.pas'
+,pl_behold in 'players\pl_behold.pas'
+,pl_mradio in 'players\pl_mradio.pas'
+,pl_lastfm in 'players\pl_lastfm.pas'
+,pl_1by1 in 'players\pl_1by1.pas'
+,pl_bs in 'players\pl_bs.pas'
+,pl_la in 'players\pl_la.pas'
+,pl_mmonkey in 'players\pl_mmonkey.pas'
+,pl_itunes in 'players\pl_itunes.pas'
+,pl_cowon in 'players\pl_cowon.pas'
+,pl_vlc in 'players\pl_vlc.pas'
+// keep file for check in future
+//,pl_wmp in 'players\pl_wmp.pas'
+,pl_mpc in 'players\pl_mpc.pas'
+,pl_aimp in 'players\pl_aimp.pas'
+,pl_foobar in 'players\pl_foobar.pas'
+,pl_winamp in 'players\pl_winamp.pas'
diff --git a/plugins/Watrack/m_music.inc b/plugins/Watrack/m_music.inc
new file mode 100644
index 0000000000..aba0bd27f6
--- /dev/null
+++ b/plugins/Watrack/m_music.inc
@@ -0,0 +1,419 @@
+{$IFNDEF M_MUSIC}
+{$DEFINE M_MUSIC}
+
+// defined in interfaces.inc
+//const MIID_WATRACK:MUUID='{FC6C81F4-837E-4430-9601-A0AA43177AE3}';
+
+type
+ pSongInfoA = ^tSongInfoA;
+ tSongInfoA = record
+ artist :PAnsiChar;
+ title :PAnsiChar;
+ album :PAnsiChar;
+ genre :PAnsiChar;
+ comment :PAnsiChar;
+ year :PAnsiChar;
+ mfile :PAnsiChar; // media file
+ kbps :dword;
+ khz :dword;
+ channels :dword;
+ track :dword;
+ total :dword; // music length
+ time :dword; // elapsed time
+ wndtext :PAnsiChar; // window title
+ player :PAnsiChar; // player name
+ plyver :dword; // player version
+ icon :THANDLE; // player icon
+ fsize :dword; // media file size
+ vbr :dword;
+ status :integer; // WAT_MES_* const
+ plwnd :HWND; // player window
+ // video part
+ codec :dword;
+ width :dword;
+ height :dword;
+ fps :dword;
+ date :int64;
+ txtver :PAnsiChar;
+ lyric :PAnsiChar;
+ cover :PAnsiChar;
+ volume :dword;
+ url :PAnsiChar; // player homepage
+ winampwnd:HWND;
+ end;
+type
+ pSongInfo=^tSongInfo;
+ tSongInfo = record
+ artist :pWideChar;
+ title :pWideChar;
+ album :pWideChar;
+ genre :pWideChar;
+ comment :pWideChar;
+ year :pWideChar;
+ mfile :pWideChar; // media file
+ kbps :dword;
+ khz :dword;
+ channels :dword;
+ track :dword;
+ total :dword; // music length
+ time :dword; // elapsed time
+ wndtext :pWideChar; // window title
+ player :pWideChar; // player name
+ plyver :dword; // player version
+ icon :THANDLE; // player icon
+ fsize :dword; // media file size
+ vbr :dword;
+ status :integer; // WAT_MES_* const
+ plwnd :HWND; // player window
+ // video part
+ codec :dword;
+ width :dword;
+ height :dword;
+ fps :dword;
+ date :int64;
+ txtver :pWideChar;
+ lyric :pWideChar;
+ cover :pWideChar; // cover path
+ volume :dword;
+ url :PWideChar; // player homepage
+ winampwnd:HWND;
+ end;
+ pSongInfoW = pSongInfo;
+ tSongInfoW = tSongInfo;
+
+const
+ // result codes
+ WAT_RES_UNKNOWN = -2;
+ WAT_RES_NOTFOUND = -1;
+ WAT_RES_ERROR = WAT_RES_NOTFOUND;
+ WAT_RES_OK = 0;
+ WAT_RES_ENABLED = WAT_RES_OK;
+ WAT_RES_DISABLED = 1;
+ // internal
+ WAT_RES_NEWFILE = 3;
+ WAT_RES_NEWPLAYER = 4;
+
+// result for MS_WAT_GETMUSICINFO service
+const
+ WAT_PLS_NORMAL = WAT_RES_OK;
+ WAT_PLS_NOMUSIC = WAT_RES_DISABLED;
+ WAT_PLS_NOTFOUND = WAT_RES_NOTFOUND;
+
+const
+ WAT_INF_UNICODE = 0;
+ WAT_INF_ANSI = 1;
+ WAT_INF_UTF8 = 2;
+ WAT_INF_CHANGES = $100;
+
+const
+ MS_WAT_INSERT:PAnsiChar = 'WATrack/Insert';
+ MS_WAT_EXPORT:PAnsiChar = 'WATrack/Export';
+
+const
+{
+ wParam : WAT_INF_* constant
+ lParam : pointer to pSongInfo (Unicode) or pSongInfoA (ANSI/UTF8)
+ Affects: Fill structure by currently played music info
+ returns: WAT_PLS_* constant
+ note: pointer will be point to global SongInfo structure of plugin
+ warning: Non-Unicode data filled only by request
+ if lParam=0 only internal SongInfo structure will be filled
+ Example:
+ var p:pSongInfo;
+ CallService(MS_WAT_GETMUSICINFO,0,dword(@p));
+}
+ MS_WAT_GETMUSICINFO:PAnsiChar = 'WATrack/GetMusicInfo';
+{
+ wParam:0
+ lParam : pointer to pSongInfo (Unicode)
+ Affects: Fill structure by info from file named in SongInfo.mfile
+ returns: 0, if success
+ note: fields, which values can't be obtained, leaves old values.
+ you must free given strings by miranda mir_free
+}
+ MS_WAT_GETFILEINFO:PAnsiChar = 'WATrack/GetFileInfo';
+
+{
+ wParam: encoding (WAT_INF_* consts, 0 = WAT_INF_UNICODE)
+ lParam: codepage (0 = ANSI)
+ Returns Global unicode SongInfo pointer or tranlated to Ansi/UTF8 structure
+}
+ MS_WAT_RETURNGLOBAL:PAnsiChar = 'WATrack/GetMainStructure';
+
+//!! DON'T CHANGE THESE VALUES!
+const
+ WAT_CTRL_FIRST = 1;
+
+ WAT_CTRL_PREV = 1;
+ WAT_CTRL_PLAY = 2;
+ WAT_CTRL_PAUSE = 3;
+ WAT_CTRL_STOP = 4;
+ WAT_CTRL_NEXT = 5;
+ WAT_CTRL_VOLDN = 6;
+ WAT_CTRL_VOLUP = 7;
+ WAT_CTRL_SEEK = 8; // lParam is new position (sec)
+
+ WAT_CTRL_LAST = 8;
+
+{
+ wParam: button code (WAT_CTRL_* const)
+ lParam: 0, or value (see WAT_CTRL_* const comments)
+ Affects: emulate player button pressing
+ returns: 0 if unsuccesful
+}
+ MS_WAT_PRESSBUTTON:PAnsiChar = 'WATrack/PressButton';
+
+{
+ Get user's Music Info
+}
+ MS_WAT_GETCONTACTINFO:PAnsiChar = 'WATrack/GetContactInfo';
+
+// ------------ Plugin/player status ------------
+
+{
+ wParam: 1 - switch off plugin
+ 0 - switch on plugin
+ -1 - switch plugin status
+ 2 - get plugin version
+ other - get plugin status
+ lParam: 0
+ Affects: Switch plugin status to enabled or disabled
+ returns: version, old plugin status, 0, if was enabled
+}
+ MS_WAT_PLUGINSTATUS:PAnsiChar = 'WATrack/PluginStatus';
+
+ ME_WAT_MODULELOADED:PAnsiChar = 'WATrack/ModuleLoaded';
+
+const
+ WAT_EVENT_PLAYERSTATUS = 1; // WAT_PLS_* in loword, WAT_MES_* in hiword
+ WAT_EVENT_NEWTRACK = 2; // SongInfo ptr
+ WAT_EVENT_PLUGINSTATUS = 3; // 0-enabled; 1-dis.temporary; 2-dis.permanent
+ WAT_EVENT_NEWPLAYER = 4; //
+ WAT_EVENT_NEWTEMPLATE = 5; // TM_* constant
+
+{
+ Plugin or player status changed:
+ wParam: type of event (see above)
+ lParam: value
+}
+ ME_WAT_NEWSTATUS:PAnsiChar = 'WATrack/NewStatus';
+
+// ---------- Popup module ------------
+
+{
+ wParam: not used
+ lParam: not used
+ Affects: Show popup or Info window with current music information
+ note: Only Info window will be showed if Popup plugin disabled
+}
+ MS_WAT_SHOWMUSICINFO:PAnsiChar = 'WATrack/ShowMusicInfo';
+
+// --------- Statistic (report) module -------------
+
+{
+ wParam: pointer to log file name or NIL
+ lParam: pointer to report file name or NIL
+ Affects: Create report from log and run it (if option is set)
+ returns: 0 if unsuccesful
+ note: if wParam or lParam is a NIL then file names from options are used
+}
+ MS_WAT_MAKEREPORT :PAnsiChar = 'WATrack/MakeReport';
+// MS_WAT_MAKEREPORTW:PAnsiChar = 'WATrack/MakeReportW';
+
+{
+ wParam, lParam - not used
+ Affects: pack statistic file
+}
+ MS_WAT_PACKLOG:PAnsiChar = 'WATrack/PackLog';
+
+{
+ wParam: not used
+ lParam: pointer to SongInfo
+}
+ MS_WAT_ADDTOLOG:PAnsiChar = 'WATrack/AddToLog';
+
+// ----------- Formats and players -----------
+
+// media file status
+
+const
+ WAT_MES_STOPPED = 0;
+ WAT_MES_PLAYING = 1;
+ WAT_MES_PAUSED = 2;
+ WAT_MES_UNKNOWN = -1;
+
+const
+ WAT_ACT_REGISTER = 1;
+ WAT_ACT_UNREGISTER = 2;
+ WAT_ACT_DISABLE = 3;
+ WAT_ACT_ENABLE = 4;
+ WAT_ACT_GETSTATUS = 5; // not found/enabled/disabled
+ WAT_ACT_SETACTIVE = 6;
+ WAT_ACT_REPLACE = $10000; // can be combined with WAT_REGISTERFORMAT
+
+const
+ // flags
+ WAT_OPT_DISABLED = $00000001; // [formats,players,options] registered but disabled
+ WAT_OPT_ONLYONE = $00000002; // [formats,players] code can't be overwriten
+ WAT_OPT_PLAYERINFO = $00000004; // [players] song info from player
+ WAT_OPT_WINAMPAPI = $00000008; // [players] Winamp API support
+ WAT_OPT_CHECKTIME = $00000010; // [options] check file time for changes
+ WAT_OPT_VIDEO = $00000020; // [formats,options] format is video
+ WAT_OPT_LAST = $00000040; // (internal-Winamp Clone) put to the end of queue
+ WAT_OPT_FIRST = $00000080; // (internal)
+ WAT_OPT_TEMPLATE = $00000100; // (internal)
+ WAT_OPT_IMPLANTANT = $00000200; // [options] use process implantation
+ WAT_OPT_HASURL = $00000400; // [players] URL field present
+ WAT_OPT_CHANGES = $00000800; // (internal) obtain only chaged values
+ // (volume, status, window text, elapsed time)
+ WAT_OPT_APPCOMMAND = $00001000; // [options] Special (multimedia) key support
+ WAT_OPT_CHECKALL = $00002000; // [options] Check all players
+ WAT_OPT_KEEPOLD = $00004000; // [options] Keep Old opened file
+ WAT_OPT_MULTITHREAD = $00008000; // [options] Use multithread scan
+ WAT_OPT_SINGLEINST = $00010000; // [players] Single player instance
+ WAT_OPT_PLAYERDATA = $00020000; // (internal) to obtain player data
+ WAT_OPT_CONTAINER = $00040000; // [formats] format is container (need to check full)
+
+type
+ tReadFormatProc = function(var Info:tSongInfo):boolean; cdecl;
+ pMusicFormat = ^tMusicFormat;
+ tMusicFormat = record
+ proc :tReadFormatProc;
+ ext :array [0..7] of AnsiChar;
+ flags:cardinal;
+ end;
+
+const
+{
+ wParam: action
+ lParam: pointer to tMusicFormat if wParam = WAT_ACT_REGISTER,
+ else - pointer to extension string (ANSI)
+ returns: see result codes
+}
+ MS_WAT_FORMAT:PAnsiChar = 'WATrack/Format';
+
+{
+ wParam: pointer to SongInfo structure (plwind field must be initialized)
+ lParam: flags
+ Affects: trying to fill SongInfo using Winamp API
+}
+ MS_WAT_WINAMPINFO:PAnsiChar = 'WATrack/WinampInfo';
+
+{
+ wParam: window
+ lParam: LoWord - command; HiWord - value
+}
+ MS_WAT_WINAMPCOMMAND:PAnsiChar = 'WATrack/WinampCommand';
+
+type
+ tInitProc = function():integer;cdecl;
+ tDeInitProc = function():integer;cdecl;
+ tStatusProc = function(wnd:HWND):integer;cdecl;
+ tNameProc = function(wnd:HWND;flags:integer):pWideChar;cdecl;
+ tCheckProc = function(wnd:HWND;flags:integer):HWND;cdecl;
+ tInfoProc = function(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+ tCommandProc = function(wnd:HWND;command:integer;value:integer):integer;cdecl;
+
+ pPlayerCell = ^tPlayerCell;
+ tPlayerCell = record
+ Desc :PAnsiChar; // Short player name
+ flags :cardinal;
+ Icon :HICON; // can be 0. for registration only
+ Init :pointer; // tInitProc; can be NIL. initialize any data
+ DeInit :pointer; // tDeInitProc; can be NIL. finalize player processing
+ Check :pointer; // tCheckProc; check player
+ GetStatus:pointer; // tStatusProc; can be NIL. get player status
+ GetName :pointer; // tNameProc; can be NIL. get media filename
+ GetInfo :pointer; // tInfoProc; can be NIL. get info from player
+ Command :pointer; // tCommandProc; can be NIL. send command to player
+ URL :PAnsiChar; // only if WAT_OPT_HASURL flag present
+ Notes :PWideChar; // any tips, notes etc for this player
+ end;
+
+const
+{
+ wParam: action
+ lParam: pointer to tPlayerCell if wParam = WAT_ACT_REGISTER,
+ else - pointer to player description string (ANSI)
+ returns: player window handle or value>0 if found
+ note: If you use GetName or GetInfo field, please, do not return empty
+ filename even when mediafile is remote!
+}
+ MS_WAT_PLAYER:PAnsiChar = 'WATrack/Player';
+
+// --------- MyShows.ru ---------
+
+{
+ Toggle MyShows scrobbling status
+ wParam,lParam=0
+ Returns: previous state
+}
+const
+ MS_WAT_MYSHOWS:pAnsiChar = 'WATrack/MyShows';
+
+
+const
+ MS_WAT_MYSHOWSINFO:pAnsiChar = 'WATrack/MyShowsInfo';
+
+// --------- Last FM ---------
+
+{
+ Toggle LastFM scrobbling status
+ wParam,lParam=0
+ Returns: previous state
+}
+const
+ MS_WAT_LASTFM:pAnsiChar = 'WATrack/LastFM';
+
+{
+ Get Info based on currently played song
+ wParam: pLastFMInfo
+ lParam: int language (first 2 bytes - 2-letters language code)
+}
+type
+ pLastFMInfo = ^tLastFMInfo;
+ tLastFMInfo = record
+ request:cardinal; // 0 - artist, 1 - album, 2 - track
+ artist :pWideChar; // artist
+ album :pWideChar; // album or similar artists for Artist info request
+ title :pWideChar; // track title
+ tags :pWideChar; // tags
+ info :pWideChar; // artist bio or wiki article
+ image :pAnsiChar; // photo/cover link
+ similar:pWideChar;
+ release:pWideChar;
+ trknum :cardinal;
+ end;
+const
+ MS_WAT_LASTFMINFO:pAnsiChar = 'WATrack/LastFMInfo';
+
+// --------- Templates ----------
+
+const
+{
+ wParam: 0 (standard Info) or pSongInfo
+ lParam: Unicode template
+ returns: New Unicode (replaced) string
+}
+ MS_WAT_REPLACETEXT:PAnsiChar = 'WATrack/ReplaceText';
+
+{
+ event types for History
+ Blob structure for EVENTTYPE_WAT_ANSWER:
+ Uniciode artist#0title#0album#0answer
+}
+const
+ EVENTTYPE_WAT_REQUEST = 9601;
+ EVENTTYPE_WAT_ANSWER = 9602;
+ EVENTTYPE_WAT_ERROR = 9603;
+ EVENTTYPE_WAT_MESSAGE = 9604;
+
+const
+{
+ wParam: 0 or parent window
+ lParam: 0
+ note: Shows Macro help window with edit aliases ability
+}
+ MS_WAT_MACROHELP:pAnsiChar = 'WATrack/MacroHelp';
+
+{$ENDIF M_MUSIC}
diff --git a/plugins/Watrack/macros.pas b/plugins/Watrack/macros.pas
new file mode 100644
index 0000000000..cdbe52991e
--- /dev/null
+++ b/plugins/Watrack/macros.pas
@@ -0,0 +1,93 @@
+{to Variables plugin and Help dialog}
+unit macros;
+
+interface
+
+type
+ pvar = ^tvar;
+ tvar = packed record
+ name :PWideChar;
+ alias:PWideChar;
+ help :PAnsiChar;
+ end;
+
+// --- data ---
+const
+ numvars = 35;
+
+ mn_wndtext = 0;
+ mn_artist = 1;
+ mn_title = 2;
+ mn_album = 3;
+ mn_genre = 4;
+ mn_file = 5;
+ mn_kbps = 6;
+ mn_bitrate = 7;
+ mn_track = 8;
+ mn_channels = 9;
+ mn_mono = 10;
+ mn_khz = 11;
+ mn_samplerate = 12;
+ mn_total = 13;
+ mn_length = 14;
+ mn_year = 15;
+ mn_time = 16;
+ mn_percent = 17;
+ mn_comment = 18;
+ mn_player = 19;
+ mn_version = 20;
+ mn_size = 21;
+ mn_type = 22;
+ mn_vbr = 23;
+ mn_status = 24;
+ mn_fps = 25;
+ mn_codec = 26;
+ mn_width = 27;
+ mn_height = 28;
+ mn_txtver = 29;
+ mn_lyric = 30;
+ mn_cover = 31;
+ mn_volume = 32;
+ mn_playerhome = 33;
+ mn_nstatus = 34;
+ vars:array [0..numvars-1] of tvar = (
+{00} (name:'wndtext' ;alias:nil;help:'player window title'),
+{01} (name:'artist' ;alias:nil;help:'artist'),
+{02} (name:'title' ;alias:nil;help:'song title'),
+{03} (name:'album' ;alias:nil;help:'album'),
+{04} (name:'genre' ;alias:nil;help:'genre'),
+{05} (name:'file' ;alias:nil;help:'media file name'),
+{06} (name:'kbps' ;alias:nil;help:'bitrate'),
+{07} (name:'bitrate' ;alias:nil;help:nil),
+{08} (name:'track' ;alias:nil;help:'track number'),
+{09} (name:'channels' ;alias:nil;help:'number of channels'),
+{10} (name:'mono' ;alias:nil;help:'"mono"/"stereo"'),
+{11} (name:'khz' ;alias:nil;help:'samplerate'),
+{12} (name:'samplerate';alias:nil;help:nil),
+{13} (name:'total' ;alias:nil;help:'total song length (sec)'),
+{14} (name:'length' ;alias:nil;help:nil),
+{15} (name:'year' ;alias:nil;help:'song year (date)'),
+{16} (name:'time' ;alias:nil;help:'current song position (sec)'),
+{17} (name:'percent' ;alias:nil;help:'time/length * 100%'),
+{18} (name:'comment' ;alias:nil;help:'comment from tag'),
+{19} (name:'player' ;alias:nil;help:'player name'),
+{20} (name:'version' ;alias:nil;help:'player version'),
+{21} (name:'size' ;alias:nil;help:'media file size'),
+{22} (name:'type' ;alias:nil;help:'media file type'),
+{23} (name:'vbr' ;alias:nil;help:'VBR or not (empty)'),
+{24} (name:'status' ;alias:nil;help:'player status (stopped,playing,paused)'),
+{25} (name:'fps' ;alias:nil;help:'FPS (frames per second), video only'),
+{26} (name:'codec' ;alias:nil;help:'codec, video only'),
+{27} (name:'width' ;alias:nil;help:'width, video only'),
+{28} (name:'height' ;alias:nil;help:'height, video only'),
+{29} (name:'txtver' ;alias:nil;help:'player version in text format'),
+{30} (name:'lyric' ;alias:nil;help:'Lyric from ID3v2 tag'),
+{31} (name:'cover' ;alias:nil;help:'Cover file path'),
+{32} (name:'volume' ;alias:nil;help:'Player volume (0-15)'),
+{33} (name:'playerhome';alias:nil;help:'Player homepage URL'),
+{34} (name:'nstatus' ;alias:nil;help:'player status (not translated)')
+ );
+
+implementation
+
+end. \ No newline at end of file
diff --git a/plugins/Watrack/make.bat b/plugins/Watrack/make.bat
new file mode 100644
index 0000000000..cfaf1df3e1
--- /dev/null
+++ b/plugins/Watrack/make.bat
@@ -0,0 +1,26 @@
+@echo off
+set myopts=-dMiranda
+set dprname=watrack.dpr
+
+..\delphi\brcc32.exe res\watrack.rc -fores\watrack.res
+..\delphi\brcc32.exe lastfm\lastfm.rc -folastfm\lastfm.res
+..\delphi\brcc32.exe myshows\myshows.rc -fomyshows\myshows.res
+..\delphi\brcc32.exe players\mradio.rc -foplayers\mradio.res
+..\delphi\brcc32.exe kolframe\frm.rc -fokolframe\frm.res
+..\delphi\brcc32.exe popup\popup.rc -fopopup\popup.res
+..\delphi\brcc32.exe proto\proto.rc -foproto\proto.res
+..\delphi\brcc32.exe stat\stat.rc -fostat\stat.res
+..\delphi\brcc32.exe status\status.rc -fostatus\status.res
+..\delphi\brcc32.exe templates\templates.rc -fotemplates\templates.res
+
+if /i '%1' == 'fpc' (
+ ..\FPC\bin\fpc.exe %myopts% %dprname% %2 %3 %4 %5 %6 %7 %8 %9
+) else if /i '%1' == 'fpc64' (
+ ..\FPC\bin64\ppcrossx64.exe %myopts% %dprname% %2 %3 %4 %5 %6 %7 %8 %9
+) else if /i '%1' == 'xe2' (
+ ..\XE2\BIN\dcc32.exe%myopts% %dprname% %2 %3 %4 %5 %6 %7 %8 %9
+) else if /i '%1' == 'xe64' (
+ ..\XE2\BIN\dcc64.exe %myopts% %dprname% %2 %3 %4 %5 %6 %7 %8 %9
+) else (
+ ..\delphi\dcc32 -b -dKOL_MCK -dUNICODE_CTRLS %myopts% %dprname% %1 %2 %3 %4 %5 %6 %7 %8 %9
+)
diff --git a/plugins/Watrack/myrtf.pas b/plugins/Watrack/myrtf.pas
new file mode 100644
index 0000000000..7a6bf2255f
--- /dev/null
+++ b/plugins/Watrack/myrtf.pas
@@ -0,0 +1,219 @@
+{RTF related code}
+unit MyRTF;
+{$include compilers.inc}
+
+interface
+uses windows;
+
+procedure SendRTF(wnd:hwnd;txt:PWideChar;isUnicode:Boolean;CP:integer=CP_ACP);
+
+implementation
+uses richedit,common,messages,m_api;
+
+const
+ RTFBufferSize = 16384;
+const
+ CTableHdr = '{\colortbl';
+const
+(*
+ ColorTable = '{\colortbl;'+
+ '\red255\green255\blue255;'+
+ '\red0\green0\blue0;'+
+ '\red0\green0\blue127;'+
+ '\red0\green147\blue0;'+
+ '\red255\green0\blue0;'+
+ '\red127\green0\blue0;'+
+ '\red156\green0\blue156;'+
+ '\red252\green127\blue0;'+
+ '\red255\green255\blue0;'+
+ '\red0\green252\blue0;'+
+ '\red0\green147\blue147;'+
+ '\red0\green255\blue255;'+
+ '\red0\green0\blue252;'+
+ '\red255\green0\blue255;'+
+ '\red127\green127\blue127;'+
+ '\red210\green210\blue210;}';
+*)
+ ColorTableD =
+ '\red255\green255\blue255;'+
+ '\red0\green0\blue0;'+
+ '\red0\green0\blue127;'+
+ '\red0\green147\blue0;'+
+ '\red255\green0\blue0;'+
+ '\red127\green0\blue0;'+
+ '\red156\green0\blue156;'+
+ '\red252\green127\blue0;'+
+ '\red255\green255\blue0;'+
+ '\red0\green252\blue0;'+
+ '\red0\green147\blue147;'+
+ '\red0\green255\blue255;'+
+ '\red0\green0\blue252;'+
+ '\red255\green0\blue255;'+
+ '\red127\green127\blue127;'+
+ '\red210\green210\blue210;';
+
+function StreamWriteCallback(dwCookie:dword_ptr;pbBuff:PAnsiChar;cb:long;var pcb:long):dword;stdcall;
+begin
+ pcb:=StrLen(PAnsiChar(dwCookie));
+ if cb<pcb then pcb:=cb;
+ move(PAnsiChar(dwCookie)^,pbBuff^,pcb);
+ result:=0;
+end;
+
+procedure WriteRTF(wnd:hwnd;const pszText:PAnsiChar);
+var
+ stream:TEDITSTREAM;
+begin
+ FillChar(stream,SizeOf(stream),0);
+ stream.pfnCallback:=@StreamWriteCallback;
+ stream.dwCookie :=dword_ptr(pszText);
+ SendMessage(wnd,EM_STREAMIN,SF_RTF or SFF_PLAINRTF or SFF_SELECTION,lparam(@stream));
+end;
+
+function StreamReadCallback(dwCookie:dword_ptr;pbBuff:PAnsiChar;cb:long;var pcb:long):dword;stdcall;
+type
+ pdword_ptr=^dword_ptr;
+begin
+ pcb:=cb;
+ move(pbBuff^,PAnsiChar(pdword_ptr(dwCookie)^)^,pcb);
+// PAnsiChar(pdword(dwCookie)^)[pcb]:=#0;
+ result:=0;
+end;
+
+procedure ReadRTF(wnd:hwnd;var dst:PAnsiChar);
+var
+ stream:TEDITSTREAM;
+begin
+ FillChar(stream,SizeOf(stream),0);
+ stream.pfnCallback:=@StreamReadCallback;
+ stream.dwCookie:=dword_ptr(@dst);
+ SendMessage(wnd,EM_STREAMOUT,SF_RTF+SFF_SELECTION,lparam(@stream));
+end;
+
+procedure ReplaceTag(src:PAnsiChar;what,new:PAnsiChar;recurse:boolean);
+var
+ i:integer;
+ block:boolean;
+ p:pAnsiChar;
+begin
+ block:=what^='{';
+ repeat
+ p:=StrPos(src,what);
+ if p<>nil then
+ begin
+ src:=p;
+ if src[StrLen(what)] in ['A'..'Z','a'..'z'] then
+ begin
+ inc(src);
+ continue;
+ end;
+ i:=1;
+ if block then
+ begin
+ while src[i]<>'}' do inc(i); inc(i);
+ end
+ else
+ begin
+ while not (src[i] in ['}',' ','\',';',#13]) do
+ inc(i);
+ end;
+ StrCopy(src,src+i);
+ if new<>nil then
+ StrInsert(new,src,0);
+ end
+ else
+ break;
+ if not recurse then break;
+ until false;
+end;
+
+procedure ReplaceTags(var src:PAnsiChar);
+var
+ i:integer;
+begin
+ ReplaceTag(src,'\b' ,nil,false);
+ ReplaceTag(src,'\i' ,nil,false);
+ ReplaceTag(src,'\ul' ,nil,false);
+ if (StrPos(src,'\{cf')<>nil) or (StrPos(src,'\{bg')<>nil) then
+ begin
+ ReplaceTag(src,'\cf' ,nil,false);
+ ReplaceTag(src,'\highlight',nil,false);
+ StrReplace(src,'\{/cf\}','\cf17 ');
+ StrReplace(src,'\{/bg\}','\highlight0 ');
+ i:=StrIndex(src,CTableHdr);
+ StrInsert(ColorTableD,src,i+integer(StrLen(CTableHdr))+1);
+ ReplaceTag(src,'\pard','\pard\cf17',false);
+ end;
+
+ StrReplace(src,'\{b\}' ,'\b1 ');
+ StrReplace(src,'\{/b\}' ,'\b0 ');
+ StrReplace(src,'\{i\}' ,'\i1 ');
+ StrReplace(src,'\{/i\}' ,'\i0 ');
+ StrReplace(src,'\{u\}' ,'\ul ');
+ StrReplace(src,'\{/u\}' ,'\ul0 ');
+
+ repeat
+ i:=StrIndex(src,'\{cf');
+ if i>0 then
+ begin
+ StrCopy(src+i,src+i+1);
+ i:=StrIndex(src,'\}');
+ if i>0 then
+ begin
+ StrCopy(src+i,src+i+1);
+ src[i-1]:=' ';
+ end;
+ end;
+ until i=0;
+ repeat
+ i:=StrIndex(src,'\{bg');
+ if i>0 then
+ begin
+ StrCopy(src+i,src+i+3);
+ StrInsert('highlight',src,i);
+ i:=StrIndex(src,'\}');
+ if i>0 then
+ begin
+ StrCopy(src+i,src+i+1);
+ src[i-1]:=' ';
+ end;
+ end;
+ until i=0;
+end;
+
+function CharCount(p:PWideChar):integer;
+begin
+ result:=0;
+ while p^<>#0 do
+ begin
+ if p^=#10 then inc(result);
+ inc(p);
+ end;
+end;
+
+procedure SendRTF(wnd:hwnd;txt:PWideChar;isUnicode:Boolean;CP:integer=CP_ACP);
+var
+ tmp:PAnsiChar;
+ sstart:integer;
+ ls:PAnsiChar;
+begin
+ SendMessage(wnd,EM_GETSEL,wparam(@sstart),0);
+ if isUnicode then
+ SendMessagew(wnd,EM_REPLACESEL,0,lparam(txt))
+ else
+ begin
+ SendMessageA(wnd,EM_REPLACESEL,0,lparam(WideToAnsi(txt,ls,CP)));
+ mFreeMem(ls);
+ end;
+
+ SendMessage(wnd,EM_SETSEL,sstart,sstart+integer(StrLenW(txt))-CharCount(txt));
+ mGetMem(tmp,RTFBufferSize);
+ FillChar(tmp^,RTFBufferSize,0);
+ ReadRTF(wnd,tmp);
+ ReplaceTags(tmp);
+ WriteRTF(wnd,tmp);
+ mFreeMem(tmp);
+ SendMessage(wnd,EM_SETSEL,-1,0);
+end;
+
+end.
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
diff --git a/plugins/Watrack/player.ini b/plugins/Watrack/player.ini
new file mode 100644
index 0000000000..16572c983e
--- /dev/null
+++ b/plugins/Watrack/player.ini
@@ -0,0 +1,283 @@
+;[name]
+;text0= for stopped (empty) player?
+;class=
+;text=
+;class1=
+;text1=
+;file=
+;flags=
+;url=
+;notes=
+;
+;prefix=
+;postfix=
+
+[ALShow]
+class='ALShowShellWindow'
+class1='ALShowMainWindow'
+url='http://www.altools.net/'
+[ALSong]
+class='ALSongKernelWindow'
+url='http://www.altools.net/'
+
+[ArezMedia]
+text='ArezMedia v8.1'
+class1='Media Event Sink Window'
+text1='Media Event Sink Window'
+file='AREZMEDIA.EXE'
+url='http://www.arezsoft.co.uk/'
+
+[Ashampoo Media Player]
+test='Ashampoo Media Player+'
+class='AMPMainWindow class'
+class1='AMP MainOwnerWindow Class'
+url='http://www2.ashampoo.com/webcache/html/1/product_2_0014___USD.htm'
+
+[AudioPlayer]
+class='AudioPlayer'
+url='http://audioplayer.sourceforge.net/'
+
+[Billy]
+class='TAppBilly'
+url='http://sheepfriends.com/?page=billy'
+
+[BizzOn]
+class='BizzOn v2.x'
+flags=8
+url='http://bizzon.nm.ru/'
+
+[Core Media Player]
+class='TApplication'
+file='COREPLAYER.EXE'
+url='http://www.tcmp.org/'
+
+[Creative Media Source]
+class='CT_MEDIASOURCE'
+url='http://www.creative.com/'
+
+[Crystal Player]
+class='CrystalPlayerClass'
+class1='CrystalClassOwner'
+url='http://crystalplayer.com/'
+
+[Cyberlink PowerDVD]
+class='Class of CyberLink Universal Player'
+text='CommandWindow'
+url='http://www.cyberlink.com/'
+
+[Daum PotPlayer]
+class='PotPlayer'
+notes='"Daum PotPlayer" text for stopped player?'
+
+[dBpowerAMP]
+class='dBpowerAMP Audio Player'
+text='dBpowerAMP Audio Player'
+class1='dBpowerAMP Core'
+text1='dBpowerAMP Core'
+url='http://www.dbpoweramp.com/'
+
+[Evil Player]
+class='TApplication'
+text='Evil Player'
+;title: Evil Player - 00:00 / 00:00
+;class='TForm1'
+;file='EVIL_PLAYER.EXE'
+url='http://www.hakeem.gigahost.dk/'
+
+[FLVPlayer]
+text='SW3 Player Engine [ Debug Window ]'
+url='http://www.martijndevisser.com/'
+
+;Fucker Player
+[FPlayer]
+class='TForm1'
+class1='TApplication'
+file='FPLAYER 3.0.EXE'
+url='http://www.kuzbassproduction.narod.ru/'
+
+[Freebox player]
+class='ThunderRT6FormDC'
+text='Freebox Player'
+class1='ThunderRT6Main'
+text1='MP3 Freebox'
+url='http://www.freeboxjukebox.com/'
+
+[J.River Media Center]
+class='MJFrame'
+class1='J. River Display Window'
+url='http://www.jrmediacenter.com/'
+
+[HKDC]
+text='HKDC_HangWnd'
+file='HKDC.exe'
+
+[Helium Music Manager]
+class='THeliumMainForm'
+url='http://www.helium-music-manager.com/'
+
+[IPOP GOMPlayer]
+class='GomPlayer1.x'
+url='http://gomplayer.com/'
+
+[KMPlayer]
+class='TApplication'
+file='KMPLAYER.EXE'
+flags=8
+url='http://www.kmplayer.com'
+Notes='Winamp API used to get more info'
+
+[MPlayer]
+class='MPlayer - The Movie Player'
+url='http://www.mplayerhq.hu/'
+
+[Media Commander Express]
+class='TApplication'
+file='MCX.EXE'
+url='http://skynet.hut1.ru/'
+
+[Media Library Master]
+class='TMainForm'
+class1='TApplication'
+file='MLMASTER.EXE'
+url='http://www.grafmstudio.narod.ru/mlmaster.htm'
+
+[MoreAmp]
+class='wxWindowClassNR'
+file='MOREAMP.EXE'
+url='http://sourceforge.net/projects/moreamp/'
+
+[MusicCube One]
+class='TfMain'
+text='MusicCubeOne'
+prefix='MusicCubeOne - '
+url='http://www.rodi.dk/musiccubeone'
+
+[Musicmatch Jukebox]
+class='MMJB:MAINWND'
+postfix=' - Musicmatch Jukebox'
+url='http://wwwp.musicmatch.com/'
+
+[MusikCube]
+class='musikCubeWindow1.0'
+postfix=']'
+url='http://www.musikcube.com/'
+
+[PlayNow]
+class='TForm1'
+file='Play Now!.exe'
+url='http://www.playnow.nightmail.ru/'
+
+[Pluton]
+class='TApplication'
+file='PLUTON.EXE'
+url='http://pluton.oss.ru/'
+
+[QCD]
+file='QMPLAYER.EXE'
+;file='QCDPLAYER.EXE'
+text='PlayerCanvas'
+flags=8
+url='http://quinnware.com/'
+
+[Quicktime Player]
+class='QuickTimePlayerMain'
+url='http://www.quicktime.com/'
+
+[RadLight]
+class='TVideoForm'
+class1='TApplication'
+file='RadLight.exe'
+url='http://radlight.da.ru/'
+
+[Real Player]
+class='GeminiWindowClass'
+prefix='RealPlayer: '
+url='http://www.real.com/'
+
+[SAPS]
+class='ThunderRT6Main'
+text='SAPS'
+file='SAPS.EXE'
+url='http://www.troupware.com/'
+
+[SongBird]
+class='SongbirdMessageWindow'
+url='http://songbirdnest.com/'
+
+[Spider Player]
+class='TSpiderMainForm'
+text='Spider Audio Player'
+class1='TApplication'
+;text1=%artist% - %title% 'Spider Player 1.80'
+file='SPIDER.EXE'
+url='http://spider-player.com/'
+
+[Storm Player Exotic]
+class='TMainStormForm'
+class1='TApplication'
+text1='Storm Player Exotic 2.0'
+url='http://splayer.nm.ru/'
+
+[Suamp]
+class='Suamp'
+class1='TApplication' ; with title (if scrolling)
+file='suamp.exe'
+url='http://www.suamp.ro/'
+
+[TotalMedia Theatre 3]
+text='ArcSoft TotalMedia Theatre 3'
+class='TotalMedia2FDVDPlayerFrame'
+
+[Ultra player]
+class='UltraPlayerMainWindowClass88667'
+url='http://www.ultraplayer.com/'
+
+[ViPlay]
+class='ViPlay3'
+url='http://www.urusoft.net/'
+
+[VUPlayer]
+class='VUPlayerClass'
+url='http://www.vuplayer.com/'
+
+[WiFiRadio Player]
+class='WasabiIPC_WiFi Radio'
+url='http://pspmx.com/wifiradio/'
+
+[WMP]
+class='WMPlayerApp'
+class1='Media Player 2'
+flags=69632
+url='http://www.microsoft.com/windows/windowsmedia/players.aspx'
+
+[WinDVD]
+class='WinDVDClass'
+;text='Player'
+url='http://www.intervideo.com/'
+
+[WxMusik]
+class='wxWindowClassNR'
+;text='wxMusik 0.4.2'
+file='WXMUSIK.EXE'
+url='http://musik.berlios.de/'
+
+[XAMP]
+class='TfrmMp3'
+class1='TApplication'
+text1='XAMP'
+;file='MP3.EXE'
+url='http://www.darksoftware.narod.ru/'
+
+[XMPlay]
+class='XMPLAY-MAIN'
+flags=8
+url='http://www.un4seen.com/'
+
+;[ZINF]
+;url='http://www.zinf.org/'
+
+[Zoom]
+class='TApplication'
+file='ZPLAYER.EXE'
+postfix=' - Zoom Player'
+url='http://www.inmatrix.com/'
diff --git a/plugins/Watrack/players/mradio.ico b/plugins/Watrack/players/mradio.ico
new file mode 100644
index 0000000000..7993fce57b
--- /dev/null
+++ b/plugins/Watrack/players/mradio.ico
Binary files differ
diff --git a/plugins/Watrack/players/mradio.rc b/plugins/Watrack/players/mradio.rc
new file mode 100644
index 0000000000..ce858cbe82
--- /dev/null
+++ b/plugins/Watrack/players/mradio.rc
@@ -0,0 +1,3 @@
+LANGUAGE 0,0
+
+ICO_MRADIO ICON "mradio.ico"
diff --git a/plugins/Watrack/players/mradio.res b/plugins/Watrack/players/mradio.res
new file mode 100644
index 0000000000..52d06f147d
--- /dev/null
+++ b/plugins/Watrack/players/mradio.res
Binary files differ
diff --git a/plugins/Watrack/players/pl_1by1.pas b/plugins/Watrack/players/pl_1by1.pas
new file mode 100644
index 0000000000..630b825363
--- /dev/null
+++ b/plugins/Watrack/players/pl_1by1.pas
@@ -0,0 +1,84 @@
+{1by1 player}
+unit pl_1by1;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,common,wrapper,srv_player,wat_api;
+
+const
+ ObOClass = '1by1WndClass';
+ ObOTitle = '1by1 - The Directory Player';
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow(ObOClass,NIL);
+end;
+
+{
+ need to set 'Elapsed time in title bar'
+ and 'Show : instead of ' as minute char'
+}
+function GetElapsedTime(wnd:HWND):integer;
+var
+ s,p:PAnsiChar;
+begin
+ result:=0;
+ s:=GetDlgText(wnd,true);
+ if s<>nil then
+ begin
+ if (s^>='0') and (s^<='9') then
+ begin
+ p:=StrScan(s,' ');
+ if p<>nil then
+ p^:=#0;
+ result:=TimeToInt(s)
+ end;
+ mFreeMem(s);
+ end;
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+begin
+ result:=0;
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ SongInfo.time:=GetElapsedTime(SongInfo.plwnd);
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'1by1';
+ flags :WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:nil;
+ GetName :nil;
+ GetInfo :@GetInfo;
+ Command :nil;
+ URL :'http://www.mpesch3.de/';
+ Notes :'To get elapsed time, needs to set "Elapsed time in title bar" and '#13#10+
+ '"Show : instead of '#39' as minute char" in player settings "Display" tab.'
+);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_aimp.pas b/plugins/Watrack/players/pl_aimp.pas
new file mode 100644
index 0000000000..17c52bc5b6
--- /dev/null
+++ b/plugins/Watrack/players/pl_aimp.pas
@@ -0,0 +1,376 @@
+{AIMP player}
+unit pl_AIMP;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,messages,common,srv_player,wat_api,winampapi;
+
+const
+ WM_AIMP_COMMAND = WM_USER + $75;
+ WM_AIMP_GET_VERSION = 4;
+ WM_AIMP_STATUS_GET = 1;
+ WM_AIMP_STATUS_SET = 2;
+ WM_AIMP_CALLFUNC = 3;
+const
+ AIMP_STS_Player = 4;
+ AIMP_STS_VOLUME = 1;
+ AIMP_STS_POS = 31;
+const
+ AIMP_PLAY = 15;
+ AIMP_PAUSE = 16;
+ AIMP_STOP = 17;
+ AIMP_NEXT = 18;
+ AIMP_PREV = 19;
+
+const
+ AIMP2_RemoteClass:PAnsiChar = 'AIMP2_RemoteInfo';
+const
+ AIMP2_RemoteFileSize = 2048;
+
+type
+ PAIMP2FileInfo = ^TAIMP2FileInfo;
+ TAIMP2FileInfo = packed record
+ cbSizeOF :dword;
+ //
+ nActive :LONGBOOL;
+ nBitRate :dword;
+ nChannels :dword;
+ nDuration :dword;
+ nFileSize :Int64;
+ nRating :dword;
+ nSampleRate :dword;
+ nTrackID :dword;
+ //
+ nAlbumLen :dword;
+ nArtistLen :dword;
+ nDateLen :dword;
+ nFileNameLen:dword;
+ nGenreLen :dword;
+ nTitleLen :dword;
+ //
+ sAlbum :dword; // size of pointer for 32 bit system
+ sArtist :dword;
+ sDate :dword;
+ sFileName :dword;
+ sGenre :dword;
+ sTitle :dword;
+ end;
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindowA(AIMP2_RemoteClass,AIMP2_RemoteClass);
+end;
+
+function GetVersionText(ver:integer):pWideChar;
+begin
+ if (ver and $F00)<>0 then
+ begin
+ mGetMem(result,8*SizeOf(WideChar));
+ result[0]:=WideChar((ver div 1000)+ORD('0'));
+ ver:=ver mod 1000;
+ result[1]:='.';
+ result[2]:=WideChar((ver div 100)+ORD('0'));
+ ver:=ver mod 100;
+ result[3]:='.';
+ result[4]:=WideChar((ver div 10)+ORD('0'));
+ result[5]:='.';
+ result[6]:=WideChar((ver mod 10)+ORD('0'));
+ result[7]:=#0;
+ end
+ else
+ result:=nil;
+end;
+
+function GetVersion(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_GET_VERSION,0);
+end;
+
+function GetStatus(wnd:HWND):integer; cdecl;
+begin
+ result:=SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_STATUS_GET,AIMP_STS_Player);
+end;
+
+function GetVolume(wnd:HWND):cardinal;
+begin
+ result:=SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_STATUS_GET,AIMP_STS_VOLUME);
+ result:=(result shl 16)+round((result shl 4)/100);
+end;
+
+procedure SetVolume(wnd:HWND;value:cardinal);
+begin
+ SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_STATUS_SET,
+ (AIMP_STS_VOLUME shl 16)+((value*100) shr 4));
+end;
+
+function VolDn(wnd:HWND):integer;
+var
+ val:dword;
+begin
+ result:=GetVolume(wnd);
+ val:=loword(result);
+ if val>0 then
+ SetVolume(wnd,val-1);
+end;
+
+function VolUp(wnd:HWND):integer;
+var
+ val:dword;
+begin
+ result:=GetVolume(wnd);
+ val:=loword(result);
+ if val<16 then
+ SetVolume(wnd,val+1);
+end;
+
+function GetFileName(wnd:HWND;flags:integer):pWideChar;cdecl;
+var
+ FFile:THANDLE;
+ pStr:pointer;
+ s:integer;
+ p:PAnsiChar;
+ pw,pw1:pWideChar;
+begin
+ result:=nil;
+ s:=AIMP2_RemoteFileSize;
+ p:=AIMP2_RemoteClass;
+ FFile:=OpenFileMappingA(FILE_MAP_READ,True,p);
+ pStr:=MapViewOfFile(FFile,FILE_MAP_READ,0,0,s);
+ try
+ if pStr<>nil then
+ begin
+ with PAIMP2FileInfo(pStr)^ do
+ begin
+ StrDupW(result,
+ pWideChar(PAnsiChar(pStr)+SizeOf(TAIMP2FileInfo)+
+ (nAlbumLen+nArtistLen+nDateLen)*SizeOf(WideChar)),
+ nFileNameLen);
+ // Delete rest index (like "filename.cue:3")
+ pw :=StrRScanW(result,':');
+ if pw<>nil then
+ begin
+ pw1:=StrScanW (result,':');
+ if pw<>pw1 then
+ pw^:=#0;
+ end;
+ end;
+ end;
+ finally
+ UnmapViewOfFile(pStr);
+ CloseHandle(FFile);
+ end;
+end;
+
+procedure TranslateRadio(var SongInfo:tSongInfo);
+var
+ pc,pc1:pWideChar;
+begin
+{
+ artist - album - title (radio)
+}
+ with SongInfo do
+ begin
+ if (artist=nil) and (title<>nil) then
+ begin
+ // Radio title
+ if (StrEndW(title)-1)^=')' then
+ begin
+ pc:=StrRScanW(title,'(');
+ if (pc<>nil) and (pc>title) and ((pc-1)^=' ') then
+ begin
+ if comment=nil then
+ begin
+ StrDupW(comment,pc+1);
+ (StrEndW(comment)-1)^:=#0;
+ end;
+ (pc-1)^:=#0;
+ end;
+ end;
+ // artist - title
+ pc:=StrPosW(title,' - ');
+ if pc<>nil then
+ begin
+ if artist=nil then
+ begin
+ pc^:=#0;
+ inc(pc,3);
+ StrDupW(artist,title);
+ end;
+ // artist - album - title
+ pc1:=StrPosW(pc,' - ');
+ if pc1<>nil then
+ begin
+ if album=nil then
+ begin
+ pc1^:=#0;
+ StrDupW(album,pc);
+ pc:=pc1+3;
+ end;
+ end;
+ pc1:=title;
+ StrDupW(title,pc);
+ mFreeMem(pc1);
+ end;
+ end;
+ end;
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+var
+ FFile:THANDLE;
+ s:integer;
+ p:PAnsiChar;
+ pStr:PAIMP2FileInfo;
+begin
+ result:=0;
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ SongInfo.plyver:=GetVersion (SongInfo.plwnd);
+ SongInfo.txtver:=GetVersionText(SongInfo.plyver);
+ end;
+ if SongInfo.winampwnd=0 then
+ SongInfo.winampwnd:=WinampFindWindow(SongInfo.plwnd);
+ exit;
+ end;
+
+ if SongInfo.winampwnd<>0 then
+ WinampGetInfo(int_ptr(@SongInfo),flags);
+
+ if (flags and WAT_OPT_CHANGES)=0 then
+ begin
+ s:=AIMP2_RemoteFileSize;
+ p:=AIMP2_RemoteClass;
+ FFile:=OpenFileMappingA(FILE_MAP_READ,True,p);
+ pStr:=MapViewOfFile(FFile,FILE_MAP_READ,0,0,s);
+ try
+ if pStr<>nil then
+ begin
+ with SongInfo do
+ begin
+ with pStr^ do
+ begin
+ if channels=0 then channels:=nChannels;
+ if kbps =0 then kbps :=nBitRate div 1000;
+ if khz =0 then khz :=nSampleRate div 1000;
+ if total =0 then total :=nduration;
+ if fsize =0 then fsize :=nFileSize;
+ if track =0 then track :=nTrackID;
+
+ with PAIMP2FileInfo(pStr)^ do
+ begin
+ if (artist=nil) and (nArtistLen>0) then
+ begin
+ StrDupW(artist,
+ pWideChar(PAnsiChar(pStr)+SizeOf(TAIMP2FileInfo))+
+ nAlbumLen,nArtistLen);
+ end;
+ if (album=nil) and (nAlbumLen>0) then
+ begin
+ StrDupW(album,
+ pWideChar(PAnsiChar(pStr)+SizeOf(TAIMP2FileInfo)),
+ nAlbumLen);
+ end;
+ if (title=nil) and (nTitleLen>0) then
+ begin
+ StrDupW(title,
+ pWideChar(PAnsiChar(pStr)+SizeOf(TAIMP2FileInfo))+
+ nAlbumLen+nArtistLen+nDateLen+nFileNameLen+nGenreLen,
+ nTitleLen);
+ end;
+ if (year=nil) and (nDateLen>0) then
+ begin
+ StrDupW(year,
+ pWideChar(PAnsiChar(pStr)+SizeOf(TAIMP2FileInfo))+
+ nAlbumLen+nArtistLen,
+ nDateLen);
+ end;
+ if (genre=nil) and (nGenreLen>0) then
+ begin
+ StrDupW(genre,
+ pWideChar(PAnsiChar(pStr)+SizeOf(TAIMP2FileInfo))+
+ nAlbumLen+nArtistLen+nDateLen+nFileNameLen,
+ nGenreLen);
+ end;
+
+ if StrPosW(mfile,'://')<>nil then
+ TranslateRadio(SongInfo);
+ end;
+ end;
+ end;
+ end;
+ finally
+ UnmapViewOfFile(pStr);
+ CloseHandle(FFile);
+ end;
+ end
+ else // request AIMP changed data: volume
+ begin
+ SongInfo.time:=SendMessage(SongInfo.plwnd,WM_AIMP_COMMAND,WM_AIMP_STATUS_GET,AIMP_STS_POS);
+ SongInfo.volume:=GetVolume(SongInfo.plwnd);
+ end;
+end;
+
+function Command(wnd:HWND;cmd:integer;value:integer):integer;cdecl;
+var
+ WinampWindow:HWND;
+begin
+ WinampWindow:=WinampFindWindow(wnd);
+ if WinampWindow<>0 then
+ result:=WinampCommand(WinampWindow,cmd+(value shl 16))
+ else
+ begin
+ result:=0;
+ case cmd of
+ WAT_CTRL_PREV : SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_CALLFUNC,AIMP_PREV);
+ WAT_CTRL_PLAY : SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_CALLFUNC,AIMP_PLAY);
+ WAT_CTRL_PAUSE: SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_CALLFUNC,AIMP_PAUSE);
+ WAT_CTRL_STOP : SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_CALLFUNC,AIMP_STOP);
+ WAT_CTRL_NEXT : SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_CALLFUNC,AIMP_NEXT);
+ WAT_CTRL_VOLDN: result:=VolDn(wnd);
+ WAT_CTRL_VOLUP: result:=VolUp(wnd);
+ WAT_CTRL_SEEK : begin
+ SendMessage(wnd,WM_AIMP_COMMAND,WM_AIMP_STATUS_SET,
+ (AIMP_STS_POS shl 16)+value);
+ end;
+ end;
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'AIMP';
+ flags :WAT_OPT_APPCOMMAND or WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.aimp.ru/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_apollo.pas b/plugins/Watrack/players/pl_apollo.pas
new file mode 100644
index 0000000000..360b23ab89
--- /dev/null
+++ b/plugins/Watrack/players/pl_apollo.pas
@@ -0,0 +1,263 @@
+{Apollo player}
+unit pl_Apollo;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,winampapi,messages,common,srv_player,wat_api;
+
+const
+ ApolloClass = 'Apollo - Main Window';
+
+const
+ WM_APOLLO_COMMAND = WM_USER+3;
+ APOLLO_GETVERSION = 0;
+ APOLLO_GETSTATUS = 1;
+ APOLLO_GETPLAYLISTPOSITION = 16;
+ APOLLO_GETCURRENTTRACKNUMBER = 17;
+ APOLLO_SETPLAYBACKPOSITION = 18;
+ APOLLO_GETPLAYBACKPOSITION = 19;
+ APOLLO_GETPLAYBACKCOUNTDOWN = 33;
+ APOLLO_GETCURRENTLYPLAYEDFILENAME = 24;
+ APOLLO_GETCURRENTLYPLAYEDTITLE = 25;
+ APOLLO_GETPLAYLISTENTRY = 26;
+ APOLLO_GETPLAYLISTTITLE = 27;
+// APOLLO_OPENURL = 4;
+ APOLLO_OPENFILE = 2;
+ APOLLO_PREVIOUSTRACK = 10;
+ APOLLO_STOP = 11;
+ APOLLO_PLAY = 12;
+ APOLLO_PAUSE = 13;
+ APOLLO_NEXTTRACK = 14;
+ APOLLO_SETVOLUME = 20;
+ APOLLO_GETVOLUME = 21;
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow(ApolloClass,NIL)
+end;
+
+function GetVersion(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_GETVERSION,0);
+end;
+
+function GetVersionText(ver:integer):PWideChar;
+begin
+ mGetMem(result,5*SizeOf(WideChar));
+ IntToStr(result,ver);
+end;
+
+function GetStatus(wnd:HWND):integer; cdecl;
+begin
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_GETSTATUS,0);
+ if result>1 then
+ result:=2;
+end;
+
+function GetFileName(wnd:HWND;flags:integer):pWideChar;cdecl;
+var
+ tmpwnd:hwnd;
+ ps:array [0..255] of AnsiChar;
+begin
+ if GetStatus(wnd)<>WAT_MES_STOPPED then
+ begin
+ tmpwnd:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_GETCURRENTLYPLAYEDFILENAME,0);
+ ps[0]:=#0;
+ SendMessageA(tmpwnd,WM_GETTEXT,255,lparam(@ps));
+ if ps[0]<>#0 then
+ begin
+ mGetMem(result,(StrLen(ps)+1)*SizeOf(WideChar));
+ AnsiToWide(ps,result);
+ exit;
+ end;
+ end;
+ result:=nil;
+end;
+
+function GetWndText(wnd:HWND):pWideChar;
+var
+ tmpwnd:hwnd;
+ ps:array [0..255] of AnsiChar;
+begin
+ tmpwnd:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_GETCURRENTLYPLAYEDTITLE,0);
+ SendMessageA(tmpwnd,WM_GETTEXT,255,lparam(@ps));
+ mGetMem(result,(StrLen(ps)+1)*SizeOf(WideChar));
+ AnsiToWide(ps,result);
+end;
+
+function Play(wnd:HWND;fname:PWideChar=nil):integer;
+var
+ cds:COPYDATASTRUCT;
+begin
+ if (fname<>nil) and (fname^<>#0) then
+ begin
+ cds.dwData:=APOLLO_OPENFILE;
+ WideToAnsi(fname,PAnsiChar(cds.lpData));
+ cds.cbData:=StrLen(PAnsiChar(cds.lpData))+1;
+ SendMessage(wnd,WM_COPYDATA,0,lparam(@cds));
+ mFreeMem(cds.lpData);
+ end;
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_PLAY,0);
+end;
+
+function Pause(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_PAUSE,0);
+end;
+
+function Stop(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_STOP,0);
+end;
+
+function Next(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_NEXTTRACK,0);
+end;
+
+function Prev(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_PREVIOUSTRACK,0);
+end;
+
+function GetVolume(wnd:HWND):cardinal;
+begin
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_GETVOLUME,0);
+ result:=(result shl 16)+(result shr 12);
+end;
+
+procedure SetVolume(wnd:HWND;value:cardinal);
+begin
+ SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_SETVOLUME,value shl 12);
+end;
+
+function VolDn(wnd:HWND):integer;
+var
+ val:integer;
+begin
+ result:=GetVolume(wnd);
+ val:=loword(result);
+ if val>0 then
+ SetVolume(wnd,val-1);
+end;
+
+function VolUp(wnd:HWND):integer;
+var
+ val:integer;
+begin
+ result:=GetVolume(wnd);
+ val:=loword(result);
+ if val<16 then
+ SetVolume(wnd,val+1);
+end;
+
+function Seek(wnd:HWND;value:integer):integer;
+begin
+ result:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_GETPLAYBACKPOSITION,0);
+ if value>0 then
+ SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_SETPLAYBACKPOSITION,value);
+end;
+
+function GetRemoteTitle(wnd:HWND):pWideChar;
+var
+ tmpwnd:hwnd;
+ ps:array [0..255] of AnsiChar;
+ num:integer;
+begin
+ num :=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_GETPLAYLISTPOSITION,0);
+ tmpwnd:=SendMessage(wnd,WM_APOLLO_COMMAND,APOLLO_GETPLAYLISTTITLE ,num);
+ SendMessageA(tmpwnd,WM_GETTEXT,255,lparam(@ps));
+ mGetMem(result,(StrLen(ps)+1)*SizeOf(WideChar));
+ AnsiToWide(ps,result);
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+begin
+ result:=0;
+
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ SongInfo.plyver:=GetVersion (SongInfo.plwnd);
+ SongInfo.txtver:=GetVersionText(SongInfo.plyver);
+ end;
+ if SongInfo.winampwnd=0 then
+ SongInfo.winampwnd:=WinampFindWindow(SongInfo.plwnd);
+ exit;
+ end;
+
+ if SongInfo.winampwnd<>0 then
+ result:=WinampGetInfo(int_ptr(@SongInfo),flags);
+
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ begin
+ with SongInfo do
+ begin
+ wndtext:=GetWndText(plwnd);
+ volume :=GetVolume (plwnd);
+ end
+ end
+ else
+ begin
+ with SongInfo do
+ begin
+ if (status<>WAT_MES_STOPPED) and
+ (mfile<>nil) and (StrPosW(mfile,'://')<>nil) and (album=nil) then
+ album:=GetRemoteTitle(plwnd);
+ end;
+ end;
+end;
+
+function Command(wnd:HWND;cmd:integer;value:int_ptr):integer;cdecl;
+begin
+ case cmd of
+ WAT_CTRL_PREV : result:=Prev(wnd);
+ WAT_CTRL_PLAY : result:=Play(wnd,pWideChar(value));
+ WAT_CTRL_PAUSE: result:=Pause(wnd);
+ WAT_CTRL_STOP : result:=Stop(wnd);
+ WAT_CTRL_NEXT : result:=Next(wnd);
+ WAT_CTRL_VOLDN: result:=VolDn(wnd);
+ WAT_CTRL_VOLUP: result:=VolUp(wnd);
+ WAT_CTRL_SEEK : result:=Seek(wnd,value);
+ else
+ result:=0;
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'Apollo';
+ flags :WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.iki.fi/hy/apollo/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_behold.pas b/plugins/Watrack/players/pl_behold.pas
new file mode 100644
index 0000000000..977a021034
--- /dev/null
+++ b/plugins/Watrack/players/pl_behold.pas
@@ -0,0 +1,175 @@
+{BeholderTV}
+unit pl_behold;
+{$include compilers.inc}
+
+interface
+
+implementation
+
+uses windows,messages,common,wrapper,srv_player,wat_api;
+
+const
+ WM_BHCMD = WM_USER+200;
+ WMBH_CHNLUP = WM_USER+203; // Ïåðåêëþ÷èòü íà ñëåäóþùèé êàíàë
+ WMBH_CHNLDOWN = WM_USER+204; // Ïåðåêëþ÷èòü íà ïðåäûäóùèé êàíàë
+ WMBH_VOLUMEUP = WM_USER+210; // Óâåëè÷èòü âûáðàííûé óðîâåíü
+ WMBH_VOLUMEDOWN = WM_USER+211; // Óìåíüøèòü âûáðàííûé óðîâåíü
+ WMBH_FREEZE = WM_USER+232; // Òðèããåð ñòîï-êàäðà
+ WMBH_SETVOLUME = WM_USER+280; // Óñòàíîâèòü óðîâåíü ãðîìêîñòè (LParam = 0..65535)
+ WMBH_GETVOLUME = WM_USER+281; // Ïîëó÷èòü òåêóùèé óðîâåíü ãðîìêîñòè (èñïîëüçîâàòü SendMessage, Result = 0..65535)
+ WMBH_GETVERSION = WM_USER+285; // Ïîëó÷èòü íîâåð âåðñèè ÏÎ (èñïîëüçîâàòü SendMessage)
+
+const
+ TitleWndClass = 'TApplication';
+ EXEName = 'BEHOLDTV.EXE';
+
+var
+ TitleWnd:HWND;
+
+function enumproc(wnd:HWND; lParam:LPARAM):bool; stdcall;
+var
+ buf:array [0..64] of AnsiChar;
+begin
+ result:=true;
+ if GetClassNameA(wnd,buf,63)<>0 then
+ begin
+ if StrCmp(buf,TitleWndClass)=0 then
+ begin
+ TitleWnd:=wnd;
+ result:=false;
+ end
+ end;
+end;
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow('TMain','BeholdTV');
+ if result<>0 then
+ EnumThreadWindows(GetWindowThreadProcessId(result,nil),@enumproc,0);
+end;
+
+function GetVersion(wnd:HWND):integer;
+begin
+ result:=DWORD(SendMessage(wnd,WM_BHCMD,WMBH_GETVERSION,0));
+ result:=((result shr 16) shl 8)+LoWord(result);
+end;
+
+function GetVersionText(ver:integer):PWideChar; //!!
+begin
+ mGetMem(result,10*SizeOf(WideChar));
+ IntToStr(result+1,ver);
+ result[0]:=result[1];
+ result[1]:='.';
+end;
+
+function GetFileName(wnd:HWND;flags:integer):pWideChar;cdecl;
+begin
+ result:=nil;
+end;
+
+function Pause(wnd:HWND):integer;
+begin
+ result:=0;
+ PostMessage(wnd,WM_BHCMD,WMBH_FREEZE,0);
+end;
+
+function Next(wnd:HWND):integer;
+begin
+ result:=0;
+ PostMessage(wnd,WM_BHCMD,WMBH_CHNLUP,0);
+end;
+
+function Prev(wnd:HWND):integer;
+begin
+ result:=0;
+ PostMessage(wnd,WM_BHCMD,WMBH_CHNLDOWN,0);
+end;
+
+function GetVolume(wnd:HWND):cardinal;
+begin
+ result:=WORD(SendMessage(wnd,WM_BHCMD,WMBH_GETVOLUME,0));
+ result:=(result shl 16)+(result shr 12);
+end;
+
+procedure SetVolume(wnd:HWND;value:cardinal);
+begin
+ SendMessage(wnd,WM_BHCMD,WMBH_SETVOLUME,value shl 12);
+end;
+
+function VolDn(wnd:HWND):integer;
+begin
+ result:=WORD(SendMessage(wnd,WM_BHCMD,WMBH_VOLUMEDOWN,0));
+end;
+
+function VolUp(wnd:HWND):integer;
+begin
+ result:=WORD(SendMessage(wnd,WM_BHCMD,WMBH_VOLUMEUP,0));
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+begin
+ result:=0;
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ SongInfo.plyver:=GetVersion (SongInfo.plwnd);
+ SongInfo.txtver:=GetVersionText(SongInfo.plyver);
+ end;
+ exit;
+ end;
+
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ SongInfo.wndtext:=GetDlgText(TitleWnd);
+end;
+
+function Command(wnd:HWND;cmd:integer;value:integer):integer;cdecl;
+begin
+ case cmd of
+ WAT_CTRL_PREV : result:=Prev(wnd);
+// WAT_CTRL_PLAY : result:=Play(wnd,pWideChar(value));
+ WAT_CTRL_PAUSE: result:=Pause(wnd);
+// WAT_CTRL_STOP : result:=Stop(wnd);
+ WAT_CTRL_NEXT : result:=Next(wnd);
+ WAT_CTRL_VOLDN: result:=VolDn(wnd);
+ WAT_CTRL_VOLUP: result:=VolUp(wnd);
+// WAT_CTRL_SEEK : result:=Seek(wnd,value);
+ else
+ result:=0;
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'BeholdTV';
+ flags :WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:nil;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :nil;
+ Notes :'Still experimental, no tested. Can work not properly');
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_bs.pas b/plugins/Watrack/players/pl_bs.pas
new file mode 100644
index 0000000000..7fd2e9c5e5
--- /dev/null
+++ b/plugins/Watrack/players/pl_bs.pas
@@ -0,0 +1,252 @@
+{BSPlayer player}
+unit pl_BS;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,messages,common,srv_player,wat_api;
+
+const
+ HWND_MESSAGE = HWND(-3);
+const
+ BSPlayerClass = 'BSPlayer';
+const
+ WM_BSP_CMD = WM_USER+2;
+ BSP_GETVERSION = $10000;
+ BSP_GetMovLen = $10100;
+ BSP_GetMovPos = $10101;
+ BSP_GetStatus = $10102;
+ BSP_Seek = $10103;
+
+// BSP_LoadPlaylist = $1010C;
+ BSP_SetVol = $10104;
+ BSP_GetVol = $10105;
+ BSP_OpenFile = $10108;
+ BSP_GetFileName = $1010B;
+
+ BSP_VolUp = 1;
+ BSP_VolDown = 2;
+ BSP_Play = 20;
+ BSP_Pause = 21;
+ BSP_Stop = 22;
+ BSP_Prev = 25;
+ BSP_Next = 28;
+
+const
+ bspwnd:HWND = 0;
+
+function HiddenWindProc(wnd:HWnd; msg:UINT;wParam:WPARAM;lParam:LPARAM):integer; stdcall;
+begin
+ result:=DefWindowProc(wnd,msg,wParam,lParam);
+end;
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow(BSPlayerClass,NIL);
+ if result=0 then
+ begin
+ if bspwnd<>0 then
+ begin
+ DestroyWindow(bspwnd);
+
+ bspwnd:=0;
+ end;
+ end
+ else if bspwnd=0 then
+ begin
+ bspwnd:=CreateWindowExW(0,'STATIC',nil,0,1,1,1,1,HWND_MESSAGE,0,hInstance,nil);
+ if bspwnd<>0 then
+ setwindowlongPtrW(bspwnd,GWL_WNDPROC,LONG_PTR(@HiddenWindProc));
+ end;
+end;
+
+function GetVersion(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_GETVERSION,0)
+end;
+
+function GetVersionText(ver:integer):pWideChar;
+begin
+ mGetMem(result,11*SizeOf(WideChar));
+ IntToHex(result,ver shr 24,2);
+ result[2]:='.';
+ IntToHex(result+3,(ver shr 16) and $FF,2);
+ result[5]:='.';
+ IntToHex(result+6,ver and $FFFF);
+end;
+
+function GetElapsedTime(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_GetMovPos,0) div 1000;
+end;
+
+function GetTotalTime(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_GetMovLen,0) div 1000;
+end;
+
+function GetStatus(wnd:HWND):integer; cdecl;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_GetStatus,0);
+ if result=1 then result:=2
+ else if result=2 then result:=1;
+ if result>2 then result:=2;
+end;
+
+function GetFileName(wnd:HWND;flags:integer):pWideChar;
+var
+ cds:tcopyDataStruct;
+ buf:array [0..255] of AnsiChar;
+ adr:pointer;
+begin
+ adr:=@buf;
+ cds.dwData:=BSP_GetFileName;
+ cds.lpData:=@adr;
+ cds.cbData:=4;
+ SendMessage(wnd,WM_COPYDATA,bspwnd,lparam(@cds));
+
+ AnsiToWide(buf,result);
+end;
+
+function Play(wnd:HWND;fname:PWideChar=nil):integer;
+var
+ cds:COPYDATASTRUCT;
+begin
+ if (fname<>nil) and (fname^<>#0) then
+ begin
+ cds.dwData:=BSP_OpenFile;
+ WideToAnsi(fname,PAnsiChar(cds.lpData));
+ cds.cbData:=StrLen(PAnsiChar(cds.lpData))+1;
+ SendMessage(wnd,WM_COPYDATA,0{!!!},lparam(@cds));
+ mFreeMem(cds.lpData);
+ end;
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_Play,0);
+end;
+
+function Pause(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_Pause,0);
+end;
+
+function Stop(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_Stop,0);
+end;
+
+function Next(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_Next,0);
+end;
+
+function Prev(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_Prev,0);
+end;
+
+function VolDn(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_VolDown,0);
+end;
+
+function VolUp(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_VolUp,0);
+end;
+
+function GetVolume(wnd:HWND):cardinal;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_GetVol,0);
+ result:=(result shl 16)+((result shl 4) div 25);
+end;
+
+procedure SetVolume(wnd:HWND;value:cardinal);
+begin
+ SendMessage(wnd,WM_BSP_CMD,BSP_SetVol,(value*25) shr 4);
+end;
+
+function Seek(wnd:HWND;value:integer):integer;
+begin
+ result:=SendMessage(wnd,WM_BSP_CMD,BSP_GetMovPos,0) div 1000;
+ SendMessage(wnd,WM_BSP_CMD,BSP_Seek,value*1000);
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+begin
+ result:=0;
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ SongInfo.plyver:=GetVersion (SongInfo.plwnd);
+ SongInfo.txtver:=GetVersionText(SongInfo.plyver);
+ end;
+ exit;
+ end;
+
+ with SongInfo do
+ begin
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ begin
+ volume:=GetVolume(plwnd);
+ if status<>WAT_MES_STOPPED then
+ time:=GetElapsedTime(plwnd);
+ end
+ else
+ begin
+ if total=0 then
+ total:=GetTotalTime(plwnd);
+ end;
+ end;
+end;
+
+function Command(wnd:HWND;cmd:integer;value:int_ptr):integer;cdecl;
+begin
+ case cmd of
+ WAT_CTRL_PREV : result:=Prev (wnd);
+ WAT_CTRL_PLAY : result:=Play (wnd,pWideChar(value));
+ WAT_CTRL_PAUSE: result:=Pause(wnd);
+ WAT_CTRL_STOP : result:=Stop (wnd);
+ WAT_CTRL_NEXT : result:=Next (wnd);
+ WAT_CTRL_VOLDN: result:=VolDn(wnd);
+ WAT_CTRL_VOLUP: result:=VolUp(wnd);
+ WAT_CTRL_SEEK : result:=Seek (wnd,value);
+ else
+ result:=0;
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'BSPlayer';
+ flags :WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.bsplayer.org/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_cowon.pas b/plugins/Watrack/players/pl_cowon.pas
new file mode 100644
index 0000000000..0977ea4b20
--- /dev/null
+++ b/plugins/Watrack/players/pl_cowon.pas
@@ -0,0 +1,392 @@
+{COWON JetAudio player}
+unit pl_cowon;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,winampapi,wrapper,messages,common,srv_player,wat_api;
+
+const
+ HWND_MESSAGE = HWND(-3);
+const
+ HOSTWND_CLASS = 'TLB_JETAUDIO';
+
+ CowonClass = 'COWON Jet-Audio MainWnd Class';
+ CowonTitle = 'Afx:400000:8:0:0:'; // for example 'Afx:400000:8:0:0:18c300fd'
+ ControlClass = 'COWON Jet-Audio Remocon Class';
+ ControlName = 'Jet-Audio Remote Control';
+ PluginClass = 'Streamzap.WMX';
+ PluginName = 'Jet-Audio Remote Plugin';
+const
+ MCI_STRING_OFFSET = 512;
+ MCI_MODE_NOT_READY = MCI_STRING_OFFSET + 12;
+ MCI_MODE_STOP = MCI_STRING_OFFSET + 13;
+ MCI_MODE_PLAY = MCI_STRING_OFFSET + 14;
+ MCI_MODE_RECORD = MCI_STRING_OFFSET + 15;
+ MCI_MODE_SEEK = MCI_STRING_OFFSET + 16;
+ MCI_MODE_PAUSE = MCI_STRING_OFFSET + 17;
+ MCI_MODE_OPEN = MCI_STRING_OFFSET + 18;
+
+ WM_REMOCON_GETSTATUS = WM_APP+740;
+ WM_REMOCON_SENDCOMMAND = WM_APP+741;
+
+ JRC_ID_STOP = 5102;
+ JRC_ID_PLAY = 5104; // Track Number (>=1). Use 0 for normal playback.
+ JRC_ID_PREV_TRACK = 5107;
+ JRC_ID_NEXT_TRACK = 5108;
+ JRC_ID_VOL_DOWN = 5134;
+ JRC_ID_VOL_UP = 5135;
+ JRC_ID_SET_VOLUME = 5180; // Volume Value (0 - 32)
+ JRC_ID_SEEK = 5192; // New position (second)
+ JRC_ID_RANDOMMODE = 5117;
+
+ GET_STATUS_STATUS = 1;
+ GET_STATUS_CUR_TRACK = 8;
+ GET_STATUS_CUR_TIME = 9;
+ GET_STATUS_MAX_TIME = 10;
+ GET_STATUS_TRACK_FILENAME = 11;
+ GET_STATUS_TRACK_TITLE = 12;
+ GET_STATUS_TRACK_ARTIST = 13;
+
+ GET_STATUS_VOLUME = 127;
+
+ JRC_COPYDATA_ID_ALBUMNAME = $1000;
+ JRC_COPYDATA_ID_GETVER = $1002;
+ JRC_COPYDATA_ID_TRACK_FILENAME = $3000;
+ JRC_COPYDATA_ID_TRACK_TITLE = $3001;
+ JRC_COPYDATA_ID_TRACK_ARTIST = $3002;
+
+ PLAY_NORMAL = 0;
+ PLAY_RANDOM = 1;
+
+ GET_STATUS_JETAUDIO_VER1 = 995;
+ GET_STATUS_JETAUDIO_VER2 = 996;
+ GET_STATUS_JETAUDIO_VER3 = 997;
+
+const
+ titlewnd:HWND = 0;
+ hostwnd :HWND = 0;
+ tmpstr :pWideChar=nil;
+
+function HiddenWindProc(wnd:HWnd; msg:UINT;wParam:WPARAM;lParam:LPARAM):integer; stdcall;
+var
+ cds:PCOPYDATASTRUCT;
+begin
+ case msg of
+ WM_COPYDATA: begin
+ cds:=PCOPYDATASTRUCT(lParam);
+ case cds^.dwData of
+ JRC_COPYDATA_ID_TRACK_FILENAME,
+ JRC_COPYDATA_ID_TRACK_TITLE ,
+ JRC_COPYDATA_ID_TRACK_ARTIST : AnsiToWide(cds^.lpData,tmpstr);
+ end;
+ result:=1;
+ exit;
+ end;
+ end;
+ result:=DefWindowProc(wnd,msg,wParam,lParam);
+end;
+
+function Init:integer;cdecl;
+begin
+ hostwnd:=CreateWindowExW(0,'STATIC',nil,0,1,1,1,1,HWND_MESSAGE,0,hInstance,nil);
+ if hostwnd<>0 then
+ SetWindowLongPtrW(hostwnd,GWL_WNDPROC,LONG_PTR(@HiddenWindProc));
+ result:=hostwnd;
+end;
+
+function DeInit:integer;cdecl;
+begin
+ result:=0;
+ if hostwnd<>0 then
+ begin
+ DestroyWindow(hostwnd);
+ hostwnd:=0;
+ end;
+end;
+
+function chwnd(awnd:hwnd;param:pdword):boolean; stdcall;
+var
+ s:array [0..255] of AnsiChar;
+begin
+ result:=true;
+ if GetClassNameA(awnd,s,255)>0 then
+ begin
+ if StrCmp(s,CowonTitle,Length(CowonTitle))=0 then
+ begin
+ param^:=awnd;
+ result:=false;
+ end;
+ end;
+end;
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow(ControlClass,ControlName);
+{
+ if result=0 then
+ result:=FindWindow(PluginClass,PluginName);
+}
+ if (result<>0) {and (result<>wnd)} then
+ if EnumWindows(@chwnd,int_ptr(@titlewnd)) then
+ titlewnd:=0;
+end;
+
+function GetWndText:pWideChar;
+var
+ p:pWideChar;
+begin
+ result:=nil;
+ if titlewnd<>0 then
+ begin
+ result:=GetDlgText(titlewnd);
+ if result<>nil then
+ begin
+ if StrScanW(result,'[')<>nil then
+ begin
+ p:=StrScanW(result,']');
+ if p<>nil then
+ begin
+ StrCopyW(result,p+1);
+ end;
+ end;
+ end;
+ end;
+end;
+
+function GetVersion(wnd:HWND):integer;
+begin
+ result:= SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GET_STATUS_JETAUDIO_VER1);
+ result:=(result shl 8)+SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GET_STATUS_JETAUDIO_VER2);
+ result:=(result shl 8)+SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GET_STATUS_JETAUDIO_VER3);
+end;
+
+function GetVersionText(ver:integer):PWideChar;
+{var
+ ver:integer;
+begin
+ ver:=GetVersion;
+ mGetMem(result,11*SizeOf(WideChar));
+ IntToHex(result,ver shr 16,2);
+ result[2]:='.';
+ IntToHex(result+3,(ver shr 8) and $FF,2);
+ result[5]:='.';
+ IntToHex(result+6,ver and $FF);
+}
+var
+ s:array [0..31] of WideChar;
+ i:integer;
+begin
+ i:=StrLenW(IntToStr(s,ver shr 16));
+ s[i]:='.';
+ i:=integer(StrLenW(IntToStr(pWideChar(@s[i+1]),(ver shr 8) and $FF)))+i+1;
+ s[i]:='.';
+ IntToStr(pWideChar(@s[i+1]),ver and $FF);
+ StrDupW(result,PWideChar(@s));
+end;
+
+function GetStatus(wnd:HWND):integer; cdecl;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GET_STATUS_STATUS);
+ case result of
+ MCI_MODE_STOP : result:=WAT_MES_STOPPED;
+ MCI_MODE_PAUSE: result:=WAT_MES_PAUSED;
+ MCI_MODE_PLAY : result:=WAT_MES_PLAYING;
+ else
+ result:=WAT_MES_UNKNOWN;
+ end;
+end;
+
+function GetFileName(wnd:HWND;flags:integer):pWideChar;cdecl;
+begin
+ SendMessage(wnd,WM_REMOCON_GETSTATUS,hostwnd,GET_STATUS_TRACK_FILENAME);
+ result:=tmpstr;
+end;
+
+function GetArtist(wnd:HWND):pWideChar;
+begin
+ SendMessage(wnd,WM_REMOCON_GETSTATUS,hostwnd,GET_STATUS_TRACK_ARTIST);
+ result:=tmpstr;
+end;
+
+function GetTitle(wnd:HWND):pWideChar;
+begin
+ SendMessage(wnd,WM_REMOCON_GETSTATUS,hostwnd,GET_STATUS_TRACK_TITLE);
+ result:=tmpstr;
+end;
+
+function GetTrack(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GET_STATUS_CUR_TRACK);
+end;
+
+function GetTotalTime(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GET_STATUS_MAX_TIME) div 1000;
+end;
+
+function GetElapsedTime(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GET_STATUS_CUR_TIME) div 1000;
+end;
+
+function Play(wnd:HWND;fname:PWideChar=nil):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_PLAY);
+end;
+
+function Pause(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_PLAY);
+end;
+
+function Stop(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_STOP);
+end;
+
+function Next(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_NEXT_TRACK);
+end;
+
+function Prev(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_PREV_TRACK);
+end;
+
+function VolDn(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_VOL_DOWN);
+end;
+
+function VolUp(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_VOL_UP);
+end;
+
+function GetVolume(wnd:HWND):cardinal;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GET_STATUS_VOLUME);
+ result:=(result shl 16)+(result shr 1);
+end;
+
+procedure SetVolume(wnd:HWND;value:cardinal);
+begin
+ SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_SET_VOLUME+(value shl 17));
+end;
+
+function Seek(wnd:HWND;value:integer):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_SENDCOMMAND,0,JRC_ID_SEEK+(value shl 16));
+end;
+{
+function Shuffle(setOn:integer):integer;
+begin
+ result:=SendMessage(wnd,WM_REMOCON_GETSTATUS,0,GETSTATUS_COMPONENT_RANDOMMODE);
+ SendMessage(wnd,WM_REMOCON_SENDCOMMAND,JRC_ID_RANDOMMODE+(SetOn shl 16));
+end;
+}
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+var
+ p:pWideChar;
+begin
+ result:=0;
+// result:=CallService(MS_WAT_WINAMPINFO,integer(@SongInfo),flags);
+// result:=WinampGetInfo(integer(@SongInfo),flags);
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ SongInfo.plyver:=GetVersion (SongInfo.plwnd);
+ SongInfo.txtver:=GetVersionText(SongInfo.plyver);
+ end;
+ exit;
+ end;
+
+ with SongInfo do
+ begin
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ begin
+ wndtext:=GetWndText;
+ volume :=GetVolume(plwnd);
+ if status<>WAT_MES_STOPPED then
+// if time=0 then
+ time:=GetElapsedTime(plwnd);
+ end
+ else
+ begin
+
+ if artist=NIL then
+ begin
+ artist:=GetArtist(plwnd);
+ if artist^=#0 then
+ mFreeMem(artist);
+ end;
+ if title =NIL then
+ begin
+ title:=GetTitle(plwnd);
+ p:=ExtractW(mfile,true);
+ if (title^=#0) or (StrCmpW(title,p)=0) then
+ mFreeMem(title);
+ mFreeMem(p);
+ end;
+
+ if total=0 then
+ total:=GetTotalTime(plwnd);
+ end;
+ end;
+end;
+
+function Command(wnd:HWND;cmd:integer;value:int_ptr):integer;cdecl;
+begin
+ case cmd of
+ WAT_CTRL_PREV : result:=Prev (wnd);
+ WAT_CTRL_PLAY : result:=Play (wnd,pWideChar(value));
+ WAT_CTRL_PAUSE: result:=Pause(wnd);
+ WAT_CTRL_STOP : result:=Stop (wnd);
+ WAT_CTRL_NEXT : result:=Next (wnd);
+ WAT_CTRL_VOLDN: result:=VolDn(wnd);
+ WAT_CTRL_VOLUP: result:=VolUp(wnd);
+ WAT_CTRL_SEEK : result:=Seek (wnd,value);
+ else
+ result:=0;
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'Cowon JetAudio';
+ flags :WAT_OPT_HASURL;
+ Icon :0;
+ Init :@Init;
+ DeInit :@DeInit;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.jetaudio.com/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_foobar.pas b/plugins/Watrack/players/pl_foobar.pas
new file mode 100644
index 0000000000..f861db6327
--- /dev/null
+++ b/plugins/Watrack/players/pl_foobar.pas
@@ -0,0 +1,534 @@
+{Foobar2000 player}
+unit pl_Foobar;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses {$IFDEF KOL_MCK}err,{$ENDIF}
+ windows,common,syswin,wrapper,srv_player,messages,wat_api,winampapi
+ {$IFDEF DELPHI_7_UP}
+ ,variants
+ {$ENDIF}
+ {$IFDEF KOL_MCK}
+ ,kolcomobj
+ {$ELSE}
+ ,ComObj
+ {$ENDIF}
+;
+
+const
+ COMName:PAnsiChar = 'Foobar2000.Application.0.7';
+const
+ dummywnd = 'uninteresting';
+const
+ FooExe = 'FOOBAR2000.EXE';
+ FooPrefix = 'foobar2000 v';
+const
+ FooBarClassExt = '{97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}';
+ FooBarClassNew = '{DA7CD0DE-1602-45e6-89A1-C2CA151E008E}';
+ FooBarClassAdd = '{E7076D1C-A7BF-4f39-B771-BCBE88F2A2A8}';
+(*
+ class1='{B73733CA-9B0A-4f53-93FA-AC95D4FF2166}';
+ text1='Cthulhu fhtagn!';
+
+ '{53229DFC-A273-45cd-A3A4-161FA9FC6414}';
+ '{641C2469-355C-4d6f-9663-E714382DA462}';
+*)
+var
+ WinampWindow:HWND;
+
+function proc(awnd:hwnd;param:pdword):boolean; stdcall;
+var
+ s:array [0..255] of AnsiChar;
+begin
+ result:=true;
+ if (awnd<>param^) and (GetClassNameA(awnd,s,255)>0) then
+ begin
+ s[Length(FooBarClassNew)]:=#0;
+ if (StrCmp(s,FooBarClassExt)=0) or
+ (StrCmp(s,FooBarClassNew)=0) or
+ (StrCmp(s,FooBarClassAdd)=0) then
+ begin
+ GetWindowTextA(awnd,s,255);
+ if StrCmp(s,dummywnd)<>0 then
+ param^:=awnd;
+// if WinampWindow<>0 then
+// result:=false;
+ end
+
+ else if (WinampWindow=0) and (StrCmp(s,WinampClass)=0) then
+ begin
+ WinampWindow:=awnd;
+ end;
+
+ end;
+end;
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+var
+ tmp,EXEName:PAnsiChar;
+ lwnd:HWND;
+ ltmp:bool;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ lwnd:=0;
+ repeat
+ lwnd:=FindWindowEx(0,lwnd,nil,dummywnd);
+ if lwnd=0 then
+ break;
+ tmp:=Extract(GetEXEByWnd(lwnd,EXEName),true);
+ mFreeMem(EXEName);
+ ltmp:=lstrcmpia(tmp,FooExe)=0;
+ mFreeMem(tmp);
+ if ltmp then
+ begin
+ WinampWindow:=0;
+ EnumThreadWindows(GetWindowThreadProcessId(lwnd,nil),@proc,int_ptr(@lwnd));
+ break;
+ end;
+ until false;
+ result:=lwnd;
+end;
+
+function GetYear(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.Playback.FormatTitle('[%year%]'))));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetArtist(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.Playback.FormatTitle('[%artist%]'))));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetTitle(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.Playback.FormatTitle('[%title%]'))));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetAlbum(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.Playback.FormatTitle('[%album%]'))));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetGenre(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.Playback.FormatTitle('[%genre%]'))));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetBitrate(const v:variant):integer;
+begin
+ try
+ result:=v.Playback.FormatTitle('%bitrate%');
+ except
+ result:=0;
+ end;
+end;
+
+function GetSamplerate(const v:variant):integer;
+begin
+ try
+ result:=v.Playback.FormatTitle('%samplerate%');
+ except
+ result:=0;
+ end;
+end;
+
+function GetChannels(const v:variant):integer;
+var
+ s:WideString;
+begin
+ result:=0;
+ try
+ s:=v.Playback.FormatTitle('%channels%');
+ if StrCmpW(pWideChar(s),'mono')=0 then
+ result:=1
+ else if StrCmpW(pWideChar(s),'Stereo')=0 then
+ result:=2;
+ except
+ end;
+end;
+
+function GetCodec(const v:variant):integer;
+var
+ s:WideString;
+ i:integer;
+begin
+ result:=0;
+ try
+ s:=v.Playback.FormatTitle('%codec%');
+ i:=Length(s);
+ if i>0 then result:=ORD(s[1]);
+ if i>1 then result:=result+(ORD(s[2]) shl 8);
+ if i>2 then result:=result+(ORD(s[3]) shl 16);
+ if i>3 then result:=result+(ORD(s[4]) shl 24);
+ except
+ end;
+end;
+
+function SplitVersion(p:pWideChar):integer;
+begin
+ result:=StrToInt(p);
+ while (p^>='0') and (p^<='9') do inc(p); inc(p);
+ result:=result*16+StrToInt(p);
+ while (p^>='0') and (p^<='9') do inc(p); inc(p);
+ result:=result*16+StrToInt(p);
+ while (p^>='0') and (p^<='9') do inc(p);
+ if p^<>#0 then inc(p);
+ if (p^>='0') and (p^<='9') then
+ begin
+ result:=result*16+StrToInt(p);
+ while (p^>='0') and (p^<='9') do inc(p);
+ end;
+ if p^<>#0 then
+ begin
+ inc(p);
+ while (p^<>#0) and (p^<>' ') do inc(p);
+ if p^=' ' then
+ begin
+ inc(p);
+ result:=result*16+StrToInt(p);
+ end;
+ end;
+end;
+
+function GetVersion(const ver:pWideChar):integer;
+begin
+ if (ver=nil) or (ver^=#0) then
+ result:=0
+ else
+ result:=SplitVersion(ver);
+end;
+
+function GetVersionText(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.Name))+length(FooPrefix));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetTotalTime(const v:variant):integer;
+begin
+ try
+ result:=v.Playback.Length;
+ except
+ result:=0;
+ end;
+end;
+
+function GetElapsedTime(const v:variant):integer;
+begin
+ try
+ result:=v.Playback.Position;
+ except
+ result:=0;
+ end;
+end;
+
+function GetStatus(wnd:HWND):integer; cdecl;
+var
+ tmp:boolean;
+ v:variant;
+ winampwnd:HWND;
+begin
+ try
+ result:=WAT_MES_STOPPED;
+ v:=GetActiveOleObject(COMName);
+ tmp:=v.Playback.IsPaused;
+ if tmp then
+ result:=WAT_MES_PAUSED
+ else
+ begin
+ tmp:=v.Playback.IsPlaying;
+ if tmp then
+ result:=WAT_MES_PLAYING;
+ end;
+ except
+ winampwnd:=WinampFindWindow(wnd);
+ if winampwnd<>0 then
+ result:=WinampGetStatus(winampwnd)
+ else
+ result:=WAT_MES_UNKNOWN;
+ end;
+ v:=null;
+end;
+
+function GetWndText(wnd:HWND):pWideChar;
+var
+ i:integer;
+begin
+ result:=GetDlgText(wnd);
+ if result<>nil then
+ begin
+ i:=StrIndexW(result,'[foobar');
+ if i<>0 then
+ begin
+ dec(i);
+ repeat
+ dec(i);
+ if ord(result[i])>ord(' ') then break;
+ until i<0;
+ result[i+1]:=#0;//if at end
+ end;
+ end;
+end;
+
+function GetFileName(wnd:HWND;flags:integer):PWideChar;cdecl;
+var
+ v:variant;
+begin
+ try
+ v:=GetActiveOleObject(COMName);
+// v:=CreateOleObject(COMName);
+ StrDupW(result,PWideChar(WideString(v.Playback.FormatTitle('%path%'))));
+ except
+ result:=nil;
+ end;
+ v:=Null;
+end;
+
+function Play(const v:variant;fname:PWideChar=nil):integer;
+begin
+ try
+ result:=v.Playback.Start(false);
+ except
+ result:=0;
+ end;
+end;
+
+function Pause(const v:variant):integer;
+begin
+ try
+ result:=v.Playback.Pause;
+ except
+ result:=0;
+ end;
+end;
+
+function Stop(const v:variant):integer;
+begin
+ try
+ result:=v.Playback.Stop;
+ except
+ result:=0;
+ end;
+end;
+
+function Next(const v:variant):integer;
+begin
+ try
+ result:=v.Playback.Next;
+ except
+ result:=0;
+ end;
+end;
+
+function Prev(const v:variant):integer;
+begin
+ try
+ result:=v.Playback.Previous;
+ except
+ result:=0;
+ end;
+end;
+
+function GetVolume(const v:variant):cardinal;
+begin
+ try
+ result:=v.Playback.Settings.Volume+100;
+ result:=(result shl 16)+round((result shl 4) / 100);
+ except
+ result:=0;
+ end;
+end;
+
+procedure SetVolume(const v:variant;value:cardinal);
+begin
+ try
+ v.Playback.Settings.Volume:=integer(((loword(value)*100) shr 4)-100);
+ except
+ end;
+end;
+
+function VolDn(const v:variant):integer;
+var
+ val:integer;
+begin
+ result:=GetVolume(v);
+ val:=loword(result);
+ if val>0 then
+ SetVolume(v,val-1);
+end;
+
+function VolUp(const v:variant):integer;
+var
+ val:integer;
+begin
+ result:=GetVolume(v);
+ val:=loword(result);
+ if val<16 then
+ SetVolume(v,val+1);
+end;
+
+function Seek(const v:variant;value:integer):integer;
+begin
+ try
+ result:=v.Playback.Position;
+ if (value>0) and (v.Playback.CanSeek) and (value<v.Playback.Length) then
+ v.Playback.Seek(value)
+ else
+ result:=0;
+ except
+ result:=0;
+ end;
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+var
+ v:variant;
+begin
+ result:=0;
+ with SongInfo do
+ begin
+ try
+ v:=GetActiveOleObject(COMName);
+// v:=CreateOleObject(COMName);
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ SongInfo.txtver:=GetVersionText(v);
+ SongInfo.plyver:=GetVersion(txtver);
+ end;
+ end
+ else if (flags and WAT_OPT_CHANGES)<>0 then
+ begin
+ volume:=GetVolume(v);
+ if status<>WAT_MES_STOPPED then
+ time:=GetElapsedTime(v);
+ end
+ else
+ begin
+ if kbps =0 then kbps :=GetBitrate(v);
+ if khz =0 then khz :=GetSamplerate(v);
+ if channels=0 then channels:=GetChannels(v);
+ if codec =0 then codec :=GetCodec(v);
+ if total =0 then total :=GetTotalTime(v);
+ if year =NIL then year :=GetYear(v);
+ if artist =NIL then artist :=GetArtist(v);
+ if title =NIL then title :=GetTitle(v);
+ if album =NIL then album :=GetAlbum(v);
+ if genre =NIL then genre :=GetGenre(v);
+ end;
+ except
+ SongInfo.winampwnd:=WinampWindow;
+ if SongInfo.winampwnd<>0 then
+ begin
+ result:=WinampGetInfo(int_ptr(@SongInfo),flags);
+ end;
+ end;
+ v:=Null;
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ wndtext:=GetWndText(SongInfo.plwnd);
+ end;
+end;
+
+function Command(wnd:HWND;cmd:integer;value:int_ptr):integer;cdecl;
+//var
+// c:integer;
+var
+ v:Variant;
+begin
+ result:=0;
+ try
+ v:=GetActiveOleObject(COMName);
+ case cmd of
+ WAT_CTRL_PREV : result:=Prev (v);
+ WAT_CTRL_PLAY : result:=Play (v,pWideChar(value));
+ WAT_CTRL_PAUSE: result:=Pause(v);
+ WAT_CTRL_STOP : result:=Stop (v);
+ WAT_CTRL_NEXT : result:=Next (v);
+ WAT_CTRL_VOLDN: result:=VolDn(v);
+ WAT_CTRL_VOLUP: result:=VolUp(v);
+ WAT_CTRL_SEEK : result:=Seek (v,value);
+ end;
+ except
+ if WinampWindow<>0 then
+ result:=WinampCommand(WinampWindow,cmd+(value shl 16))
+{
+ else
+ begin
+ case cmd of
+ WAT_CTRL_PREV : c:=ORD('B');
+ WAT_CTRL_PLAY : c:=ORD('C');
+ WAT_CTRL_PAUSE: c:=ORD('X');
+ WAT_CTRL_STOP : c:=ORD('Z');
+ WAT_CTRL_NEXT : c:=ORD('V');
+ WAT_CTRL_VOLDN: c:=VK_SUBTRACT;
+ WAT_CTRL_VOLUP: c:=VK_ADD;
+ else
+ exit;
+ end;
+ PostMessageW(wnd,WM_KEYDOWN,c,1);
+ end;
+}
+ end;
+ v:=Null;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'foobar2000';
+ flags :WAT_OPT_SINGLEINST or WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.foobar2000.org/';
+ Notes :'For more full info WinampSpam or foo_comserver (more powerful) '#13#10+
+ 'components needs to be installed.');
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_itunes.pas b/plugins/Watrack/players/pl_itunes.pas
new file mode 100644
index 0000000000..f43e6bac91
--- /dev/null
+++ b/plugins/Watrack/players/pl_itunes.pas
@@ -0,0 +1,392 @@
+{iTunes player}
+unit pl_iTunes;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,common,srv_player,wat_api
+ {$IFDEF DELPHI_7_UP}
+ ,variants
+ {$ENDIF}
+ {$IFDEF KOL_MCK}
+ ,kolcomobj
+ {$ELSE}
+ ,ComObj
+ {$ENDIF}
+;
+
+const
+ iTunesClass = 'iTunes';
+ iTunesTitle = 'iTunes';
+ COMName = 'iTunes.Application';
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow(iTunesClass,iTunesTitle);
+end;
+
+function GetFileName(wnd:HWND;flags:integer):PWideChar;cdecl;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ StrDupW(result,PWideChar(WideString(v.CurrentTrack.Location)));
+ except
+ result:=nil;
+ end;
+ v:=Null;
+end;
+
+function SplitVersion(p:pWideChar):integer;
+begin
+ result:=StrToInt(p);
+ while (p^>='0') and (p^<='9') do inc(p); inc(p);
+ result:=result*16+StrToInt(p);
+ while (p^>='0') and (p^<='9') do inc(p); inc(p);
+ result:=(result*16+StrToInt(p))*16;
+ while (p^>='0') and (p^<='9') do inc(p); inc(p);
+ result:=result*16+StrToInt(p);
+end;
+
+function GetVersion(const ver:pWideChar):integer;
+begin
+ if (ver<>nil) and (ver^<>#0) then
+ result:=SplitVersion(ver)
+ else
+ result:=0;
+end;
+
+function GetVersionText(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.Version)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetTotalTime(const v:variant):integer;
+begin
+ try
+ result:=v.CurrentTrack.Duration;
+ except
+ result:=0;
+ end;
+end;
+
+function GetElapsedTime(const v:variant):integer;
+begin
+ try
+ result:=v.PlayerPosition;
+ except
+ result:=0;
+ end;
+end;
+
+function GetStatus(wnd:HWND):integer; cdecl;
+var
+ tmp:integer;
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ tmp:=v.PlayerState;
+ if tmp=1 then
+ result:=WAT_MES_PLAYING
+ else
+ result:=WAT_MES_STOPPED;
+ except
+ result:=WAT_MES_UNKNOWN;
+ end;
+ v:=Null;
+end;
+
+function GetKbps(const v:variant):integer;
+begin
+ try
+ result:=v.CurrentTrack.BitRate;
+ except
+ result:=0;
+ end;
+end;
+
+function GetKhz(const v:variant):integer;
+begin
+ try
+ result:=v.CurrentTrack.SampleRate;
+ except
+ result:=0;
+ end;
+end;
+
+function GetTrack(const v:variant):integer;
+begin
+ try
+ result:=v.CurrentTrack.TrackNumber;
+ except
+ result:=0;
+ end;
+end;
+
+function GetAlbum(const v:variant):pWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.CurrentTrack.Album)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetYear(const v:variant):pWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.CurrentTrack.Year)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetGenre(const v:variant):pWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.CurrentTrack.Genre)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetArtist(const v:variant):pWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.CurrentTrack.Artist)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetTitle(const v:variant):pWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.CurrentStreamTitle)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetComment(const v:variant):pWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.CurrentTrack.Comment)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetWndText(const v:variant):pWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.Windows.Name)));
+ except
+ result:=nil;
+ end;
+end;
+
+function Play(const v:variant;fname:PWideChar=nil):integer;
+begin
+ try
+// v.PlayFile(fname);
+ v.BackTrack;
+ result:=v.Play;
+ except
+ result:=0;
+ end;
+end;
+
+function Pause(const v:variant):integer;
+begin
+ try
+ result:=v.PlayPause;
+ except
+ result:=0;
+ end;
+end;
+
+function Stop(const v:variant):integer;
+begin
+ try
+ result:=v.Stop;
+ except
+ result:=0;
+ end;
+end;
+
+function Next(const v:variant):integer;
+begin
+ try
+ result:=v.NextTrack;
+ except
+ result:=0;
+ end;
+end;
+
+function Prev(const v:variant):integer;
+begin
+ try
+ result:=v.PreviousTrack;
+ except
+ result:=0;
+ end;
+end;
+
+function Seek(const v:variant;value:integer):integer;
+begin
+ try
+ result:=v.PlayerPosition;
+ if value>0 then
+ v.PlayerPosition:=value
+ else
+ result:=0;
+ except
+ result:=0;
+ end;
+end;
+
+function GetVolume(const v:variant):cardinal;
+begin
+ try
+ result:=v.SoundVolume;
+ result:=(result shl 16)+round((result shl 4)/100);
+ except
+ result:=0;
+ end;
+end;
+
+procedure SetVolume(const v:variant;value:cardinal);
+begin
+ try
+ v.SoundVolume:=integer((value*100) shr 4);
+ except
+ end;
+end;
+
+function VolDn(const v:variant):integer;
+var
+ val:integer;
+begin
+ result:=GetVolume(v);
+ val:=loword(result);
+ if val>0 then
+ SetVolume(v,val-1);
+end;
+
+function VolUp(const v:variant):integer;
+var
+ val:integer;
+begin
+ result:=GetVolume(v);
+ val:=loword(result);
+ if val<16 then
+ SetVolume(v,val+1);
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+var
+ v:variant;
+begin
+ result:=0;
+ with SongInfo do
+ begin
+ try
+ v:=CreateOleObject(COMName);
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if plyver=0 then
+ begin
+ txtver:=GetVersionText(v);
+ plyver:=GetVersion(txtver);
+ end;
+ end
+ else if (flags and WAT_OPT_CHANGES)<>0 then
+ begin
+ volume:=GetVolume(v);
+ if status<>WAT_MES_STOPPED then
+ time:=GetElapsedTime(v);
+ end
+ else
+ begin
+ if total =0 then total :=GetTotalTime(v);
+ if track =0 then track :=GetTrack(v);
+ if year =NIL then year :=GetYear(v);
+ if genre =NIL then genre :=GetGenre(v);
+ if artist =NIL then artist :=GetArtist(v);
+ if album =NIL then album :=GetAlbum(v);
+ if comment=NIL then comment:=GetComment(v);
+ if kbps =0 then kbps :=GetKbps(v);
+ if khz =0 then khz :=GetKhz(v);
+ end;
+// wndtext:=GetWndText(v);
+ except
+ end;
+ v:=Null;
+// if title=NIL then title:=GetTitle; // only for streaming audio
+ end;
+end;
+
+function Command(wnd:HWND;cmd:integer;value:int_ptr):integer;cdecl;
+var
+ v:Variant;
+begin
+ result:=0;
+ try
+ v:=CreateOleObject(COMName);
+ case cmd of
+ WAT_CTRL_PREV : result:=Prev (v);
+ WAT_CTRL_PLAY : result:=Play (v,pWideChar(value));
+ WAT_CTRL_PAUSE: result:=Pause(v);
+ WAT_CTRL_STOP : result:=Stop (v);
+ WAT_CTRL_NEXT : result:=Next (v);
+ WAT_CTRL_VOLDN: result:=VolDn(v);
+ WAT_CTRL_VOLUP: result:=VolUp(v);
+ WAT_CTRL_SEEK : result:=Seek (v,value);
+ end;
+ except
+ end;
+ v:=Null;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'iTunes';
+ flags :WAT_OPT_SINGLEINST or WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.itunes.com/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_la.pas b/plugins/Watrack/players/pl_la.pas
new file mode 100644
index 0000000000..1945cf6580
--- /dev/null
+++ b/plugins/Watrack/players/pl_la.pas
@@ -0,0 +1,141 @@
+{LightAlloy player}
+unit pl_la;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,messages,common,srv_player,wat_api;
+
+const
+ LAClass = 'LightAlloyFront';
+const
+ WM_LACMD = WM_APP + 2504;
+ LAC_VERSION = 000;
+
+ LAC_FILE_OPEN = 050;
+ LAC_PLAYBACK_STOP = 100;
+ LAC_PLAYBACK_PLAY = 101;
+ LAC_PLAYBACK_STOP_PLAY = 102;
+ LAC_PLAYLIST_NEXT = 250;
+ LAC_PLAYLIST_PREV = 251;
+ LAC_PLAYLIST_PLAY = 252;
+ LAC_SOUND_VOLUME_INC = 401;
+ LAC_SOUND_VOLUME_DEC = 402;
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow(LAClass,NIL);
+end;
+
+function GetVersion(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_LACMD,LAC_VERSION,0)
+end;
+
+function Play(wnd:HWND;fname:PWideChar=nil):integer;
+var
+ cds:COPYDATASTRUCT;
+begin
+ if (fname<>nil) and (fname^<>#0) then
+ begin
+ cds.dwData:=LAC_FILE_OPEN;
+ WideToAnsi(fname,PAnsiChar(cds.lpData));
+ cds.cbData:=StrLen(PAnsiChar(cds.lpData))+1;
+ SendMessage(wnd,WM_COPYDATA,0,lparam(@cds));
+ mFreeMem(cds.lpData);
+ end;
+ result:=SendMessage(wnd,WM_LACMD,LAC_PLAYLIST_PLAY,0) // LAC_PLAYLIST_PLAY
+end;
+
+function Pause(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_LACMD,LAC_PLAYBACK_STOP_PLAY,0)
+end;
+
+function Stop(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_LACMD,LAC_PLAYBACK_STOP,0)
+end;
+
+function Next(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_LACMD,LAC_PLAYLIST_NEXT,0)
+end;
+
+function Prev(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_LACMD,LAC_PLAYLIST_PREV,0)
+end;
+
+function VolDn(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_LACMD,LAC_SOUND_VOLUME_DEC,0);
+end;
+
+function VolUp(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_LACMD,LAC_SOUND_VOLUME_INC,0);
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+begin
+ result:=0;
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ SongInfo.plyver:=GetVersion(SongInfo.plwnd);
+ end;
+ end;
+end;
+
+function Command(wnd:HWND;cmd:integer;value:int_ptr):integer;cdecl;
+begin
+ case cmd of
+ WAT_CTRL_PREV : result:=Prev (wnd);
+ WAT_CTRL_PLAY : result:=Play (wnd,pWideChar(value));
+ WAT_CTRL_PAUSE: result:=Pause(wnd);
+ WAT_CTRL_STOP : result:=Stop (wnd);
+ WAT_CTRL_NEXT : result:=Next (wnd);
+ WAT_CTRL_VOLDN: result:=VolDn(wnd);
+ WAT_CTRL_VOLUP: result:=VolUp(wnd);
+ else
+ result:=0;
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'LightAlloy';
+ flags :WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:nil;
+ GetName :nil;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.softella.com/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_lastfm.pas b/plugins/Watrack/players/pl_lastfm.pas
new file mode 100644
index 0000000000..56ed3c7d4b
--- /dev/null
+++ b/plugins/Watrack/players/pl_lastfm.pas
@@ -0,0 +1,129 @@
+{Last.fm Player}
+unit pl_LastFM;
+
+interface
+
+implementation
+
+uses windows,common,messages,syswin,srv_player,wat_api;
+
+
+const
+ LFMName = 'Last.fm Player';
+ LFMText = 'Last.fm';
+ LFMClass = 'QWidget';
+
+const
+ UserName:pWideChar=nil;
+
+function Check(wnd:HWND;aflags:integer):HWND;cdecl;
+var
+ tmp,EXEName:PAnsiChar;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow(LFMClass,nil{LFMName});
+ if result<>0 then
+ begin
+ tmp:=Extract(GetEXEByWnd(result,EXEName),true);
+ if lstrcmpia(tmp,'LASTFM.EXE')<>0 then
+ result:=0;
+ mFreeMem(tmp);
+ mFreeMem(EXEName);
+ if result<>0 then
+ result:=GetWindow(result,GW_OWNER);
+ end;
+ if result=0 then
+ mFreeMem(UserName);
+end;
+
+function GetWndText(wnd:HWND):pWideChar;
+var
+ ps:array [0..255] of WideChar;
+ p:pWideChar;
+begin
+ SendMessageW(wnd,WM_GETTEXT,255,lparam(@ps));
+ p:=StrPosW(ps,' | ');
+ if p<>nil then
+ begin
+ mFreeMem(UserName);
+ StrDupW(UserName,p+3);
+ p^:=#0;
+ end;
+ StrDupW(result,ps);
+end;
+
+function GetFileName(wnd:HWND;flags:integer):PWideChar;cdecl;
+var
+ buf:array [0..1023] of WideChar;
+ p:pWideChar;
+begin
+// lstrcpyw(buf,'http://');
+buf[0]:=#0;
+ p:=GetWndText(wnd);
+ StrCatW(buf,p);
+ StrCatW(buf,'.mp3');
+ StrDupW(result,buf);
+ mFreeMem(p);
+end;
+
+function GetStatus(wnd:HWND):integer; cdecl;
+var
+ txt:pWideChar;
+begin
+ txt:=GetWndText(wnd);
+ if StrCmpW(txt,LFMText,Length(LFMText))<>0 then
+ result:=WAT_MES_PLAYING
+ else
+ result:=WAT_MES_STOPPED;
+ mFreeMem(txt);
+end;
+
+function GetInfo(var SongInfo:tSongInfo;aflags:integer):integer;cdecl;
+begin
+ result:=0;
+ with SongInfo do
+ begin
+ fsize:=1;
+ if (aflags and WAT_OPT_CHANGES)<>0 then
+ begin
+ wndtext:=GetWndText(plwnd);
+ end
+ else
+ begin
+ end;
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'Last.fm';
+ flags :WAT_OPT_LAST or WAT_OPT_SINGLEINST or WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :nil;
+ URL :'http://www.lastfm.com/';
+ Notes :'Works by window title analysing only');
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_mmonkey.pas b/plugins/Watrack/players/pl_mmonkey.pas
new file mode 100644
index 0000000000..bb826b9851
--- /dev/null
+++ b/plugins/Watrack/players/pl_mmonkey.pas
@@ -0,0 +1,181 @@
+{MediaMonkey player}
+unit pl_mmonkey;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,messages,winampapi,common,srv_player,wat_api
+ {$IFDEF DELPHI_7_UP}
+ ,variants
+ {$ENDIF}
+ {$IFDEF KOL_MCK}
+ ,kolcomobj
+ {$ELSE}
+ ,ComObj
+ {$ENDIF}
+;
+
+const
+ COMName:PAnsiChar = 'SongsDB.SDBApplication';
+
+const
+ WM_WA_IPC = WM_USER;
+ IPC_GETVERSION = 0;
+
+{
+const
+ MMonkeyName = 'MediaMonkey';
+}
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+//var
+// i:integer;
+{
+ EXEName:pWideChar;
+ tmp:pWideChar;
+}
+// v:Variant;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow('TFMainWindow','MediaMonkey');
+ if result=0 then
+ result:=FindWindow('TFMainWindow.UnicodeClass','MediaMonkey');
+{
+ wnd:=FindWindow(WinAmpClass,NIL);
+ if wnd<>0 then
+ begin
+ if (SendMessage(wnd,WM_WA_IPC,0,IPC_GETVERSION) and $FF0F)<>$990B then
+ wnd:=result;
+ end;
+}
+{
+ wnd:=FindWindow(WinAmpClass,NIL);
+ if wnd<>0 then
+ begin
+ i:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETVERSION) and $FF0F;
+ if i=$990B then
+ begin
+
+ try
+// v:=GetActiveOleObject(COMName);
+ v:=CreateOleObject(COMName);
+ if not v.IsRunning then
+ wnd:=0;
+ except
+ end;
+ v:=Null;
+
+ end
+ else
+ wnd:=0;
+ end;
+ result:=wnd;
+{
+ begin
+ EXEName:=GetEXEByWnd(wnd);
+ tmp:=Extract(EXEName,true);
+ mFreeMem(EXEName);
+ result:=StrCmpW(tmp,MMonkeyName,length(MMonkeyName))=0;
+ mFreeMem(tmp);
+ end;
+}
+end;
+
+function GetVersion(const v:variant):integer;
+begin
+ try
+ result:=(v.VersionHi shl 8)+(v.VersionLo shl 4)+v.VersionRelease;
+ except
+ result:=0;
+ end;
+end;
+
+function GetVersionText(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.VersionString)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetFileName(wnd:HWND;flags:integer):pWideChar;cdecl;
+var
+ v:Variant;
+begin
+ try
+// SDB:=GetActiveOleObject(COMName);
+ v:=CreateOleObject(COMName);
+ StrDupW(result,PWideChar(WideString(v.Player.CurrentSong.Path)));
+ except
+ result:=nil;
+ end;
+ v:=Null;
+end;
+
+function GetStatus(wnd:HWND):integer; cdecl;
+begin
+ result:=WinampGetStatus(wnd)
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+var
+ v:variant;
+begin
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ try
+ v:=CreateOleObject(COMName);
+ with SongInfo do
+ begin
+ plyver:=GetVersion(v);
+ txtver:=GetVersionText(v);
+ end;
+ except
+ end;
+ v:=Null;
+ end;
+ end;
+ result:=WinampGetInfo(int_ptr(@SongInfo),flags);
+end;
+
+function Command(wnd:HWND;cmd:integer;value:integer):integer;cdecl;
+begin
+ result:=WinampCommand(wnd,cmd+(value shl 16));
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'MediaMonkey';
+ flags :WAT_OPT_SINGLEINST or WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.mediamonkey.com/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_mpc.pas b/plugins/Watrack/players/pl_mpc.pas
new file mode 100644
index 0000000000..a2127cea76
--- /dev/null
+++ b/plugins/Watrack/players/pl_mpc.pas
@@ -0,0 +1,117 @@
+{Media Player Classic}
+unit pl_MPC;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,common,wrapper,srv_player,wat_api;
+
+const
+ MPCClass98 = 'MediaPlayerClassicA';
+ MPCClassXP = 'MediaPlayerClassicW';
+ MPCTail = ' - Media Player Classic';
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ result:=FindWindowEx(0,wnd,MPCClassXP,NIL);
+ if result=0 then
+ result:=FindWindowEx(0,wnd,MPCClass98,NIL);
+end;
+
+function chwnd(awnd:hwnd;Param:pdword):boolean; stdcall;
+var
+ s:array [0..31] of AnsiChar;
+ i:integer;
+begin
+ FillChar(s,SizeOf(s),0);
+ GetWindowTextA(awnd,s,30);
+ i:=StrIndex(PAnsiChar(@s),' / ');
+ if i<>0 then
+ begin
+ if Param^=0 then
+ begin
+ s[i-1]:=#0;
+ Param^:=TimeToInt(s);
+ end
+ else
+ begin
+ Param^:=TimeToInt(s+i+2);
+ end;
+ result:=false;
+ end
+ else
+ result:=true;
+end;
+
+function GetElapsedTime(wnd:HWND):integer;
+begin
+ result:=0;
+ if EnumChildWindows(wnd,@chwnd,int_ptr(@result)) then
+ result:=0;
+end;
+
+function GetTotalTime(wnd:HWND):integer;
+begin
+ result:=1;
+ if EnumChildWindows(wnd,@chwnd,int_ptr(@result)) then
+ result:=0;
+end;
+
+function GetWndText(wnd:HWND):pWidechar;
+var
+ p:pWideChar;
+begin
+ result:=GetDlgText(wnd);
+ if result<>nil then
+ begin
+ p:=StrPosW(result,MPCTail);
+ if p<>nil then
+ p^:=#0;
+ end;
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+begin
+ result:=0;
+ with SongInfo do
+ begin
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ begin
+ time :=GetElapsedTime(SongInfo.plwnd);
+ wndtext:=GetWndText(SongInfo.plwnd);
+ end
+ else if total=0 then
+ total:=GetTotalTime(SongInfo.plwnd);
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'MPC';
+ flags :WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:nil;
+ GetName :nil;
+ GetInfo :@GetInfo;
+ Command :nil;
+ URL :'http://gabest.org/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_mradio.pas b/plugins/Watrack/players/pl_mradio.pas
new file mode 100644
index 0000000000..3d97037fbb
--- /dev/null
+++ b/plugins/Watrack/players/pl_mradio.pas
@@ -0,0 +1,345 @@
+{mRadio protocol support}
+unit pl_mradio;
+{$include compilers.inc}
+{$r mradio.res}
+interface
+
+implementation
+uses m_api,dbsettings,windows,common,srv_player,wat_api,io;
+
+const
+ strUnknown:PwideChar = 'Unknown';
+ playername:PAnsiChar = 'mRadio';
+const
+ CurrentStation:THANDLE=THANDLE(-1);
+const
+ ChangesHook:THANDLE=0;
+const
+ MS_RADIO_COMMAND = 'mRadio/Command';
+ MS_RADIO_SETVOL = 'mRadio/SetVol';
+ ME_RADIO_STATUS:PAnsiChar = 'mRadio/Status';
+const
+ MRC_STOP = 0;
+ MRC_PLAY = 1;
+ MRC_PAUSE = 2;
+ MRC_PREV = 3;
+ MRC_NEXT = 4;
+ MRC_STATUS = 5;
+ MRC_SEEK = 6;
+const
+ RD_STATUS_NOSTATION = 0; // no active station found
+ RD_STATUS_PLAYING = 1; // media is playing
+ RD_STATUS_PAUSED = 2; // media is paused
+ RD_STATUS_STOPPED = 3; // media is stopped (only for playlists)
+ RD_STATUS_CONNECT = 4; // plugin try to connect to the station
+ RD_STATUS_ABORT = 5; // plugin want to abort while try to connect
+ // next is for events only
+ RD_STATUS_POSITION = 107; // position was changed
+ RD_STATUS_MUTED = 108; // Mute/Unmute command was sent
+ RD_STATUS_RECORD = 109; // "Record" action called
+ RD_STATUS_NEWTRACK = 110; // new track/station
+ RD_STATUS_NEWTAG = 111; // tag data changed
+ RD_STATUS_NEWSTATION = 112; // new station (contact)
+ // next command is for users
+ RD_STATUS_GET = 6; // to get current status
+const
+ prevfile:PWideChar=nil;
+
+function ClearmRadio:integer; cdecl;
+begin
+ result:=0;
+ if ChangesHook>0 then
+ begin
+ UnhookEvent(ChangesHook);
+ ChangesHook:=0;
+ CurrentStation:=THANDLE(-1);
+ end;
+ mFreeMem(prevfile);
+end;
+
+function SettingsChanged(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+begin
+ result:=0;
+ case wParam of
+ // clear station
+ RD_STATUS_NOSTATION: CurrentStation:=THANDLE(-1);
+ // get new url
+ RD_STATUS_NEWSTATION: CurrentStation:=lParam;
+ end;
+end;
+
+function Fill:integer;
+var
+ i:integer;
+begin
+ CurrentStation:=CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while CurrentStation<>0 do
+ begin
+ i:=DBReadWord(CurrentStation,playername,'Status',WORD(-1));
+ if i=ID_STATUS_ONLINE then
+ begin
+ result:=1;
+ exit;
+ end;
+ CurrentStation:=CallService(MS_DB_CONTACT_FINDNEXT,CurrentStation,0);
+ end;
+ result:=WAT_RES_NOTFOUND;
+end;
+
+function InitmRadio:integer;
+begin
+ if ChangesHook=0 then
+ begin
+ ChangesHook:=HookEvent(ME_RADIO_STATUS,@SettingsChanged);
+ result:=Fill;
+ end
+ else if (CurrentStation<>0) and (CurrentStation<>THANDLE(-1)) then
+ result:=1
+ else
+ result:=WAT_RES_NOTFOUND;
+end;
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ if CallProtoService(playername,PS_GETSTATUS,0,0)=ID_STATUS_ONLINE then
+ begin
+ result:=InitmRadio
+ end
+ else
+ begin
+ result:=HWND(WAT_RES_NOTFOUND);
+ ClearmRadio;
+ end;
+end;
+
+function GetKbps:integer;
+var
+ pc:PWideChar;
+begin
+ pc:=DBReadUnicode(CurrentStation,playername,'Bitrate','0');
+ result:=StrToInt(pc);
+ mFreeMem(pc);
+end;
+
+function GetFileName(wnd:HWND;flags:integer):pWideChar; cdecl;
+begin
+ result:=DBReadUnicode(0,playername,'ActiveURL',nil)
+end;
+
+function GetGenre:pWideChar;
+begin
+ result:=DBReadUnicode(CurrentStation,playername,'Genre',nil);
+end;
+
+function GetWndText:pWideChar;
+begin
+ result:=DBReadUnicode(CurrentStation,strCList,'StatusMsg',strUnknown);
+end;
+
+function GetTitle:pWideChar;
+begin
+ result:=DBReadUnicode(0,playername,'Title');
+ if result=nil then
+ result:=DBReadUnicode(CurrentStation,strCList,'StatusMsg',strUnknown);
+end;
+
+function GetArtist:pWideChar;
+begin
+ result:=DBReadUnicode(0,playername,'Artist');
+ if result=nil then
+ result:=DBReadUnicode(CurrentStation,strCList,'MyHandle',strUnknown);
+end;
+
+function GetVolume:cardinal;
+begin
+ result:=DBReadByte(0,playername,'Volume',0);
+ result:=(result shl 16)+round((result shl 4)/100);
+end;
+
+procedure SetVolume(value:cardinal);
+begin
+ CallService(MS_RADIO_SETVOL,(value*100) shr 4,0);
+end;
+
+function VolDn:integer;
+var
+ val:dword;
+begin
+ result:=GetVolume;
+ val:=loword(result);
+ if val>0 then
+ SetVolume(val-1);
+end;
+
+function VolUp:integer;
+var
+ val:dword;
+begin
+ result:=GetVolume;
+ val:=loword(result);
+ if val<16 then
+ SetVolume(val+1);
+end;
+
+function GetCover:pWideChar;
+var
+ ptr:PavatarCacheEntry;
+begin
+ result:=nil;
+ if ServiceExists(MS_AV_GETAVATARBITMAP)<>0 then
+ begin
+ ptr:=PavatarCacheEntry(CallService(MS_AV_GETAVATARBITMAP,CurrentStation,0));
+ if ptr<>nil then
+ AnsiToWide(ptr^.szFilename,result)
+ end;
+end;
+
+function GetVersionText(ver:dword):pWideChar;
+var
+ s:array [0..31] of WideChar;
+ p:pWideChar;
+begin
+ p:=@s;
+ IntToStr(p,ver shr 12);
+ while p^<>#0 do inc(p);
+ p^:='.';
+ IntToStr(p+1,(ver shr 8) and $F);
+ while p^<>#0 do inc(p);
+ p^:='.';
+ IntToStr(p+1,(ver shr 4) and $F);
+ while p^<>#0 do inc(p);
+ p^:='.';
+ IntToStr(p+1,ver and $F);
+ StrDupW(result,PWideChar(@s));
+end;
+
+function GetStatus:integer; cdecl;
+begin
+ if CurrentStation<>0 then
+ begin
+ result:=WAT_MES_PLAYING;
+ case CallService(MS_RADIO_COMMAND,MRC_STATUS,RD_STATUS_GET) of
+ RD_STATUS_PAUSED : result:=WAT_MES_PAUSED;
+ RD_STATUS_STOPPED: begin
+ result:=WAT_MES_STOPPED;
+ mFreeMem(prevfile);
+ end;
+ RD_STATUS_NOSTATION,
+ RD_STATUS_ABORT : result:=WAT_MES_UNKNOWN;
+ end;
+ end
+ else
+ result:=WAT_MES_STOPPED;
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+var
+ lfile:pWideChar;
+ isRemote:bool;
+ isChanging:bool;
+begin
+ result:=0;
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ SongInfo.plyver:=DBReadDWord(0,playername,'version');
+ SongInfo.txtver:=GetVersionText(SongInfo.plyver);
+ end;
+ end
+ else if CurrentStation<>0 then
+ with SongInfo do
+ begin
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ begin
+ volume:=GetVolume;
+ mFreeMem(wndtext);
+ wndtext:=GetWndText;
+ time:=CallService(MS_RADIO_COMMAND,MRC_SEEK,-1);
+ end
+ else
+ begin
+ lfile:=GetFileName(plwnd,flags);
+ isRemote:=StrPosW(lfile,'://')<>nil;
+ if (prevfile=nil) or isRemote or (StrCmpW(prevfile,lfile)<>0) then
+ begin
+ ClearTrackInfo(SongInfo,false);
+ mfile:=lfile;
+ mFreeMem(prevfile);
+ StrDupW(prevfile,mfile);
+ isChanging:=true;
+ end
+ else
+ begin
+ isChanging:=false;
+ mFreeMem(lfile);
+ end;
+
+ if not isRemote then
+ begin
+ if isChanging then
+ begin
+ CallService(MS_WAT_GETFILEINFO,0,lparam(@SongInfo));
+ fsize:=GetFSize(mfile);
+ mFreeMem(prevfile);
+ StrDupW(prevfile,mfile);
+ end;
+ end;
+//!!
+ if kbps =0 then kbps :=GetKbps;
+ if genre =nil then genre :=GetGenre;
+ if title =nil then title :=GetTitle;
+ if artist=nil then artist:=GetArtist;
+ if cover =nil then cover :=GetCover;
+ end;
+ end;
+end;
+
+function Command(wnd:HWND;cmd:integer;value:integer):integer;cdecl;
+begin
+ result:=0;
+ case cmd of
+ WAT_CTRL_PREV : result:=CallService(MS_RADIO_COMMAND,MRC_PREV,0);
+ WAT_CTRL_PLAY : result:=CallService(MS_RADIO_COMMAND,MRC_PLAY,0);
+ WAT_CTRL_PAUSE: result:=CallService(MS_RADIO_COMMAND,MRC_PAUSE,0);
+ WAT_CTRL_STOP : result:=CallService(MS_RADIO_COMMAND,MRC_STOP,0);
+ WAT_CTRL_NEXT : result:=CallService(MS_RADIO_COMMAND,MRC_NEXT,0);
+ WAT_CTRL_VOLDN: result:=VolDn;
+ WAT_CTRL_VOLUP: result:=VolUp;
+ WAT_CTRL_SEEK : result:=CallService(MS_RADIO_COMMAND,MRC_SEEK,value);
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'mRadio';
+ flags :WAT_OPT_PLAYERINFO or WAT_OPT_SINGLEINST or WAT_OPT_HASURL or WAT_OPT_LAST;
+ Icon :0;
+ Init :nil;
+ DeInit :@ClearmRadio;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'https://code.google.com/p/delphi-miranda-plugins/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ if plRec.Icon=0 then
+ plRec.Icon:=LoadImage(hInstance,'ICO_MRADIO',IMAGE_ICON,16,16,0);
+
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+ InitLink;
+finalization
+ if plRec.Icon<>0 then DestroyIcon(plRec.Icon);
+end.
diff --git a/plugins/Watrack/players/pl_vlc.pas b/plugins/Watrack/players/pl_vlc.pas
new file mode 100644
index 0000000000..9d3a2ad57d
--- /dev/null
+++ b/plugins/Watrack/players/pl_vlc.pas
@@ -0,0 +1,380 @@
+{Video Lan player}
+unit pl_VLC;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,common,srv_player,wat_api,syswin,wrapper
+ {$IFDEF DELPHI_7_UP}
+ ,variants
+ {$ENDIF}
+ {$IFDEF KOL_MCK}
+ ,kolcomobj
+ {$ELSE}
+ ,ComObj
+ {$ENDIF}
+;
+
+{
+ procedure play; safecall;
+ procedure pause; safecall;
+ procedure stop; safecall;
+ procedure playlistNext; safecall;
+ procedure playlistPrev; safecall;
+ property Playing: WordBool read Get_Playing;
+ property Position: Single read Get_Position write Set_Position;
+ property Time: SYSINT read Get_Time write Set_Time;
+ property Length: SYSINT read Get_Length;
+ (0)1-97(100)
+ property Volume: SYSINT read Get_Volume write Set_Volume;
+ property VersionInfo: WideString read Get_VersionInfo;
+}
+
+const
+// GuidOld: TGUID = '{E23FE9C6-778E-49D4-B537-38FCDE4887D8}';
+ VLCClass = 'wxWindowClassNR';
+ VLCName = 'VLC media player';
+ COMName = 'VideoLAN.VLCPlugin.1'; // IVLCControl
+
+// GuidNew: TGUID = '{9BE31822-FDAD-461B-AD51-BE1D1C159921}';
+ VLCClassSkin = 'SkinWindowClass';
+ VLCClassNew = 'QWidget';
+ VLCEXEName = 'VLC.EXE';
+ COMNameNew = 'VideoLAN.VLCPlugin2'; // IVLCControl2
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+var
+ tmp,EXEName:PAnsiChar;
+begin
+ if wnd<>0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ result:=FindWindow(VLCClass,VLCName);
+ if result=0 then
+ result:=FindWindow(VLCClassSkin,nil); // VLCName
+ if result=0 then
+ result:=FindWindow(VLCClassNew,nil);
+ if result<>0 then
+ begin
+ tmp:=Extract(GetEXEByWnd(result,EXEName),true);
+ if lstrcmpia(tmp,VLCEXEName)<>0 then
+ result:=0;
+ mFreeMem(tmp);
+ mFreeMem(EXEName);
+ end;
+{ if result<>0 then
+ begin
+ tmp:=Extract(GetEXEByWnd(result,EXEName),true);
+ if lstrcmpia(tmp,'VLC.EXE')<>0 then
+ result:=0;
+ mFreeMem(tmp);
+ mFreeMem(EXEName);
+ end;
+}
+end;
+
+function SplitVersion(p:pWideChar):integer;
+begin
+ result:=StrToInt(p);
+ while (p^>='0') and (p^<='9') do inc(p); inc(p);
+ result:=result*16+StrToInt(p);
+ while (p^>='0') and (p^<='9') do inc(p); inc(p);
+ result:=(result*16+StrToInt(p))*16;
+ while (p^>='0') and (p^<='9') do inc(p); inc(p);
+ result:=result*16+StrToInt(p);
+end;
+
+function GetVersion(const ver:pWideChar):integer;
+begin
+ try
+ result:=SplitVersion(ver);
+ except
+ result:=0;
+ end;
+end;
+
+function GetVersionText(const v:variant):PWideChar;
+begin
+ try
+ StrDupW(result,PWideChar(WideString(v.VersionInfo)));
+ except
+ result:=nil;
+ end;
+end;
+
+function GetWndText(wnd:HWND):pWideChar;
+var
+ p:pWideChar;
+begin
+ result:=GetDlgText(wnd);
+{
+need to clear " - lalala VLC" at the end
+}
+ if result<>nil then
+ begin
+ p:=StrRScanW(result,'-');
+ if p<>nil then // found
+ begin
+ if (p>result) and ((p-1)^=' ') and ((p+1)^=' ') then
+ (p-1)^:=#0;
+ end;
+ end;
+end;
+
+{
+function GetTotalTime:integer;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.Length;
+ except
+ result:=inherited GetTotalTime;
+ end;
+ v:=Null;
+end;
+
+function GetElapsedTime:integer;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.Time;
+ except
+ result:=inherited GetElapsedTime;
+ end;
+ v:=Null;
+end;
+
+function GetStatus:integer; cdecl;
+var
+ v:variant;
+ tmp:boolean;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ tmp:=v.Playing;
+ if tmp then
+ result:=WAT_MES_PLAYING
+ else
+ result:=WAT_MES_STOPPED;
+ except
+ result:=inherited GetStatus;
+ end;
+ v:=Null;
+end;
+
+function Play(fname:PWideChar=nil):integer;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.play;
+ except
+ result:=inherited Play(fname);
+ end;
+ v:=Null;
+end;
+
+function Pause:integer;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.pause;
+ except
+ result:=inherited Pause;
+ end;
+ v:=Null;
+end;
+
+function Stop:integer;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.stop;
+ except
+ result:=inherited Stop;
+ end;
+ v:=Null;
+end;
+
+function Next:integer;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.playlistNext;
+ except
+ result:=inherited Next;
+ end;
+ v:=Null;
+end;
+
+function Prev:integer;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.playlistPrev;
+ except
+ result:=inherited Prev;
+ end;
+ v:=Null;
+end;
+
+function Seek(value:integer):integer;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.Position;
+ if value>0 then
+ v.Position:=value
+ else
+ result:=0;
+ except
+ result:=inherited Seek(value);
+ end;
+ v:=Null;
+end;
+
+function GetVolume:cardinal;
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ result:=v.Volume;
+ result:=(result shl 16)+((result shl 4) div 100);
+ except
+ result:=0;
+ end;
+ v:=Null;
+end;
+
+procedure SetVolume(value:cardinal);
+var
+ v:variant;
+begin
+ try
+ v:=CreateOleObject(COMName);
+ v.Volume:=(value*100) shr 4;
+ end;
+ except
+ result:=inherited SetVolume(value);
+ end;
+ v:=Null;
+end;
+
+function VolDn:integer;
+var
+ val:integer;
+begin
+ result:=GetVolume;
+ val:=loword(result);
+ if val>0 then
+ SetVolume(val-1);
+end;
+
+function VolUp:integer;
+var
+ val:integer;
+begin
+ result:=GetVolume;
+ val:=loword(result);
+ if val<16 then
+ SetVolume(val+1);
+end;
+
+}
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+var
+ v:variant;
+begin
+ result:=0;
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.plyver=0 then
+ begin
+ try
+ try
+ v:=CreateOleObject(COMName);
+ except
+ try
+ v:=CreateOleObject(COMNameNew);
+ except
+ v:=Null;
+ end;
+ end;
+ if v<>Null then
+ with SongInfo do
+ begin
+ txtver:=GetVersionText(v);
+ plyver:=GetVersion(txtver);
+ end;
+ except
+ end;
+ v:=Null;
+ if (flags and WAT_OPT_CHANGES)<>0 then
+ SongInfo.wndtext:=GetWndText(SongInfo.plwnd);
+ end;
+ end;
+end;
+{
+function Command(wnd:HWND;cmd:integer;value:integer):integer;cdecl;
+begin
+ result:=0;
+ case cmd of
+ WAT_CTRL_PREV : result:=Prev;
+ WAT_CTRL_PLAY : result:=Play(pWideChar(value));
+ WAT_CTRL_PAUSE: result:=Pause;
+ WAT_CTRL_STOP : result:=Stop;
+ WAT_CTRL_NEXT : result:=Next;
+ WAT_CTRL_VOLDN: result:=VolDn;
+ WAT_CTRL_VOLUP: result:=VolUp;
+ WAT_CTRL_SEEK : result:=Seek(value);
+ end;
+end;
+}
+const
+ plRec:tPlayerCell=(
+ Desc :'VideoLAN player';
+ flags :WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:nil;
+ GetName :nil;
+ GetInfo :@GetInfo;
+ Command :nil;
+ URL :'http://www.videolan.org/';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_winamp.pas b/plugins/Watrack/players/pl_winamp.pas
new file mode 100644
index 0000000000..254475e09a
--- /dev/null
+++ b/plugins/Watrack/players/pl_winamp.pas
@@ -0,0 +1,170 @@
+{Winamp-like - base class}
+unit pl_WinAmp;
+{$include compilers.inc}
+
+interface
+
+implementation
+
+uses winampapi,windows,common,messages,syswin,srv_player,wat_api;
+
+{
+#define IPC_GETPLAYLISTTITLE 212
+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
+** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE);
+**
+** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index].
+** returns a pointer to it. returns NULL on error.
+*/
+}
+// class = BaseWindow_RootWnd
+// title = Main Window
+
+// ---------- check player ------------
+
+function Check(wnd:HWND;aflags:integer):HWND;cdecl;
+var
+ tmp,EXEName:PAnsiChar;
+begin
+ result:=FindWindowEx(0,wnd,WinampClass,NIL);
+ if result<>0 then
+ begin
+ tmp:=Extract(GetEXEByWnd(result,EXEName),true);
+ if lstrcmpia(tmp,'WINAMP.EXE')<>0 then
+ result:=0;
+ mFreeMem(tmp);
+ mFreeMem(EXEName);
+ end;
+end;
+
+function WAnyCheck(wnd:HWND;aflags:integer):HWND;cdecl;
+begin
+ result:=FindWindowEx(0,wnd,WinampClass,NIL);
+end;
+
+// ----------- Get info ------------
+
+function GetStatus(wnd:HWND):integer; cdecl;
+begin
+ result:=WinampGetStatus(wnd)
+end;
+
+function GetWidth(wnd:HWND):integer;
+begin
+ result:=LOWORD(SendMessage(wnd,WM_WA_IPC,3,IPC_GETINFO));
+end;
+
+function GetHeight(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,3,IPC_GETINFO) shr 16;
+end;
+
+function GetInfo(var SongInfo:tSongInfo;aflags:integer):integer;cdecl;
+begin
+ SongInfo.winampwnd:=SongInfo.plwnd;
+ result:=WinampGetInfo(int_ptr(@SongInfo),aflags);
+ with SongInfo do
+ begin
+ if (aflags and WAT_OPT_CHANGES)<>0 then
+ wndtext:=WinampGetWindowText(winampwnd)
+ else
+ begin
+{
+ if ((loword(plyver) shr 12)>=5) and
+ (SendMessage(wnd,WM_WA_IPC,0,IPC_IS_PLAYING_VIDEO)>1) then
+ begin
+ if width =0 then width :=GetWidth(wnd);
+ if height=0 then Height:=GetHeight(wnd);
+ end;
+}
+ end;
+ end;
+end;
+
+// ------- Commands ----------
+
+function Command(wnd:HWND;cmd:integer;value:integer):integer;cdecl;
+begin
+ result:=WinampCommand(wnd,cmd+(value shl 16));
+end;
+
+// ------- In-process code -------
+
+function GetFileName(wnd:HWND;flags:integer):pWideChar;cdecl;
+var
+ fpos,fname:int_ptr;
+ pid:dword;
+ op:THANDLE;
+ buf:array [0..1023] of AnsiChar;
+ tmp:{$IFDEF FPC}LongWord{$ELSE}ulong_ptr{$ENDIF};
+begin
+ result:=nil;
+ if (flags and WAT_OPT_IMPLANTANT)<>0 then
+ begin
+ if SendMessage(wnd,WM_WA_IPC,0,IPC_ISPLAYING)<>WAT_MES_STOPPED then
+ begin
+ fpos :=SendMessage(wnd,WM_USER,0 ,IPC_GETLISTPOS);
+ fname:=SendMessage(wnd,WM_USER,fpos,IPC_GETPLAYLISTFILE);
+ GetWindowThreadProcessId(wnd,@pid);
+ op:=OpenProcess(PROCESS_VM_READ,false,pid);
+ if op<>0 then
+ begin
+ ReadProcessMemory(op,PByte(fname),@buf,SizeOf(buf),tmp);
+ CloseHandle(op);
+ if tmp>0 then
+ AnsiToWide(buf,result);
+ end;
+ end;
+ end;
+end;
+
+const
+ plRec:tPlayerCell=(
+ Desc :'Winamp';
+ flags :WAT_OPT_ONLYONE or WAT_OPT_WINAMPAPI or WAT_OPT_HASURL;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:@GetStatus;
+ GetName :@GetFileName;
+ GetInfo :@GetInfo;
+ Command :@Command;
+ URL :'http://www.winamp.com/';
+ Notes :nil);
+
+const
+ plRecClone:tPlayerCell=(
+ Desc :'Winamp Clone';
+ flags :WAT_OPT_ONLYONE or WAT_OPT_WINAMPAPI or WAT_OPT_LAST;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@WAnyCheck;
+ GetStatus:@GetStatus;
+ GetName :nil;
+ GetInfo :@WinampGetInfo;
+ Command :@Command;
+ URL :nil;
+ Notes :'All "unknown" players using Winamp API');
+
+var
+ LocalPlayerLink,
+ LocalPlayerLinkC:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+
+ LocalPlayerLinkC.Next:=PlayerLink;
+ LocalPlayerLinkC.This:=@plRecClone;
+ PlayerLink :=@LocalPlayerLinkC;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRecClone));
+ InitLink;
+end.
diff --git a/plugins/Watrack/players/pl_wmp.pas b/plugins/Watrack/players/pl_wmp.pas
new file mode 100644
index 0000000000..971cb28ac6
--- /dev/null
+++ b/plugins/Watrack/players/pl_wmp.pas
@@ -0,0 +1,128 @@
+{Windows Media Player}
+unit pl_WMP;
+{$include compilers.inc}
+
+interface
+
+implementation
+uses windows,common,messages,srv_player,wat_api
+ {$IFDEF DELPHI_7_UP}
+ ,variants
+ {$ENDIF}
+ {$IFDEF KOL_MCK}
+ ,kolcomobj
+ {$ELSE}
+ ,ComObj
+ {$ENDIF}
+;
+
+const
+ WMPOld:boolean=false;
+
+const
+// CLASS_MP :TGUID = '{22D6F312-B0F6-11D0-94AB-0080C74C7E95}';
+// CLASS_WMP:TGUID = '{6BF52A52-394A-11D3-B153-00C04F79FAA6}'; CLASS_WindowsMediaPlayer
+ MPCOMName = 'MediaPlayer.MediaPlayer.1';
+ WMPCOMName = 'WMPlayer.OCX.7';
+const
+ MPClass = 'Media Player 2';
+ WMPClass = 'WMPlayerApp';
+
+function Check(wnd:HWND;flags:integer):HWND;cdecl;
+begin
+ result:=FindWindowEx(0,wnd,MPClass,NIL);
+ if result=0 then
+ begin
+ result:=FindWindowEx(0,wnd,WMPClass,NIL); //?
+ WMPOld:=false;
+ end
+ else
+ WMPOld:=true;
+end;
+
+{ Version detect
+ fHasWMP64 = (WMP64.FileName="") ' WMP64 was create above via OBJECT tag else this returns False.
+ fHasWMP7 = (WMP7.URL = "") ' WMP7 or later was create above via OBJECT tag else this returns False.
+}
+
+const
+ MPVersion:PWideChar = '6.4';
+
+function GetVersionText(flags:integer):PWideChar;
+var
+ v:variant;
+begin
+ if WMPOld then
+ StrDupW(result,MPVersion)
+ else
+ begin
+ try
+ v:=CreateOleObject(WMPCOMName);
+ StrDupW(result,pWideChar(Widestring(v.versionInfo)));
+ except
+ result:=nil;
+ end;
+// VarClear(v);
+ v:=Null;
+ end;
+end;
+
+function GetInfo(var SongInfo:tSongInfo;flags:integer):integer;cdecl;
+begin
+ result:=0;
+ if (flags and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if SongInfo.txtver=nil then
+ SongInfo.txtver:=GetVersionText(flags);
+ end;
+end;
+
+{
+function Command(wnd:HWND;cmd:integer;value:integer):integer;cdecl;
+var
+ c:integer;
+begin
+ result:=0;
+ case cmd of
+// WAT_CTRL_PREV : c:=VK_B;
+// WAT_CTRL_PLAY : c:=VK_C;
+// WAT_CTRL_PAUSE: c:=VK_X;
+// WAT_CTRL_STOP : c:=VK_Z;
+// WAT_CTRL_NEXT : c:=VK_V;
+ WAT_CTRL_VOLDN: c:=VK_F9;
+ WAT_CTRL_VOLUP: c:=VK_F10;
+ else
+ exit;
+ end;
+ PostMessageW(wnd,WM_KEYDOWN,c,1);
+end;
+}
+const
+ plRec:tPlayerCell=(
+ Desc :'WMP';
+ flags :WAT_OPT_APPCOMMAND or WAT_OPT_SINGLEINST;
+ Icon :0;
+ Init :nil;
+ DeInit :nil;
+ Check :@Check;
+ GetStatus:nil;
+ GetName :nil;
+ GetInfo :@GetInfo;
+ Command :nil;
+ URL :'http://www.microsoft.com/windows/windowsmedia/players.aspx';
+ Notes :nil);
+
+var
+ LocalPlayerLink:twPlayer;
+
+procedure InitLink;
+begin
+ LocalPlayerLink.Next:=PlayerLink;
+ LocalPlayerLink.This:=@plRec;
+ PlayerLink :=@LocalPlayerLink;
+end;
+
+initialization
+// ServicePlayer(WAT_ACT_REGISTER,dword(@plRec));
+ InitLink;
+end.
diff --git a/plugins/Watrack/plugins/watrack_mpd/Makefile b/plugins/Watrack/plugins/watrack_mpd/Makefile
new file mode 100644
index 0000000000..02c89bd6d3
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/Makefile
@@ -0,0 +1,12 @@
+all:
+ i686-pc-mingw32-gcc -c -DBUILD_DLL -D UNICODE -D _UNICODE *.c -I../../include -I/usr/i686-pc-mingw32/usr/include -I. -w -mwin32 -mwindows -mdll -march=i686 -msse -O2 -pipe
+ i686-pc-mingw32-windres -i watrack_mpd.rc -o resources.o
+ i686-pc-mingw32-gcc -shared -o watrack_mpd.dll *.o -Wl,-O1,-s
+ upx -9 watrack_mpd.dll
+
+clean:
+ rm *.o
+
+clean-all:
+ rm *.o *.dll
+
diff --git a/plugins/Watrack/plugins/watrack_mpd/res/watrack_mpd.rc b/plugins/Watrack/plugins/watrack_mpd/res/watrack_mpd.rc
new file mode 100644
index 0000000000..17aaad10e4
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/res/watrack_mpd.rc
@@ -0,0 +1,112 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "src/resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_WA_MPD DIALOGEX 0, 0, 268, 214
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+FONT 8, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+ EDITTEXT IDC_SERVER,71,18,72,14,ES_AUTOHSCROLL
+ EDITTEXT IDC_PORT,72,38,72,14,ES_AUTOHSCROLL
+ EDITTEXT IDC_PASSWORD,71,58,73,14,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "MPD Host",IDC_STATIC,7,20,32,8
+ LTEXT "Port",IDC_STATIC,7,42,14,8
+ LTEXT "Password",IDC_STATIC,7,63,32,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPT_WA_MPD, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 261
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 207
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/commonheaders.h b/plugins/Watrack/plugins/watrack_mpd/src/commonheaders.h
new file mode 100644
index 0000000000..85eb73a335
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/commonheaders.h
@@ -0,0 +1,43 @@
+// Copyright © 2008 sss, chaos.persei
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#ifndef COMMONHEADERS_H
+#define COMMONHEADERS_H
+#include <windows.h>
+#include <tchar.h>
+#include <malloc.h>
+#include <time.h>
+
+
+#define MIRANDA_VER 0x0800
+#include <newpluginapi.h>
+#include <m_netlib.h>
+//#include <m_clist.h>
+//#include <m_skin.h>
+#include <m_database.h>
+//#include <m_protosvc.h>
+//#include <m_protocols.h>
+//#include <m_system.h>
+#include <m_options.h>
+#include <m_langpack.h>
+
+#include "resource.h"
+
+#include "constants.h"
+#include "globals.h"
+#include "main.h"
+#include "m_music.h"
+#include "utilities.h"
+#endif
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/constants.h b/plugins/Watrack/plugins/watrack_mpd/src/constants.h
new file mode 100644
index 0000000000..2ac58a4d43
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/constants.h
@@ -0,0 +1,4 @@
+#ifndef CONSTANTS_H
+#define CONSTANTS_H
+#define szModuleName "Watrack_MPD"
+#endif
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/globals.h b/plugins/Watrack/plugins/watrack_mpd/src/globals.h
new file mode 100644
index 0000000000..edc5bd10c3
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/globals.h
@@ -0,0 +1,11 @@
+#ifndef GLOBALS_H
+#define GLOBALS_H
+HANDLE ghNetlibUser;
+HANDLE ghConnection;
+HANDLE ghPacketReciever;
+BOOL bWatrackService;
+TCHAR *gbHost, *gbPassword;
+WORD gbPort;
+BOOL Connected;
+int gbState;
+#endif
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/init.c b/plugins/Watrack/plugins/watrack_mpd/src/init.c
new file mode 100644
index 0000000000..4d4f9eba29
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/init.c
@@ -0,0 +1,112 @@
+// Copyright © 2009-2010 sss
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "commonheaders.h"
+
+
+#define PLUGIN_NAME "Watrack_MPD"
+
+HINSTANCE hInst;
+BOOL bWatrackService = FALSE;
+int hLangpack = 0;
+static int OnModulesLoaded(WPARAM wParam,LPARAM lParam);
+extern char *date();
+extern int WaMpdOptInit(WPARAM wParam,LPARAM lParam);
+
+
+PLUGININFOEX pluginInfo={
+ sizeof(PLUGININFOEX),
+ 0,
+ PLUGIN_MAKE_VERSION(0,0,0,4),
+ "Music Player Daemon support for watrack",
+ "sss, others..",
+ "sss123next@list.ru",
+ "© 2009 sss, others...",
+ "http://sss.chaoslab.ru:81/tracker/mim_plugs/",
+ 1, //unicode
+ { 0x692e87d0, 0x6c71, 0x4cdc, { 0x9e, 0x36, 0x2b, 0x2d, 0x69, 0xfb, 0xdc, 0x4c } }
+
+};
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
+{
+ hInst=hinstDLL;
+ return TRUE;
+}
+
+__declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ {
+ static char plugname[52];
+ strcpy(plugname, PLUGIN_NAME" [");
+ strcat(plugname, date());
+ strcat(plugname, " ");
+ strcat(plugname, __TIME__);
+ strcat(plugname, "]");
+ pluginInfo.shortName = plugname;
+ }
+ return &pluginInfo;
+}
+
+static const MUUID interfaces[] = {MIID_SERVICEMODE, MIID_LAST};
+__declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
+{
+ return interfaces;
+}
+
+int __declspec(dllexport) Load()
+{
+ mir_getLP(&pluginInfo);
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
+ return 0;
+}
+
+void InitVars()
+{
+ gbPort = DBGetContactSettingWord(NULL, szModuleName, "Port", 6600);
+ gbPassword = (TCHAR*)malloc(64*sizeof(TCHAR));
+ gbHost = (TCHAR*)malloc(128*sizeof(TCHAR));
+ gbHost = UniGetContactSettingUtf(NULL, szModuleName, "Server", _T("127.0.0.1"));
+ gbPassword = UniGetContactSettingUtf(NULL, szModuleName, "Password", _T(""));
+}
+
+
+extern void RegisterPlayer();
+static int OnModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hHookOptionInit;
+ NETLIBUSER nlu = {0};
+ nlu.cbSize = sizeof(nlu);
+ nlu.flags = (NUF_OUTGOING | NUF_HTTPCONNS);
+ nlu.szDescriptiveName = "Watrack MPD connection";
+ nlu.szSettingsModule = PLUGIN_NAME;
+ ghNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
+ InitVars();
+ hHookOptionInit = HookEvent(ME_OPT_INITIALISE, WaMpdOptInit);
+ if (ServiceExists("WATrack/Player"))
+ bWatrackService = TRUE;
+ RegisterPlayer();
+
+ return 0;
+}
+
+
+int __declspec(dllexport) Unload(void)
+{
+ free(gbHost);
+ free(gbPassword);
+ return 0;
+}
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/m_music.h b/plugins/Watrack/plugins/watrack_mpd/src/m_music.h
new file mode 100644
index 0000000000..4b33881f06
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/m_music.h
@@ -0,0 +1,355 @@
+#ifndef M_MUSIC
+#define M_MUSIC
+
+#define MIID_WATRACK {0xfc6c81f4, 0x837e, 0x4430, {0x96, 0x01, 0xa0, 0xaa, 0x43, 0x17, 0x7a, 0xe3}}
+
+typedef struct tSongInfoA {
+ char *artist;
+ char *title;
+ char *album;
+ char *genre;
+ char *comment;
+ char *year;
+ char *mfile; // media file
+ int kbps;
+ int khz;
+ int channels;
+ int track;
+ int total; // music length
+ int time; // elapsed time
+ char *wndtext; // window title
+ char *player; // player name
+ int plyver; // player version
+ HANDLE icon; // player icon
+ int fsize; // media file size
+ int vbr;
+ int status; // player status: 0 - stopped; 1 - playing; 2 - paused
+ HWND plwnd; // player window
+ // video part
+ int codec;
+ int width;
+ int height;
+ int fps;
+ __int64 date;
+ char *txtver;
+ char *lyric;
+ char *cover;
+ int volume;
+ char *url;
+} SONGINFOA, *LPSONGINFOA;
+
+typedef struct tSongInfo {
+ wchar_t *artist;
+ wchar_t *title;
+ wchar_t *album;
+ wchar_t *genre;
+ wchar_t *comment;
+ wchar_t *year;
+ wchar_t *mfile; // media file
+ int kbps;
+ int khz;
+ int channels;
+ int track;
+ int total; // music length
+ int time; // elapsed time
+ wchar_t *wndtext; // window title
+ wchar_t *player; // player name
+ int plyver; // player version
+ HANDLE icon; // player icon
+ int fsize; // media file size
+ int vbr;
+ int status; // player status: 0 - stopped; 1 - playing; 2 - paused
+ HWND plwnd; // player window
+ // video part
+ int codec;
+ int width;
+ int height;
+ int fps;
+ __int64 date;
+ wchar_t *txtver;
+ // not implemented yet
+ wchar_t *lyric;
+ wchar_t *cover;
+ int volume;
+ wchar_t *url;
+} SONGINFO, *LPSONGINFO;
+
+#if defined(_UNICODE)
+ #define WAT_INF_TCHAR WAT_INF_UNICODE
+ #define SongInfoT tSongInfo
+#else
+ #define WAT_INF_TCHAR WAT_INF_ANSI
+ #define SongInfoT tSongInfoA
+#endif
+
+ // result codes
+#define WAT_RES_UNKNOWN -2
+#define WAT_RES_NOTFOUND -1
+#define WAT_RES_ERROR WAT_RES_NOTFOUND
+#define WAT_RES_OK 0
+#define WAT_RES_ENABLED WAT_RES_OK
+#define WAT_RES_DISABLED 1
+ // internal
+#define WAT_RES_NEWFILE 3
+
+#define WAT_PLS_NORMAL WAT_RES_OK
+#define WAT_PLS_NOMUSIC WAT_RES_DISABLED
+#define WAT_PLS_NOTFOUND WAT_RES_NOTFOUND
+
+#define WAT_INF_UNICODE 0
+#define WAT_INF_ANSI 1
+#define WAT_INF_UTF8 2
+#define WAT_INF_CHANGES 0x100
+
+/*
+ wParam : WAT_INF_* constant
+ lParam : pointer to LPSONGINGO (Unicode) or LPSONGINFOA (ANSI/UTF8)
+ Affects: Fill structure by currently played music info
+ returns: WAT_PLS_* constant
+ note: pointer will be point to global SONGINFO structure of plugin
+ warning: Non-Unicode data filled only by request
+ if lParam=0 only internal SongInfo structure will be filled
+ Example:
+ LPSONGINFO p;
+ PluginLink->CallService(MS_WAT_GETMUSICINFO,0,(DWORD)&p);
+*/
+
+#define MS_WAT_GETMUSICINFO "WATrack/GetMusicInfo"
+
+/*
+ wParam:0
+ lParam : pointer to pSongInfo (Unicode)
+ Affects: Fill structure by info from file named in SongInfo.mfile
+ returns: 0, if success
+ note: fields, which values can't be obtained, leaves old values.
+ you must free given strings by miranda mmi.free
+*/
+#define MS_WAT_GETFILEINFO "WATrack/GetFileInfo"
+
+/*
+ wParam: encoding (WAT_INF_* consts, 0 = WAT_INF_UNICODE)
+ lParam: codepage (0 = ANSI)
+ Returns Global unicode SongInfo pointer or tranlated to Ansi/UTF8 structure
+*/
+#define MS_WAT_RETURNGLOBAL "WATrack/GetMainStructure"
+
+#define WAT_CTRL_PREV 1
+#define WAT_CTRL_PLAY 2
+#define WAT_CTRL_PAUSE 3
+#define WAT_CTRL_STOP 4
+#define WAT_CTRL_NEXT 5
+#define WAT_CTRL_VOLDN 6
+#define WAT_CTRL_VOLUP 7
+#define WAT_CTRL_SEEK 8 // lParam is new position (sec)
+/*
+ wParam: button code (WAT_CTRL_* const)
+ lParam: 0, or value (see WAT_CTRL_* const comments)
+ Affects: emulate player button pressing
+ returns: 0 if unsuccesful
+*/
+#define MS_WAT_PRESSBUTTON "WATrack/PressButton"
+
+/*
+ Get user's Music Info
+*/
+#define MS_WAT_GETCONTACTINFO = "WATrack/GetContactInfo"
+
+// ------------ Plugin/player status ------------
+
+/*
+ wParam: 1 - switch off plugin
+ 0 - switch on plugin
+ -1 - switch plugin status
+ 2 - get plugin version
+ other - get plugin status
+ lParam: 0
+ Affects: Switch plugin status to enabled or disabled
+ returns: version, old plugin status, 0, if was enabled
+*/
+
+#define MS_WAT_PLUGINSTATUS "WATrack/PluginStatus"
+
+#define ME_WAT_MODULELOADED "WATrack/ModuleLoaded"
+
+#define WAT_EVENT_PLAYERSTATUS 1 // 0-normal; 1-no music (possibly stopped); 2-not found
+#define WAT_EVENT_NEWTRACK 2
+#define WAT_EVENT_PLUGINSTATUS 3 // 0-enabled; 1-dis.temporary; 2-dis.permanent
+#define WAT_EVENT_NEWPLAYER 4 //
+#define WAT_EVENT_NEWTEMPLATE 5 // TM_* constant
+
+/*
+ Plugin or player status changed:
+ wParam: type of event (see above)
+ lParam: value
+*/
+#define ME_WAT_NEWSTATUS "WATrack/NewStatus"
+
+// ---------- Popup module ------------
+
+/*
+ wParam: not used
+ lParam: not used
+ Affects: Show popup or Info window with current music information
+ note: Only Info window will be showed if Popup plugin disabled
+*/
+
+#define MS_WAT_SHOWMUSICINFO "WATrack/ShowMusicInfo"
+
+// --------- Statistic (report) module -------------
+
+/*
+ wParam: pointer to log file name or NULL
+ lParam: pointer to report file name or NULL
+ Affects: Create report from log and run it (if option is set)
+ returns: 0 if unsuccesful
+ note: if wParam or lParam is a NULL then file names from options are used
+*/
+#define MS_WAT_MAKEREPORT "WATrack/MakeReport"
+
+/*
+ wParam, lParam - not used
+ Affects: pack statistic file
+*/
+#define MS_WAT_PACKLOG = "WATrack/PackLog"
+
+/*
+ wParam: not used
+ lParam: pointer to SongInfo
+*/
+#define MS_WAT_ADDTOLOG = "WATrack/AddToLog"
+
+// ----------- Formats and players -----------
+
+// media file status
+
+#define WAT_MES_STOPPED 0
+#define WAT_MES_PLAYING 1
+#define WAT_MES_PAUSED 2
+#define WAT_MES_UNKNOWN -1
+
+#define WAT_ACT_REGISTER 1
+#define WAT_ACT_UNREGISTER 2
+#define WAT_ACT_DISABLE 3
+#define WAT_ACT_ENABLE 4
+#define WAT_ACT_GETSTATUS 5 // not found/enabled/disabled
+#define WAT_ACT_SETACTIVE 6
+#define WAT_ACT_REPLACE 0x10000 // can be combined with WAT_REGISTERFORMAT
+
+ // flags
+#define WAT_OPT_DISABLED 0x00000001 // format registered but disabled
+#define WAT_OPT_ONLYONE 0x00000002 // format can't be overwriten
+#define WAT_OPT_PLAYERINFO 0x00000004 // song info from player
+#define WAT_OPT_WINAMPAPI 0x00000008 // Winamp API support
+#define WAT_OPT_CHECKTIME 0x00000010 // check file time for changes
+#define WAT_OPT_VIDEO 0x00000020 // only for format registering used
+#define WAT_OPT_LAST 0x00000040 // (internal)
+#define WAT_OPT_FIRST 0x00000080 // (internal)
+#define WAT_OPT_TEMPLATE 0x00000100 // (internal)
+#define WAT_OPT_IMPLANTANT 0x00000200 // use process implantation
+#define WAT_OPT_HASURL 0x00000400 // (player registration) URL field present
+#define WAT_OPT_CHANGES 0x00000800 // obtain only chaged values
+ // (volume, status, window text, elapsed time)
+#define WAT_OPT_APPCOMMAND 0x00001000 // Special (multimedia) key support
+#define WAT_OPT_CHECKALL 0x00002000 // Check all players
+#define WAT_OPT_KEEPOLD 0x00004000 // Keep Old opened file
+#define WAT_OPT_MULTITHREAD 0x00008000 // Use multithread scan
+#define WAT_OPT_SINGLEINST 0x00010000 // Single player instance
+
+
+typedef BOOL (__cdecl *LPREADFORMATPROC)(LPSONGINFO Info);
+
+typedef struct tMusicFormat {
+ LPREADFORMATPROC proc;
+ char ext[8];
+ int flags;
+} MUSICFORMAT, *LPMUSICFORMAT;
+
+/*
+ wParam: action
+ lParam: pointer to MUSICFORMAT if wParam = WAT_ACT_REGISTER,
+ else - pointer to extension string (ANSI)
+ returns: see result codes
+*/
+
+#define MS_WAT_FORMAT "WATrack/Format"
+
+/*
+ wParam - pointer to SONGINFO structure (plwind field must be initialized)
+ lParam - flags
+*/
+
+#define MS_WAT_WINAMPINFO "WATrack/WinampInfo"
+
+/*
+ wParam: window
+ lParam: LoWord - command; HiWord - value
+*/
+
+#define MS_WAT_WINAMPCOMMAND "WATrack/WinampCommand"
+
+int tInitProc();
+int tDeInitProc();
+int tStatusProc();
+
+typedef int (__cdecl *LPINITPROC)();
+typedef int (__cdecl *LPDEINITPROC)();
+typedef int (__cdecl *LPSTATUSPROC)(HWND wnd);
+typedef wchar_t (__cdecl *LPNAMEPROC)(HWND wnd, int flags);
+typedef HWND (__cdecl *LPCHECKPROC)(HWND wnd, int flags);
+typedef int (__cdecl *LPGETSTATUSPROC) (HWND wnd);
+typedef int (__cdecl *LPINFOPROC)(LPSONGINFO Info, int flags);
+typedef int (__cdecl *LPCOMMANDPROC)(HWND wnd, int command, int value);
+
+typedef struct tPlayerCell {
+ char *Desc;
+ int flags;
+ HICON Icon; // can be 0. for registration only
+ LPINITPROC Init;
+ LPDEINITPROC DeInit;
+ LPCHECKPROC Check; // check player
+ LPGETSTATUSPROC GetStatus;
+ LPNAMEPROC GetName; // can be NULL. get media filename
+ LPINFOPROC GetInfo; // can be NULL. get info from player
+ LPCOMMANDPROC Command; // can be NULL. send command to player
+ char *URL; // only if WAT_OPT_HASURL flag present
+ wchar_t *Notes;
+} PLAYERCELL, *LPPLAYERCELL;
+
+/*
+ wParam: action
+ lParam: pointer to PLAYERCELL if wParam = WAT_ACT_REGISTER,
+ else - pointer to player description string (ANSI)
+ returns: player window handle or value>0 if found
+ note: If you use GetName or GetInfo field, please, do not return empty
+ filename even when mediafile is remote!
+*/
+
+#define MS_WAT_PLAYER "WATrack/Player"
+
+// --------- Templates ----------
+
+/*
+ wParam: not used
+ lParam: Unicode template
+ returns: New Unicode (replaced) string
+*/
+#define MS_WAT_REPLACETEXT "WATrack/ReplaceText"
+
+/*
+ event types for History
+ Blob structure for EVENTTYPE_WAT_ANSWER:
+ Uniciode artist#0title#0album#0answer
+*/
+#define EVENTTYPE_WAT_REQUEST 9601
+#define EVENTTYPE_WAT_ANSWER 9602
+#define EVENTTYPE_WAT_ERROR 9603
+#define EVENTTYPE_WAT_MESSAGE 9604
+
+/*
+ wParam: 0 or parent window
+ lParam: 0
+ note: Shows Macro help window with edit aliases ability
+*/
+#define MS_WAT_MACROHELP "WATrack/MacroHelp"
+
+#endif
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/main.c b/plugins/Watrack/plugins/watrack_mpd/src/main.c
new file mode 100644
index 0000000000..17a8c29d64
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/main.c
@@ -0,0 +1,433 @@
+// Copyright © 2008 sss, chaos.persei
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+
+
+#include "commonheaders.h"
+
+
+//maybe add mutex ?
+void Start(void *param);
+int Parser();
+
+LPINITPROC Init()
+{
+ mir_forkthread(&Start, 0);
+ return 0;
+}
+void Stop();
+LPDEINITPROC DeInit()
+{
+ Stop();
+ return 0;
+}
+LPCHECKPROC CheckPlayer(HWND wnd, int flags)
+{
+ if(!ghConnection)
+ {
+ mir_forkthread(&Start, 0);
+ return 0;
+ }
+ if(Parser())
+ return (LPCHECKPROC)WAT_MES_STOPPED;
+ if(Connected)
+ return (LPCHECKPROC)WAT_MES_PLAYING;
+ return 0;
+}
+LPGETSTATUSPROC GetStatus()
+{
+ if(!ghConnection)
+ {
+ mir_forkthread(&Start, 0);
+ return 0;
+ }
+ if(Parser())
+ return (LPGETSTATUSPROC)-1;
+ return (LPGETSTATUSPROC)(gbState);
+}
+LPNAMEPROC GetFileName(HWND wnd, int flags)
+{
+ if(!ghConnection)
+ {
+ mir_forkthread(&Start, 0);
+ return 0;
+ }
+ return 0;
+}
+SONGINFO SongInfo = {0};
+
+LPINFOPROC GetPlayerInfo(LPSONGINFO info, int flags)
+{
+ if(!ghConnection)
+ {
+ mir_forkthread(&Start, 0);
+ return 0;
+ }
+ if(Parser())
+ return (LPINFOPROC)-1;
+/*
+
+ info->channels = SongInfo.channels;
+ info->codec = SongInfo.codec;
+ info->comment = SongInfo.comment;
+ info->cover = SongInfo.cover;
+ info->date = SongInfo.date;
+ info->fps = SongInfo.fps;
+ info->fsize = SongInfo.fsize;
+
+ info->icon = SongInfo.icon;
+ info->kbps = SongInfo.kbps;
+ info->khz = SongInfo.khz;
+ info->lyric = SongInfo.lyric;
+ info->mfile = SongInfo.mfile;
+ info->player = SongInfo.player;
+ info->plyver = SongInfo.plyver;
+ info->status = SongInfo.status;
+ info->time = SongInfo.time;
+ info->title = SongInfo.title;
+ info->total = SongInfo.total;
+ info->track = SongInfo.track;*/
+ info->total = SongInfo.total;
+ info->time = SongInfo.time;
+ info->mfile = SongInfo.mfile;
+ info->txtver = SongInfo.txtver;
+ info->title = SongInfo.title;
+ info->artist = SongInfo.artist;
+ info->genre = SongInfo.genre;
+ info->album = SongInfo.album;
+ info->year = SongInfo.year;
+ info->kbps = SongInfo.kbps;
+ info->track = SongInfo.track;
+ info->khz = SongInfo.khz;
+ info->volume = SongInfo.volume;
+/* info->url = SongInfo.url; //??
+ info->vbr = SongInfo.vbr;
+ info->volume = SongInfo.volume;
+ */
+ return 0;
+}
+LPCOMMANDPROC SendCommand(HWND wnd, int command, int value)
+{
+ switch (command)
+ {
+ case WAT_CTRL_PREV:
+ Netlib_Send(ghConnection, "previous\n", strlen("previous\n"), 0);
+ break;
+ case WAT_CTRL_PLAY: //add resuming support
+ if(gbState != WAT_MES_PAUSED)
+ Netlib_Send(ghConnection, "play\n", strlen("play\n"), 0);
+ else
+ Netlib_Send(ghConnection, "pause 0\n", strlen("pause 0\n"), 0);
+ break;
+ case WAT_CTRL_PAUSE:
+ Netlib_Send(ghConnection, "pause 1\n", strlen("pause 1\n"), 0);
+ break;
+ case WAT_CTRL_STOP:
+ Netlib_Send(ghConnection, "stop\n", strlen("stop\n"), 0);
+ break;
+ case WAT_CTRL_NEXT:
+ Netlib_Send(ghConnection, "next\n", strlen("next\n"), 0);
+ break;
+ case WAT_CTRL_VOLDN:
+ break;
+ case WAT_CTRL_VOLUP:
+ break;
+ case WAT_CTRL_SEEK:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+void RegisterPlayer()
+{
+ if(!bWatrackService)
+ return;
+ {
+ PLAYERCELL player = {0};
+ player.Desc = "Music Player Daemon";
+ player.Check = (LPCHECKPROC)CheckPlayer;
+ player.Init = (LPINITPROC)Init;
+ player.DeInit = (LPDEINITPROC)DeInit;
+ player.GetStatus = (LPGETSTATUSPROC)GetStatus;
+ player.Command = (LPCOMMANDPROC)SendCommand;
+ player.flags = (WAT_OPT_HASURL|WAT_OPT_SINGLEINST|WAT_OPT_PLAYERINFO);
+ player.GetName = (LPNAMEPROC)GetFileName;
+ player.GetInfo = (LPINFOPROC)GetPlayerInfo;
+// player.Icon = //TODO:implement icon support
+ player.Notes = _T("mpd is a nice music player for *nix which have not any gui, just daemon.\nuses very small amount of ram, cpu.");
+ player.URL = "http://www.musicpd.org";
+ CallService(MS_WAT_PLAYER, (WPARAM)WAT_ACT_REGISTER, (LPARAM)&player);
+ }
+}
+void ReStart(void *data);
+int Parser()
+{
+ static NETLIBPACKETRECVER nlpr = {0};
+ char *ptr;
+ char tmp[256];
+ int i;
+ char *buf;
+ static char ver[16];
+ nlpr.cbSize = sizeof(nlpr);
+ nlpr.dwTimeout = 5;
+ if(!ghConnection)
+ {
+ mir_forkthread(&Start, 0);
+ }
+ if(ghConnection)
+ {
+ int recvResult;
+/* do
+ {
+ recvResult = CallService(MS_NETLIB_GETMOREPACKETS,(WPARAM)ghPacketReciever, (LPARAM)&nlpr);
+ if(recvResult == SOCKET_ERROR)
+ {
+ ReStart();
+ return 1;
+ }
+ }
+ while(recvResult > 0);*/
+ if(!Connected)
+ {
+ char tmp[128];
+ char *tmp2 = mir_t2a(gbPassword);
+ recvResult = CallService(MS_NETLIB_GETMOREPACKETS,(WPARAM)ghPacketReciever, (LPARAM)&nlpr);
+ if(recvResult == SOCKET_ERROR)
+ {
+ mir_forkthread(&ReStart, 0);
+// ReStart();
+ return 1;
+ }
+ if(strlen(tmp2) > 2)
+ {
+ strcpy(tmp, "password ");
+ strcat(tmp, tmp2);
+ strcat(tmp, "\n");
+ Netlib_Send(ghConnection, tmp, strlen(tmp), 0);
+ recvResult = CallService(MS_NETLIB_GETMOREPACKETS,(WPARAM)ghPacketReciever, (LPARAM)&nlpr);
+ if(recvResult == SOCKET_ERROR)
+ {
+ mir_forkthread(&ReStart, 0);
+ return 1;
+ }
+ }
+ mir_free(tmp2);
+ }
+ Netlib_Send(ghConnection, "status\n", strlen("status\n"), 0);
+ recvResult = CallService(MS_NETLIB_GETMOREPACKETS,(WPARAM)ghPacketReciever, (LPARAM)&nlpr);
+ if(recvResult == SOCKET_ERROR)
+ {
+ mir_forkthread(&ReStart, 0);
+ return 1;
+ }
+ Netlib_Send(ghConnection, "currentsong\n", strlen("currentsong\n"), 0);
+ recvResult = CallService(MS_NETLIB_GETMOREPACKETS,(WPARAM)ghPacketReciever, (LPARAM)&nlpr);
+ if(recvResult == SOCKET_ERROR)
+ {
+ mir_forkthread(&ReStart, 0);
+ return 1;
+ }
+ nlpr.bytesUsed = nlpr.bytesAvailable;
+ }
+ buf = nlpr.buffer;
+ if(ptr = strstr(buf, "MPD"))
+ {
+ Connected = TRUE;
+ ptr = &ptr[4];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ strcpy(ver, tmp);
+ SongInfo.txtver = (TCHAR*)mir_utf8decodeW(tmp);
+ }
+ else
+ SongInfo.txtver = (TCHAR*)mir_utf8decodeW(ver);
+ if(ptr = strstr(buf, "file:"))
+ {
+ ptr = &ptr[6];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.mfile = (TCHAR*)mir_utf8decodeW(tmp);
+ }
+ else
+ SongInfo.mfile = _T("");
+ if(ptr = strstr(buf, "Time:"))
+ {
+ ptr = &ptr[6];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.total = atoi(tmp);
+ }
+ else if(!SongInfo.total)
+ SongInfo.total = 0;
+ if(ptr = strstr(buf, "time:"))
+ {
+ ptr = &ptr[6];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.time = atoi(tmp);
+ }
+ else if(!SongInfo.time)
+ SongInfo.time = 0;
+ if(ptr = strstr(buf, "Title:"))
+ {
+ ptr = &ptr[7];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.title = (TCHAR*)mir_utf8decodeW(tmp);
+ }
+ else
+ SongInfo.title = _T("Unknown track");
+ if(ptr = strstr(buf, "Artist:"))
+ {
+ ptr = &ptr[8];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.artist = (TCHAR*)mir_utf8decodeW(tmp);
+ }
+ else
+ SongInfo.artist = _T("Unknown artist");
+ if(ptr = strstr(buf, "Genre:"))
+ {
+ ptr = &ptr[7];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.genre = (TCHAR*)mir_utf8decodeW(tmp);
+ }
+ else
+ SongInfo.genre = _T("Unknown genre");
+ if(ptr = strstr(buf, "Album:"))
+ {
+ ptr = &ptr[7];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.album = (TCHAR*)mir_utf8decodeW(tmp);
+ }
+ else
+ SongInfo.album = _T("Unknown album");
+ if(ptr = strstr(buf, "Date:"))
+ {
+ ptr = &ptr[6];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.year = (TCHAR*)mir_utf8decodeW(tmp);
+ }
+ else
+ SongInfo.year = _T("Unknown year");
+ if(ptr = strstr(buf, "volume:"))
+ {
+ ptr = &ptr[8];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.volume = atoi(tmp);
+ }
+ else if(!SongInfo.volume)
+ SongInfo.volume = 0;
+ if(ptr = strstr(buf, "audio:"))
+ {
+ ptr = &ptr[7];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.khz = atoi(tmp);
+ }
+ else if(!SongInfo.khz)
+ SongInfo.khz = 0;
+ if(ptr = strstr(buf, "bitrate:"))
+ {
+ ptr = &ptr[9];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.kbps = atoi(tmp);
+ }
+ else if(!SongInfo.kbps)
+ SongInfo.kbps = 0;
+
+ if(ptr = strstr(buf, "Track:"))
+ {
+ ptr = &ptr[7];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ SongInfo.track = atoi(tmp);
+ }
+ else if(!SongInfo.track)
+ SongInfo.track = 0;
+ if(ptr = strstr(buf, "state:"))
+ {
+ ptr = &ptr[7];
+ for(i = 0; ((ptr[i] != '\n') && (ptr[i] != '\0')); i++)
+ tmp[i] = ptr[i];
+ tmp[i] = '\0';
+ if(strstr(tmp, "play"))
+ gbState = WAT_MES_PLAYING;
+ if(strstr(tmp, "pause"))
+ gbState = WAT_MES_PAUSED;
+ if(strstr(tmp, "stop"))
+ gbState = WAT_MES_STOPPED;
+ }
+ else if(!gbState)
+ gbState = WAT_MES_UNKNOWN;
+ return 0;
+}
+
+
+void Start(void* param)
+{
+ NETLIBOPENCONNECTION nloc = {0};
+ char *tmp = (char*)mir_u2a(gbHost);
+ nloc.cbSize = sizeof(nloc);
+ nloc.szHost = tmp;
+ nloc.timeout = 5;
+ nloc.wPort = gbPort;
+ Connected = FALSE;
+ ghConnection = NetLib_CreateConnection(ghNetlibUser, &nloc);
+ if(ghConnection)
+ ghPacketReciever = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER,(WPARAM)ghConnection,2048);
+}
+void Stop()
+{
+ if(ghPacketReciever)
+ Netlib_CloseHandle(ghPacketReciever);
+ if(ghConnection)
+ Netlib_CloseHandle(ghConnection);
+ if(ghNetlibUser && (ghNetlibUser != INVALID_HANDLE_VALUE))
+ CallService(MS_NETLIB_SHUTDOWN,(WPARAM)ghNetlibUser,0);
+}
+void ReStart(void *param)
+{
+ if(ghPacketReciever)
+ Netlib_CloseHandle(ghPacketReciever);
+ if(ghConnection)
+ Netlib_CloseHandle(ghConnection);
+ Sleep(500);
+ mir_forkthread(&Start, 0);
+}
+
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/main.h b/plugins/Watrack/plugins/watrack_mpd/src/main.h
new file mode 100644
index 0000000000..4dcd949c11
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/main.h
@@ -0,0 +1,24 @@
+// Copyright © 2008 sss, chaos.persei
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#ifndef MAIN_H
+#define MAIN_H
+
+//TCHAR* __stdcall UniGetContactSettingUtf(HANDLE hContact, const char *szModule,const char* szSetting, TCHAR* szDef);
+//const TCHAR *stristr( const TCHAR *str, const TCHAR *substr);
+
+#endif
+
+
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/options.c b/plugins/Watrack/plugins/watrack_mpd/src/options.c
new file mode 100644
index 0000000000..ef607d78ed
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/options.c
@@ -0,0 +1,91 @@
+// Copyright © 2008 sss, chaos.persei
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "commonheaders.h"
+#include <uxtheme.h>
+
+HINSTANCE hInst;
+static INT_PTR CALLBACK DlgProcWaMpdOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+int WaMpdOptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_WA_MPD);
+ odp.ptszTitle = LPGENT("Winamp Track");
+ odp.ptszGroup = LPGENT("Plugins");
+ odp.ptszTab = LPGENT("Watrack MPD");
+ odp.flags=ODPF_BOLDGROUPS|ODPF_TCHAR;
+ odp.pfnDlgProc = DlgProcWaMpdOpts;
+ Options_AddPage(wParam, &odp);
+ return 0;
+}
+
+
+static INT_PTR CALLBACK DlgProcWaMpdOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemInt(hwndDlg, IDC_PORT, DBGetContactSettingWord(NULL, szModuleName, "Port", 6600), FALSE);
+ SetDlgItemText(hwndDlg, IDC_SERVER, UniGetContactSettingUtf(NULL, szModuleName, "Server", _T("127.0.0.1")));
+ SetDlgItemText(hwndDlg, IDC_PASSWORD, UniGetContactSettingUtf(NULL, szModuleName, "Password", _T("")));
+ return TRUE;
+ }
+
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+
+ }
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+
+ case WM_NOTIFY:
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+
+ case PSN_APPLY:
+ {
+ TCHAR szText[128];
+ DBWriteContactSettingWord(NULL, szModuleName, "Port", (WORD)GetDlgItemInt(hwndDlg, IDC_PORT, NULL, FALSE));
+ gbPort = (WORD)GetDlgItemInt(hwndDlg, IDC_PORT, NULL, FALSE);
+ GetDlgItemText(hwndDlg, IDC_SERVER, szText, sizeof(szText));
+ DBWriteContactSettingTString(NULL, szModuleName, "Server", szText);
+ _tcscpy(gbHost, szText);
+ GetDlgItemText(hwndDlg, IDC_PASSWORD, szText, sizeof(szText));
+ DBWriteContactSettingTString(NULL, szModuleName, "Password", szText);
+ _tcscpy(gbPassword, szText);
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+
+
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/resource.h b/plugins/Watrack/plugins/watrack_mpd/src/resource.h
new file mode 100644
index 0000000000..15f3d472f1
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/resource.h
@@ -0,0 +1,32 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by watrack_mpd.rc
+//
+#define IDD_OPT_DOS 104
+#define IDD_OPT_WA_MPD 104
+#define IDC_FOR_ONLINE 1003
+#define IDC_MSG_NUMBER 1004
+#define IDC_MSG_TEXT 1005
+#define IDC_MSG_RATE 1006
+#define IDC_ENABLE_CUSTOM_MESSAGE 1007
+#define IDC_FOR_ONLINE2 1008
+#define IDC_CLIENT_BASED 1008
+#define IDC_MESSAGE_SIZE 1009
+#define IDC_MSG_SIZE 1009
+#define IDC_MSG_SIZE2 1010
+#define IDC_CHAR_COUNT 1010
+#define IDC_SERVER 1011
+#define IDC_PORT 1012
+#define IDC_EDIT3 1013
+#define IDC_PASSWORD 1013
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1016
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/utilities.c b/plugins/Watrack/plugins/watrack_mpd/src/utilities.c
new file mode 100644
index 0000000000..444a6d210d
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/utilities.c
@@ -0,0 +1,126 @@
+// Copyright © 2008 sss, chaos.persei
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#include "commonheaders.h"
+
+/*HANDLE CreateThreadEx(pThreadFuncEx AFunc, void* arg, DWORD* pThreadID)
+{
+ FORK_THREADEX_PARAMS params;
+ DWORD dwThreadId;
+ HANDLE hThread;
+
+ params.pFunc = AFunc;
+ params.arg = arg;
+ params.iStackSize = 0;
+ params.threadID = &dwThreadId;
+ hThread = (HANDLE)CallService(MS_SYSTEM_FORK_THREAD_EX, 0, (LPARAM)&params);
+ if (pThreadID)
+ *pThreadID = dwThreadId;
+
+ return hThread;
+}*/
+
+TCHAR* __stdcall UniGetContactSettingUtf(HANDLE hContact, const char *szModule,const char* szSetting, TCHAR* szDef)
+{
+ DBVARIANT dbv = {DBVT_DELETED};
+ TCHAR* szRes;
+ if (DBGetContactSettingTString(hContact, szModule, szSetting, &dbv))
+ return _tcsdup(szDef);
+ if(dbv.pszVal)
+ szRes = _tcsdup(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ return szRes;
+}
+
+// case-insensitive _tcsstr
+/*#define NEWTSTR_ALLOCA(A) (A==NULL)?NULL:_tcscpy((TCHAR*)alloca(sizeof(TCHAR)*(_tcslen(A)+1)),A)
+const TCHAR *stristr( const TCHAR *str, const TCHAR *substr)
+{
+ TCHAR *p;
+ TCHAR *str_up = NEWTSTR_ALLOCA(str);
+ TCHAR *substr_up = NEWTSTR_ALLOCA(substr);
+
+ CharUpperBuff(str_up, lstrlen(str_up));
+ CharUpperBuff(substr_up, lstrlen(substr_up));
+
+ p = _tcsstr(str_up, substr_up);
+ return p ? (str + (p - str_up)) : NULL;
+}*/
+
+char *date()
+{
+ static char d[11];
+ char *tmp = __DATE__, m[4], mn[3] = "01";
+ m[0]=tmp[0];
+ m[1]=tmp[1];
+ m[2]=tmp[2];
+ if(strstr(m,"Jan"))
+ strcpy(mn,"01");
+ else if(strstr(m,"Feb"))
+ strcpy(mn,"02");
+ else if(strstr(m,"Mar"))
+ strcpy(mn,"03");
+ else if(strstr(m,"Apr"))
+ strcpy(mn,"04");
+ else if(strstr(m,"May"))
+ strcpy(mn,"05");
+ else if(strstr(m,"Jun"))
+ strcpy(mn,"06");
+ else if(strstr(m,"Jul"))
+ strcpy(mn,"07");
+ else if(strstr(m,"Aug"))
+ strcpy(mn,"08");
+ else if(strstr(m,"Sep"))
+ strcpy(mn,"09");
+ else if(strstr(m,"Oct"))
+ strcpy(mn,"10");
+ else if(strstr(m,"Nov"))
+ strcpy(mn,"11");
+ else if(strstr(m,"Dec"))
+ strcpy(mn,"12");
+ d[0]=tmp[7];
+ d[1]=tmp[8];
+ d[2]=tmp[9];
+ d[3]=tmp[10];
+ d[4]='.';
+ d[5]=mn[0];
+ d[6]=mn[1];
+ d[7]='.';
+ if (tmp[4] == ' ')
+ d[8] = '0';
+ else
+ d[8]=tmp[4];
+ d[9]=tmp[5];
+ return d;
+}
+HANDLE NetLib_CreateConnection(HANDLE hUser, NETLIBOPENCONNECTION* nloc) //from icq )
+{
+ HANDLE hConnection;
+
+ nloc->cbSize = sizeof(NETLIBOPENCONNECTION);
+ nloc->flags |= NLOCF_V2;
+
+ hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hUser, (LPARAM)nloc);
+ if (!hConnection && (GetLastError() == 87))
+ { // this ensures, an old Miranda will be able to connect also
+ nloc->cbSize = NETLIBOPENCONNECTION_V1_SIZE;
+ hConnection = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hConnection, (LPARAM)nloc);
+ }
+ return hConnection;
+}
+
+
diff --git a/plugins/Watrack/plugins/watrack_mpd/src/utilities.h b/plugins/Watrack/plugins/watrack_mpd/src/utilities.h
new file mode 100644
index 0000000000..8cef30fb25
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/src/utilities.h
@@ -0,0 +1,6 @@
+#ifndef UTILITIES_H
+#define UTILITIES_H
+HANDLE NetLib_CreateConnection(HANDLE hUser, NETLIBOPENCONNECTION* nloc);
+HANDLE CreateThreadEx(pThreadFuncEx AFunc, void* arg, DWORD* pThreadID);
+TCHAR* __stdcall UniGetContactSettingUtf(HANDLE hContact, const char *szModule,const char* szSetting, TCHAR* szDef);
+#endif
diff --git a/plugins/Watrack/plugins/watrack_mpd/watrack_mpd.vcxproj b/plugins/Watrack/plugins/watrack_mpd/watrack_mpd.vcxproj
new file mode 100644
index 0000000000..8f8de22140
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/watrack_mpd.vcxproj
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\init.c" />
+ <ClCompile Include="src\main.c" />
+ <ClCompile Include="src\options.c" />
+ <ClCompile Include="src\utilities.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\commonheaders.h" />
+ <ClInclude Include="src\constants.h" />
+ <ClInclude Include="src\globals.h" />
+ <ClInclude Include="src\main.h" />
+ <ClInclude Include="src\m_music.h" />
+ <ClInclude Include="src\resource.h" />
+ <ClInclude Include="src\utilities.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\watrack_mpd.rc" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{F29D0C8D-141A-43CF-86B2-34A04653F8D4}</ProjectGuid>
+ <RootNamespace>watrack_mpd</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">
+ <CharacterSet>Unicode</CharacterSet>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\Debug\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release Unicode/testplug.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;FULL_BUILD;%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0809</Culture>
+ </ResourceCompile>
+ <Link>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>.\Release Unicode/testplug.lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Release Unicode/testplug.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TypeLibraryName>.\Release Unicode/testplug.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;FULL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <FloatingPointModel>Precise</FloatingPointModel>
+ <PrecompiledHeaderOutputFile>.\Release Unicode/testplug.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Release Unicode/</AssemblerListingLocation>
+ <ObjectFileName>.\Release Unicode/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release Unicode/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0809</Culture>
+ </ResourceCompile>
+ <Link>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>.\Release Unicode/testplug.lib</ImportLibrary>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);mir_core64.lib;Miranda64.lib</AdditionalDependencies>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Release Unicode/testplug.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug/testplug.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>X:\install\git\miranda\miranda-im\miranda\include;../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;TESTPLUG_EXPORTS;_CRT_SECURE_NO_WARNINGS;FULL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeaderOutputFile>.\Debug/testplug.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0809</Culture>
+ </ResourceCompile>
+ <Link>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>.\Debug/testplug.lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Debug/testplug.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TypeLibraryName>.\Debug/testplug.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>X:\install\git\miranda\miranda-im\miranda\include;../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;TESTPLUG_EXPORTS;_CRT_SECURE_NO_WARNINGS;FULL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeaderOutputFile>.\Debug/testplug.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0809</Culture>
+ </ResourceCompile>
+ <Link>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>.\Debug/testplug.lib</ImportLibrary>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Debug/testplug.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/Watrack/plugins/watrack_mpd/watrack_mpd.vcxproj.filters b/plugins/Watrack/plugins/watrack_mpd/watrack_mpd.vcxproj.filters
new file mode 100644
index 0000000000..67721aee48
--- /dev/null
+++ b/plugins/Watrack/plugins/watrack_mpd/watrack_mpd.vcxproj.filters
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Sources">
+ <UniqueIdentifier>{2c37ce60-87c1-44a6-85ff-147b48dd84f4}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Headers">
+ <UniqueIdentifier>{1d016f21-3dfc-4617-a16d-2543db03d939}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resources">
+ <UniqueIdentifier>{67db7959-3d43-439b-ae9b-8223911c651d}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\init.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="src\main.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="src\options.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ <ClCompile Include="src\utilities.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\commonheaders.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="src\constants.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="src\globals.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="src\m_music.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="src\main.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="src\resource.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ <ClInclude Include="src\utilities.h">
+ <Filter>Headers</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\watrack_mpd.rc">
+ <Filter>Resources</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/Watrack/popup/pop_dlg.inc b/plugins/Watrack/popup/pop_dlg.inc
new file mode 100644
index 0000000000..129b538780
--- /dev/null
+++ b/plugins/Watrack/popup/pop_dlg.inc
@@ -0,0 +1,179 @@
+{PopUp Option Dialog}
+
+// PopUp options
+const
+ DLGPOPUP = 'POPUP';
+
+function DlgPopUpOpt(Dialog:HWnd;hMessage:Uint;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
+const
+ dlginit:boolean=false;
+var
+ tmp:longbool;
+ ppd:PPOPUPDATAW;
+ fore,back:HWND;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ dlginit:=false;
+
+ SetDlgItemTextW(Dialog,IDC_POPUP_TITLE,PopTitle);
+ SetDlgItemTextW(Dialog,IDC_POPUP_TEXT ,PopText);
+
+ CheckDlgButton(Dialog,IDC_SHOWFILE ,PopUpFile);
+ CheckDlgButton(Dialog,IDC_REQUEST ,PopRequest);
+
+ CheckDlgButton(Dialog,IDC_ACTLEFTCLOSE ,ord(LoByte(PopUpAction)=0));
+ CheckDlgButton(Dialog,IDC_ACTLEFTINFO ,ord(LoByte(PopUpAction)=1));
+ CheckDlgButton(Dialog,IDC_ACTLEFTPLAYER ,ord(LoByte(PopUpAction)=2));
+ CheckDlgButton(Dialog,IDC_ACTLEFTNEXT ,ord(LoByte(PopUpAction)=3));
+ CheckDlgButton(Dialog,IDC_ACTRIGHTCLOSE ,ord(HiByte(PopUpAction)=0));
+ CheckDlgButton(Dialog,IDC_ACTRIGHTINFO ,ord(HiByte(PopUpAction)=1));
+ CheckDlgButton(Dialog,IDC_ACTRIGHTPLAYER,ord(HiByte(PopUpAction)=2));
+ CheckDlgButton(Dialog,IDC_ACTRIGHTNEXT ,ord(HiByte(PopUpAction)=3));
+
+ CheckDlgButton(Dialog,IDC_USEBUTTONS,PopUpButtons);
+
+ SetDlgItemInt (Dialog,IDC_DELAY,PopUpPause,false);
+
+ if PopUpDelay<0 then
+ CheckDlgButton(Dialog,IDC_DELAYPERM,BST_CHECKED)
+ else if PopUpDelay=0 then
+ CheckDlgButton(Dialog,IDC_DELAYDEF,BST_CHECKED)
+ else
+ CheckDlgButton(Dialog,IDC_DELAYCUST,BST_CHECKED);
+ if PopUpDelay<=0 then
+ EnableWindow(GetDlgItem(Dialog,IDC_DELAY),false);
+
+ SendDlgItemMessage(Dialog,IDC_MACRO_HELP,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_SKIN_LOADICON,SKINICON_OTHER_HELP,0));
+
+ fore:=GetDlgItem(Dialog,IDC_FORE);
+ back:=GetDlgItem(Dialog,IDC_BACK);
+ SendMessage(fore,CPM_SETCOLOUR,0,PopUpFore);
+ SendMessage(fore,CPM_SETDEFAULTCOLOUR,0,GetSysColor(COLOR_BTNTEXT));
+ SendMessage(back,CPM_SETCOLOUR,0,PopUpBack);
+ SendMessage(back,CPM_SETDEFAULTCOLOUR,0,GetSysColor(COLOR_BTNFACE));
+ SetDlgItemInt(Dialog,IDC_FORE,PopUpFore,false);
+ SetDlgItemInt(Dialog,IDC_BACK,PopUpBack,false);
+ if PopUpColor<2 then
+ begin
+ EnableWindow(fore,false);
+ EnableWindow(back,false);
+ end;
+ case PopUpColor of
+ 0: CheckDlgButton(Dialog,IDC_COLORDEF ,BST_CHECKED);
+ 1: CheckDlgButton(Dialog,IDC_COLORWIN ,BST_CHECKED);
+ 2: CheckDlgButton(Dialog,IDC_COLORCUST,BST_CHECKED);
+ end;
+ dlginit:=true;
+ end;
+
+ WM_COMMAND: begin
+ if (wParam shr 16)=BN_CLICKED then
+ begin
+ fore:=GetDlgItem(Dialog,IDC_FORE);
+ back:=GetDlgItem(Dialog,IDC_BACK);
+ case LoWord(wParam) of
+ IDC_MACRO_HELP: CallService(MS_WAT_MACROHELP,Dialog,0);
+ IDC_TEST: begin
+ mGetMem(ppd,SizeOf(TPOPUPDATAW));
+ FillChar(ppd^,SizeOf(ppd^),0);
+ ppd^.lchIcon:=LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ StrCopyW(ppd^.lpwzContactName,TranslateW('popup test'));
+ StrCopyW(ppd^.lpwzText,TranslateW('second line'));
+ if IsDlgButtonChecked(Dialog,IDC_COLORDEF)=BST_CHECKED then
+ begin
+ ppd^.colorBack:=0;
+ ppd^.colorText:=0;
+ end
+ else if IsDlgButtonChecked(Dialog,IDC_COLORWIN)=BST_CHECKED then
+ begin
+ ppd^.colorBack:=GetSysColor(COLOR_BTNFACE);
+ ppd^.colorText:=GetSysColor(COLOR_BTNTEXT);
+ end
+ else
+ begin
+ ppd^.colorBack:=SendMessage(back,CPM_GETCOLOUR,0,0);
+ ppd^.colorText:=SendMessage(fore,CPM_GETCOLOUR,0,0);
+ end;
+ CallService(MS_POPUP_ADDPOPUPW,twparam(ppd),0);
+ mFreeMem(ppd);
+ end;
+ IDC_DELAYCUST:
+ EnableWindow(GetDlgItem(Dialog,IDC_DELAY),true);
+ IDC_DELAYDEF,IDC_DELAYPERM:
+ EnableWindow(GetDlgItem(Dialog,IDC_DELAY),false);
+ IDC_COLORCUST: begin
+ EnableWindow(fore,true);
+ EnableWindow(back,true);
+ end;
+ IDC_COLORDEF,IDC_COLORWIN: begin
+ EnableWindow(fore,false);
+ EnableWindow(back,false);
+ end;
+ end;
+ end;
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ result:=0;
+ end;
+
+ WM_NOTIFY: begin
+ if dlginit then
+ begin
+ if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ begin
+
+ mFreeMem(PopTitle);
+ mFreeMem(PopText);
+ PopTitle:=GetDlgText(Dialog,IDC_POPUP_TITLE);
+ PopText :=GetDlgText(Dialog,IDC_POPUP_TEXT);
+
+ PopUpButtons:=IsDlgButtonChecked(Dialog,IDC_USEBUTTONS);
+
+ PopUpFile :=IsDlgButtonChecked(Dialog,IDC_SHOWFILE);
+ PopRequest:=IsDlgButtonChecked(Dialog,IDC_REQUEST);
+//color
+ if IsDlgButtonChecked(Dialog,IDC_COLORDEF)=BST_CHECKED then
+ PopUpColor:=0
+ else if IsDlgButtonChecked(Dialog,IDC_COLORWIN)=BST_CHECKED then
+ PopUpColor:=1
+ else
+ begin
+ PopUpColor:=2;
+ PopUpFore:=SendDlgItemMessage(Dialog,IDC_FORE,CPM_GETCOLOUR,0,0);
+ PopUpBack:=SendDlgItemMessage(Dialog,IDC_BACK,CPM_GETCOLOUR,0,0);
+ end;
+//pause
+ if IsDlgButtonChecked(Dialog,IDC_DELAYDEF)=BST_CHECKED then
+ PopUpDelay:=0
+ else if IsDlgButtonChecked(Dialog,IDC_DELAYPERM)=BST_CHECKED then
+ PopUpDelay:=-1
+ else
+ begin
+ PopUpDelay:=1;
+ PopUpPause:=GetDlgItemInt(Dialog,IDC_DELAY,tmp,false);
+ end;
+//action
+ if IsDlgButtonChecked(Dialog,IDC_ACTLEFTINFO)=BST_CHECKED then
+ PopUpAction:=1
+ else if IsDlgButtonChecked(Dialog,IDC_ACTLEFTPLAYER)=BST_CHECKED then
+ PopUpAction:=2
+ else if IsDlgButtonChecked(Dialog,IDC_ACTLEFTNEXT)=BST_CHECKED then
+ PopUpAction:=3
+ else
+ PopUpAction:=0;
+ if IsDlgButtonChecked(Dialog,IDC_ACTRIGHTINFO)=BST_CHECKED then
+ inc(PopUpAction,$100)
+ else if IsDlgButtonChecked(Dialog,IDC_ACTRIGHTPLAYER)=BST_CHECKED then
+ inc(PopUpAction,$200)
+ else if IsDlgButtonChecked(Dialog,IDC_ACTRIGHTNEXT)=BST_CHECKED then
+ inc(PopUpAction,$300);
+
+ savepopup;
+ end;
+ end;
+ end;
+ end;
+end;
diff --git a/plugins/Watrack/popup/pop_opt.inc b/plugins/Watrack/popup/pop_opt.inc
new file mode 100644
index 0000000000..591063923e
--- /dev/null
+++ b/plugins/Watrack/popup/pop_opt.inc
@@ -0,0 +1,81 @@
+{Popup options saving-loading}
+
+const
+ defPopupTitle = 'Now listening to';
+ defPopupText = '%artist% - %title%';
+ defAltPopupTitle = 'Now ?ifgreater(%width%,0,watching,listening to)';
+ defAltPopupText = '%artist% - %title%'#13#10'?iflonger(%album%,0, (from "%album%"),)';
+const
+ opt_ModStatus :PAnsiChar = 'module/popups';
+
+ opt_PopUpFile :PAnsiChar = 'popup/file';
+ opt_PopUpAction :PAnsiChar = 'popup/action';
+ opt_PopUpFore :PAnsiChar = 'popup/fore';
+ opt_PopUpBack :PAnsiChar = 'popup/back';
+ opt_PopUpPause :PAnsiChar = 'popup/time';
+ opt_PopUpDelay :PAnsiChar = 'popup/delay';
+ opt_PopUpColor :PAnsiChar = 'popup/color';
+ opt_ByRequest :PAnsiChar = 'popup/byrequest';
+ opt_PopTitle :PAnsiChar = 'popup/poptitle';
+ opt_PopText :PAnsiChar = 'popup/poptext';
+ opt_PopUpButtons:PAnsiChar = 'popup/usebuttons';
+
+ spref = 'strings/';
+
+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 loadpopup;
+var
+ def1,def2:pWideChar;
+begin
+ PopUpButtons:=DBReadByte (0,PluginShort,opt_PopUpButtons,BST_CHECKED);
+ PopUpFile :=DBReadByte (0,PluginShort,opt_PopUpFile ,BST_CHECKED);
+ PopUpPause :=DBReadByte (0,PluginShort,opt_PopUpPause ,0);
+ PopUpDelay :=DBReadByte (0,PluginShort,opt_PopUpDelay ,0);
+ PopUpAction :=DBReadWord (0,PluginShort,opt_PopUpAction ,0);
+ PopUpColor :=DBReadByte (0,PluginShort,opt_PopUpColor ,0);
+ PopUpFore :=DBReadDWord(0,PluginShort,opt_PopUpFore ,GetSysColor(COLOR_BTNTEXT));
+ PopUpBack :=DBReadDWord(0,PluginShort,opt_PopUpBack ,GetSysColor(COLOR_BTNFACE));
+ PopRequest :=DBReadByte (0,PluginShort,opt_ByRequest ,BST_UNCHECKED);
+ if isVarsInstalled then
+ begin
+ def1:=defAltPopupTitle;
+ def2:=defAltPopupText;
+ end
+ else
+ begin
+ def1:=defPopupTitle;
+ def2:=defPopupText;
+ end;
+ PopTitle:=DBReadUnicode(0,PluginShort,opt_PopTitle,def1);
+ PopText :=DBReadUnicode(0,PluginShort,opt_PopText ,def2);
+end;
+
+procedure savepopup;
+begin
+ DBWriteByte (0,PluginShort,opt_PopUpButtons,PopUpButtons);
+ DBWriteByte (0,PluginShort,opt_PopUpFile ,PopUpFile);
+ DBWriteByte (0,PluginShort,opt_PopUpPause ,PopUpPause);
+ DBWriteByte (0,PluginShort,opt_PopUpDelay ,PopUpDelay);
+ DBWriteWord (0,PluginShort,opt_PopUpAction ,PopUpAction);
+ DBWriteByte (0,PluginShort,opt_PopUpColor ,PopUpColor);
+ DBWriteDWord (0,PluginShort,opt_PopUpFore ,PopUpFore);
+ DBWriteDWord (0,PluginShort,opt_PopUpBack ,PopUpBack);
+ DBWriteByte (0,PluginShort,opt_ByRequest ,PopRequest);
+ DBWriteUnicode(0,PluginShort,opt_PopTitle,PopTitle);
+ DBWriteUnicode(0,PluginShort,opt_PopText ,PopText);
+end;
+
+procedure freepopup;
+begin
+ mFreeMem(PopTitle);
+ mFreeMem(PopText);
+end;
diff --git a/plugins/Watrack/popup/pop_rc.inc b/plugins/Watrack/popup/pop_rc.inc
new file mode 100644
index 0000000000..4e8298d209
--- /dev/null
+++ b/plugins/Watrack/popup/pop_rc.inc
@@ -0,0 +1,34 @@
+{POPUP DLG}
+const
+ IDC_DELAY = 1026;
+ IDC_DELAYDEF = 1027;
+ IDC_DELAYCUST = 1028;
+ IDC_DELAYPERM = 1029;
+ IDC_COLORDEF = 1030;
+ IDC_BACK = 1031;
+ IDC_FORE = 1032;
+ IDC_COLORWIN = 1033;
+ IDC_COLORCUST = 1034;
+ IDC_SHOWFILE = 1035;
+ IDC_TEST = 1036;
+ IDC_ACTLEFTCLOSE = 1040;
+ IDC_ACTLEFTINFO = 1041;
+ IDC_ACTRIGHTCLOSE = 1042;
+ IDC_ACTRIGHTINFO = 1043;
+ IDC_ONKEY = 1044;
+ IDC_KEYEMPTY = 1050;
+ IDC_KEYCUSTOM = 1051;
+ IDC_KEYMSG = 1052;
+ IDC_KEYNOMSG = 1055;
+ IDC_ACTLEFTPLAYER = 1056;
+ IDC_ACTRIGHTPLAYER = 1057;
+ IDC_ACTLEFTNEXT = 1058;
+ IDC_ACTRIGHTNEXT = 1059;
+ IDC_REQUEST = 1060;
+ IDC_STAT_HKBOX = 1061;
+ IDC_POPUP_TITLE = 1062;
+ IDC_POPUP_TEXT = 1063;
+ IDC_MACRO_HELP = 1064;
+ IDC_USEBUTTONS = 1065;
+
+ BTN_INFO = 9;
diff --git a/plugins/Watrack/popup/pop_vars.inc b/plugins/Watrack/popup/pop_vars.inc
new file mode 100644
index 0000000000..4a845aaadc
--- /dev/null
+++ b/plugins/Watrack/popup/pop_vars.inc
@@ -0,0 +1,27 @@
+{popup variables}
+const
+ ActionList:PPOPUPACTION=nil;
+var
+ PopTitle,
+ PopText:pWideChar;
+ PopRequest,
+ PopUpFile:dword;
+ PopUpColor:dword;
+ PopUpFore,
+ PopUpBack:cardinal;
+ PopUpPause:cardinal;
+ PopUpDelay:integer;
+ PopUpAction:cardinal;
+ PopUpButtons:cardinal;
+
+ DisablePlugin:integer;
+ IsPopup2Present:boolean;
+ IsFreeImagePresent:boolean;
+var
+ hMenuInfo :THANDLE;
+ ssmi,sic,
+ plStatusHook:THANDLE;
+ PopupPresent:Bool;
+ onttbhook,
+ opthook:THANDLE;
+ ttbInfo:THANDLE; \ No newline at end of file
diff --git a/plugins/Watrack/popup/popup.rc b/plugins/Watrack/popup/popup.rc
new file mode 100644
index 0000000000..ae05c73860
--- /dev/null
+++ b/plugins/Watrack/popup/popup.rc
@@ -0,0 +1,55 @@
+#include "pop_rc.inc"
+
+LANGUAGE 0,0
+
+POPUP DIALOGEX 0, 0, 304, 226, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0
+{
+ AUTOCHECKBOX "Show by request only", IDC_REQUEST, 156, 0, 144, 18, BS_MULTILINE
+
+ GROUPBOX "Colors", -1, 4, 18, 144, 74
+ CTEXT "Background", -1, 24, 64, 50, 8
+ CTEXT "Text" , -1, 84, 64, 50, 8
+ AUTORADIOBUTTON "Default colors", IDC_COLORDEF , 12, 28, 88, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Windows colors", IDC_COLORWIN , 12, 40, 88, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Custom colors" , IDC_COLORCUST, 12, 52, 88, 10, NOT WS_TABSTOP
+ CONTROL "", IDC_BACK, "ColourPicker", WS_TABSTOP, 24, 75, 50, 14
+ CONTROL "", IDC_FORE, "ColourPicker", WS_TABSTOP, 84, 75, 50, 14
+
+ GROUPBOX "Actions", -1, 156, 18, 144, 74
+ RTEXT "Close" , -1, 162, 40, 50, 10
+ RTEXT "Info" , -1, 162, 53, 50, 10
+ RTEXT "Show player", -1, 162, 66, 50, 10
+ RTEXT "Next track" , -1, 162, 79, 50, 10
+
+ CTEXT "Left click", -1, 208, 26, 40, 16
+ AUTORADIOBUTTON "", IDC_ACTLEFTCLOSE , 224, 40, 10, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "", IDC_ACTLEFTINFO , 224, 53, 10, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "", IDC_ACTLEFTPLAYER, 224, 66, 10, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "", IDC_ACTLEFTNEXT , 224, 79, 10, 10, NOT WS_TABSTOP
+ CTEXT "Right click", -1, 248, 26, 40, 16
+ AUTORADIOBUTTON "", IDC_ACTRIGHTCLOSE , 262, 40, 10, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "", IDC_ACTRIGHTINFO , 262, 53, 10, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "", IDC_ACTRIGHTPLAYER, 262, 66, 10, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "", IDC_ACTRIGHTNEXT , 262, 79, 10, 10, NOT WS_TABSTOP
+
+ GROUPBOX "Delay", -1, 4, 96, 144, 48
+ EDITTEXT IDC_DELAY, 86, 117, 36, 12, ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "sec", -1, 126, 118, 12, 8
+ AUTORADIOBUTTON "Default" , IDC_DELAYDEF , 12, 106, 128, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Custom" , IDC_DELAYCUST, 12, 118, 72, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Permanent", IDC_DELAYPERM, 12, 130, 128, 10, NOT WS_TABSTOP
+
+ AUTOCHECKBOX "Show file name in info" , IDC_SHOWFILE , 156, 94 , 144, 17, BS_MULTILINE
+ AUTOCHECKBOX "Use popup action buttons", IDC_USEBUTTONS, 156, 111, 144, 17, BS_MULTILINE
+ PUSHBUTTON "Test", IDC_TEST, 156, 128, 48, 16
+
+ CONTROL "M", IDC_MACRO_HELP ,"MButtonClass",WS_TABSTOP,278,138,16,16,$18000000
+ CTEXT "Popup Title / Text", -1, 6, 146, 270, 10
+ EDITTEXT IDC_POPUP_TITLE, 6, 156, 290, 14, ES_AUTOHSCROLL
+ EDITTEXT IDC_POPUP_TEXT , 6, 174, 290, 48, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+}
+
+BTN_INFO ICON "wat_info.ico"
diff --git a/plugins/Watrack/popup/popup.res b/plugins/Watrack/popup/popup.res
new file mode 100644
index 0000000000..707791399b
--- /dev/null
+++ b/plugins/Watrack/popup/popup.res
Binary files differ
diff --git a/plugins/Watrack/popup/popups.pas b/plugins/Watrack/popup/popups.pas
new file mode 100644
index 0000000000..381d33dab3
--- /dev/null
+++ b/plugins/Watrack/popup/popups.pas
@@ -0,0 +1,542 @@
+{PopUp support}
+unit Popups;
+{$include compilers.inc}
+interface
+{$Resource popup.res}
+implementation
+
+uses windows,messages,commctrl,
+ wat_api,waticons,global,
+ wrapper,common,m_api,dbsettings,mirutils;
+
+const
+ MenuInfoPos = 500050002;
+ PluginName = 'Winamp Track';
+const
+ IcoBtnInfo:PAnsiChar='WATrack_Info';
+const
+ HKN_POPUP:PAnsiChar = 'WAT_Popup';
+
+{$include pop_rc.inc}
+{$include pop_vars.inc}
+{$include pop_opt.inc}
+
+const
+ MainTmpl = 'artist: %ls'#13#10'title: "%ls"'#13#10'album: "%ls"'#13#10+
+ 'genre: %ls'#13#10'comment: %ls'#13#10'year: %ls'#13#10'track: %lu'#13#10+
+ 'bitrate: %lukbps %ls'#13#10'samplerate: %luKHz'#13#10+
+ 'channels: %lu'#13#10'length: %ls'#13#10'player: "%ls" v.%ls';
+ AddTmpl = #13#10'file: "%ls"'#13#10'size: %lu bytes';
+
+procedure ShowMusicInfo(si:pSongInfo);
+var
+ Tmpl:array [0..255] of WideChar;
+ buf:pWideChar;
+ lvars:array [0..15] of uint_ptr;
+ s:array [0..31] of WideChar;
+ p:PWideChar;
+begin
+ mGetMem(buf,16384);
+ with si^ do
+ begin
+ lvars[0]:=uint_ptr(artist);
+ lvars[1]:=uint_ptr(title);
+ lvars[2]:=uint_ptr(album);
+ lvars[3]:=uint_ptr(genre);
+ lvars[4]:=uint_ptr(comment);
+ lvars[5]:=uint_ptr(year);
+ lvars[6]:=track;
+ lvars[7]:=kbps;
+ if vbr>0 then
+ p:='VBR'
+ else
+ p:='CBR';
+ lvars[8]:=uint_ptr(p);
+ lvars[9]:=khz;
+ lvars[10]:=channels;
+ lvars[11]:=uint_ptr(IntToTime(s,total));
+ lvars[12]:=uint_ptr(player);
+ lvars[13]:=uint_ptr(txtver);
+ end;
+ StrCopyW(Tmpl,TranslateW(MainTmpl));
+ if PopUpFile=BST_CHECKED then
+ begin
+ lvars[14]:=uint_ptr(si^.mfile);
+ lvars[15]:=si^.fsize;
+ StrCatW(Tmpl,TranslateW(AddTmpl));
+ end;
+
+ wvsprintfw(buf,Tmpl,@lvars);
+ MessageBoxW(0,buf,PluginName,MB_OK);
+ mFreeMem(buf);
+end;
+
+function DumbPopupDlgProc(Wnd:hwnd;msg:uint;wParam:integer;lParam:longint):integer;stdcall;
+var
+ si:pSongInfo;
+ h:HBITMAP;
+begin
+ case msg of
+ WM_COMMAND,WM_CONTEXTMENU: begin
+ if msg=WM_CONTEXTMENU then
+ wParam:=HiByte(PopUpAction)
+ else
+ wParam:=LoByte(PopUpAction);
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,0,0));
+ case wParam of
+ 1: ShowMusicInfo(si);
+ 2: ShowWindow(si^.plwnd,SW_RESTORE);
+ 3: CallServiceSync(MS_WAT_PRESSBUTTON,WAT_CTRL_NEXT,0);
+ end;
+ SendMessage(Wnd,UM_DESTROYPOPUP,0,0);
+ result:=1;
+ end;
+ UM_POPUPACTION: begin
+// if wParam<>0 then
+ result:=CallServiceSync(MS_WAT_PRESSBUTTON,lParam,0);
+ end;
+ UM_FREEPLUGINDATA: begin
+ h:=0;
+ h:=CallService(MS_POPUP_GETPLUGINDATA,Wnd,h);
+ if h<>0 then
+ DeleteObject(h);
+ result:=0;
+ end;
+ else
+ result:=DefWindowProc(Wnd,msg,wParam,lParam);
+ end;
+end;
+
+function MakeAction(var anAct:TPOPUPACTION;action:integer):PPOPUPACTION;
+begin
+ result:=@anAct;
+ anAct.cbSize :=SizeOf(TPOPUPACTION);
+ anAct.lchIcon:=GetIcon(action);
+ anAct.flags :=PAF_ENABLED;
+ anAct.wParam :=1;
+ anAct.lParam :=action;
+ StrCopy(StrCopyE(anAct.lpzTitle,'Watrack/'),GetIconDescr(action));
+end;
+
+function MakeActions:PPOPUPACTION;
+type
+ anacts = array [0..6] of TPOPUPACTION;
+var
+ actions:^anacts;
+begin
+ if PopUpButtons<>BST_UNCHECKED then
+ begin
+ mGetMem(actions,SizeOf(anacts));
+ result:=PPOPUPACTION(actions);
+ FillChar(actions^,SizeOf(actions^),0);
+ MakeAction(actions[0],WAT_CTRL_PREV);
+ MakeAction(actions[1],WAT_CTRL_PLAY);
+ MakeAction(actions[2],WAT_CTRL_PAUSE);
+ MakeAction(actions[3],WAT_CTRL_STOP);
+ MakeAction(actions[4],WAT_CTRL_NEXT);
+ MakeAction(actions[5],WAT_CTRL_VOLDN);
+ MakeAction(actions[6],WAT_CTRL_VOLUP);
+ end
+ else
+ result:=nil;
+end;
+
+procedure ThShowPopup(si:pSongInfo); cdecl;
+var
+ ppdu:PPOPUPDATAW;
+ title,descr:pWideChar;
+ flag:dword;
+ ppd2:PPOPUPDATA2;
+ Icon:HICON;
+ sec:integer;
+ cb,ct:TCOLORREF;
+ line:boolean;
+ tmp:pAnsiChar;
+begin
+ line:=CallService(MS_POPUP_ISSECONDLINESHOWN,0,0)<>0;
+
+ descr:=PWideChar(CallService(MS_WAT_REPLACETEXT,0,lparam(PopText)));
+ if line then
+ title:=PWideChar(CallService(MS_WAT_REPLACETEXT,0,lparam(PopTitle)))
+ else
+ title:=nil;
+
+ if (descr<>nil) or (title<>nil) then
+ begin
+ if si^.icon<>0 then
+ Icon:=si^.icon
+ else
+ Icon:=LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ if PopUpDelay<0 then
+ sec:=-1
+ else if PopUpDelay>0 then
+ sec:=PopUpPause
+ else
+ sec:=0;
+ case PopUpColor of
+ 0: begin
+ cb:=0;
+ ct:=0;
+ end;
+ 1: begin
+ cb:=GetSysColor(COLOR_BTNFACE);
+ ct:=GetSysColor(COLOR_BTNTEXT);
+ end;
+ 2: begin
+ cb:=PopUpBack;
+ ct:=PopUpFore;
+ end;
+ else
+ cb:=0;
+ ct:=0;
+ end;
+
+ if IsPopup2Present then
+ begin
+ mGetMem (ppd2 ,SizeOf(TPOPUPDATA2));
+ FillChar(ppd2^,SizeOf(TPOPUPDATA2),0);
+ with ppd2^ do
+ begin
+ cbSize :=SizeOf(TPOPUPDATA2);
+ flags :=PU2_UNICODE;
+ lchIcon :=Icon;
+ colorBack :=cb;
+ colorText :=ct;
+ PluginWindowProc:=@DumbPopupDlgProc;
+
+ if line then
+ begin
+ pzTitle.w:=title;
+ pzText .w:=descr;
+ end
+ else
+ pzTitle.w:=descr;
+
+ if ActionList=nil then
+ flag:=0
+ else
+ begin
+ flag :=APF_NEWDATA;
+ actionCount:=7;
+ lpActions :=ActionList;
+ end;
+
+ if si.cover<>nil then
+ begin
+ if IsFreeImagePresent then
+ hbmAvatar:=CallService(MS_IMG_LOAD,wparam(si.cover),IMGL_WCHAR)
+ else
+ hbmAvatar:=0;
+ if hbmAvatar=0 then
+ begin
+ WideToAnsi(si.cover,tmp);
+ hbmAvatar:=CallService(MS_UTILS_LOADBITMAP,0,lparam(tmp));
+ mFreeMem(tmp);
+ end;
+ end;
+ PluginData:=pointer(hbmAvatar);
+ end;
+ CallService(MS_POPUP_ADDPOPUP2,wparam(ppd2),flag);
+ mFreeMem(ppd2);
+ end
+ else
+ begin
+ mGetMem (ppdu ,SizeOf(TPOPUPDATAW));
+ FillChar(ppdu^,SizeOf(TPOPUPDATAW),0);
+ with ppdu^ do
+ begin
+ if line then
+ begin
+ if title<>nil then
+ StrCopyW(lpwzContactName,title,MAX_CONTACTNAME-1)
+ else
+ lpwzContactName[0]:=' ';
+ if descr<>nil then
+ StrCopyW(lpwzText,descr,MAX_SECONDLINE-1)
+ else
+ lpwzText[0]:=' ';
+ end
+ else
+ begin
+ StrCopyW(ppdu^.lpwzContactName,title,MAX_CONTACTNAME-1);
+ lpwzText[0]:=' ';
+ end;
+
+ lchIcon :=Icon;
+ PluginWindowProc:=@DumbPopupDlgProc;
+ iSeconds :=sec;
+ colorBack :=cb;
+ colorText :=ct;
+
+ // if ServiceExists(MS_POPUP_REGISTERACTIONS)=0 then
+ if ActionList=nil then
+ flag:=0
+ else
+ begin
+ flag :=APF_NEWDATA;
+ icbSize :=SizeOf(TPOPUPDATAW);
+ actionCount:=7;
+ lpActions :=ActionList;
+ end;
+ end;
+ CallService(MS_POPUP_ADDPOPUPW,wparam(ppdu),flag);
+ mFreeMem(ppdu);
+ end;
+ mFreeMem(title);
+ mFreeMem(descr);
+ end;
+end;
+
+procedure ShowPopUp(si:pSongInfo);
+begin
+ CloseHandle(mir_forkthread(@ThShowPopup,si));
+end;
+
+// --------------- Services and Hooks ----------------
+
+function OpenPopUp(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ si:pSongInfo;
+begin
+ result:=0;
+ if DisablePlugin<>dsEnabled then
+ exit;
+ if CallService(MS_WAT_GETMUSICINFO,0,tlparam(@si))=WAT_PLS_NORMAL then
+ begin
+ if PopupPresent then
+ ShowPopUp(si)
+ else
+ ShowMusicInfo(si);
+ end;
+end;
+
+procedure regpophotkey;
+var
+ hkrec:HOTKEYDESC;
+begin
+ if DisablePlugin=dsPermanent then
+ exit;
+ FillChar(hkrec,SizeOf(hkrec),0);
+ with hkrec do
+ begin
+ cbSize :=HOTKEYDESC_SIZE_V1;
+ pszName :=HKN_POPUP;
+ pszDescription.a:='WATrack popup hotkey';
+ pszSection.a :=PluginName;
+ pszService :=MS_WAT_SHOWMUSICINFO;
+ DefHotKey:=((HOTKEYF_ALT or HOTKEYF_CONTROL) shl 8) or VK_F7 or HKF_MIRANDA_LOCAL;
+ end;
+ CallService(MS_HOTKEY_REGISTER,0,lparam(@hkrec));
+end;
+
+{$include pop_dlg.inc}
+
+function NewPlStatus(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ mi:TCListMenuItem;
+ flag:integer;
+begin
+ result:=0;
+ case wParam of
+ WAT_EVENT_NEWTRACK: begin
+ if PopupPresent and (PopRequest=BST_UNCHECKED) then
+ ShowPopUp(pSongInfo(lParam));
+ end;
+ WAT_EVENT_PLUGINSTATUS: begin
+ DisablePlugin:=lParam;
+ case lParam of
+ dsEnabled: begin
+ flag:=0;
+ end;
+ dsPermanent: begin
+ 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,hMenuInfo,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(IcoBtnInfo));
+ CallService(MS_CLIST_MODIFYMENUITEM,hMenuInfo,tlparam(@mi));
+ if ActionList<>nil then
+ begin
+ mFreeMem(ActionList);
+ ActionList:=MakeActions;
+ CallService(MS_POPUP_REGISTERACTIONS,twparam(ActionList),7);
+ end;
+end;
+
+function OnOptInitialise(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ odp:TOPTIONSDIALOGPAGE;
+begin
+ FillChar(odp,SizeOf(odp),0);
+ odp.cbSize :=OPTIONPAGE_OLD_SIZE2; //for 0.5 compatibility
+ odp.flags :=ODPF_BOLDGROUPS;
+ odp.Position :=900003000;
+ odp.hInstance :=hInstance;
+ odp.szTitle.a :=PluginName;
+
+ odp.szGroup.a :='PopUps';
+ odp.pszTemplate:=DLGPOPUP;
+ odp.pfnDlgProc :=@DlgPopUpOpt;
+ CallService(MS_OPT_ADDPAGE,wParam,tlparam(@odp));
+ result:=0;
+end;
+
+function OnTTBLoaded(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ ttb:TTBButton;
+begin
+ result:=0;
+ if onttbhook<>0 then
+ UnhookEvent(onttbhook);
+ // get info button
+ FillChar(ttb,SizeOf(ttb),0);
+ ttb.cbSize :=SizeOf(ttb);
+ ttb.dwFlags :=TTBBF_VISIBLE{ or TTBBF_SHOWTOOLTIP};
+ ttb.hIconUp :=CallService(MS_SKIN2_GETICON,0,tlparam(IcoBtnInfo));
+ ttb.hIconDn :=ttb.hIconUp;
+ ttb.pszService:=MS_WAT_SHOWMUSICINFO;
+ ttb.name :='Music Info';
+ ttbInfo:=TopToolbar_AddButton(@ttb);
+ if ttbInfo=THANDLE(-1) then
+ ttbInfo:=0;
+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;
+
+ ssmi:=CreateServiceFunction(MS_WAT_SHOWMUSICINFO,@OpenPopUp);
+
+ 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_INFO),IMAGE_ICON,16,16,0);
+ sid.pszName :=IcoBtnInfo;
+ sid.szDescription.a:='Music Info';
+ Skin_AddIcon(@sid);
+ DestroyIcon(sid.hDefaultIcon);
+ sic:=HookEvent(ME_SKIN2_ICONSCHANGED,@IconChanged);
+
+ FillChar(mi,SizeOf(mi),0);
+ mi.cbSize :=SizeOf(mi);
+ mi.szPopupName.a:=PluginShort;
+ mi.hIcon :=CallService(MS_SKIN2_GETICON,0,lparam(IcoBtnInfo));
+ mi.szName.a :='Music Info';
+ mi.pszService :=MS_WAT_SHOWMUSICINFO;
+ mi.popupPosition:=MenuInfoPos;
+ hMenuInfo :=Menu_AddMainMenuItem(@mi);
+
+ if ServiceExists(MS_POPUP_ADDPOPUPW)<>0 then
+ begin
+ IsFreeImagePresent:=ServiceExists(MS_IMG_LOAD )<>0;
+ IsPopup2Present :=ServiceExists(MS_POPUP_ADDPOPUP2)<>0;
+ PopupPresent:=true;
+ opthook:=HookEvent(ME_OPT_INITIALISE,@OnOptInitialise);
+ loadpopup;
+ regpophotkey;
+
+ ActionList:=nil;
+ if ServiceExists(MS_POPUP_REGISTERACTIONS)<>0 then
+ begin
+ if RegisterButtonIcons then
+ begin
+ ActionList:=MakeActions;
+ if ActionList<>nil then
+ CallService(MS_POPUP_REGISTERACTIONS,wparam(ActionList),7);
+ end;
+ end;
+ end
+ else
+ begin
+ PopupPresent:=false;
+ end;
+
+ plStatusHook:=HookEvent(ME_WAT_NEWSTATUS,@NewPlStatus);
+
+ if ServiceExists(MS_TTB_ADDBUTTON)>0 then
+ begin
+ onttbhook:=0;
+ OnTTBLoaded(0,0);
+ if ttbInfo=0 then
+ onttbhook:=HookEvent(ME_TTB_MODULELOADED,@OnTTBLoaded);
+ end
+ else
+ ttbInfo:=0;
+end;
+
+procedure DeInitProc(aSetDisable:boolean);
+begin
+ if aSetDisable then
+ SetModStatus(0);
+
+ CallService(MS_CLIST_REMOVEMAINMENUITEM,hMenuInfo,0);
+ UnhookEvent(plStatusHook);
+ DestroyServiceFunction(ssmi);
+ UnhookEvent(sic);
+
+ freepopup;
+
+ if ttbInfo<>0 then
+ begin
+ if ServiceExists(MS_TTB_REMOVEBUTTON)>0 then
+ CallService(MS_TTB_REMOVEBUTTON,WPARAM(ttbInfo),0);
+ ttbInfo:=0;
+ end;
+
+ if PopupPresent then
+ begin
+ UnhookEvent(opthook);
+ mFreeMem(ActionList);
+ end;
+end;
+
+var
+ Popup:twModule;
+
+procedure Init;
+begin
+ Popup.Next :=ModuleLink;
+ Popup.Init :=@InitProc;
+ Popup.DeInit :=@DeInitProc;
+ Popup.AddOption :=nil;
+ Popup.ModuleName:='PopUps';
+ ModuleLink :=@Popup;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Watrack/popup/wat_info.ico b/plugins/Watrack/popup/wat_info.ico
new file mode 100644
index 0000000000..70d54c8bac
--- /dev/null
+++ b/plugins/Watrack/popup/wat_info.ico
Binary files differ
diff --git a/plugins/Watrack/proto/i_proto_dlg.inc b/plugins/Watrack/proto/i_proto_dlg.inc
new file mode 100644
index 0000000000..3c467c79ac
--- /dev/null
+++ b/plugins/Watrack/proto/i_proto_dlg.inc
@@ -0,0 +1,144 @@
+{Misc}
+
+procedure SetAllContactStat(hwndList:HWND);
+var
+ hContact,hItem:THANDLE;
+begin
+ hContact:=CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while hContact<>0 do
+ begin
+ hItem:=SendMessage(hwndList,CLM_FINDCONTACT,hContact,0);
+ if hItem<>0 then
+ begin
+ SendMessage(hwndList,CLM_SETCHECKMARK,hItem,
+ DBReadByte(hContact,strCList,ShareOptText,0));
+ end;
+ hContact:=CallService(MS_DB_CONTACT_FINDNEXT,hContact,0);
+ end;
+end;
+
+procedure SaveAllContactStat(hwndList:HWND);
+var
+ hContact,hItem:THANDLE;
+begin
+ hContact:=CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while hContact<>0 do
+ begin
+ hItem:=SendMessage(hwndList,CLM_FINDCONTACT,hContact,0);
+ if hItem<>0 then
+ begin
+ if SendMessage(hwndList,CLM_GETCHECKMARK,hItem,0)<>0 then
+ DBWriteByte(hContact,strCList,ShareOptText,1)
+ else
+ DBDeleteSetting(hContact,strCList,ShareOptText);
+ end;
+ hContact:=CallService(MS_DB_CONTACT_FINDNEXT,hContact,0);
+ end;
+end;
+
+procedure ResetListOptions(hwndList:HWND);
+var
+ i:integer;
+begin
+ SendMessage(hwndList,CLM_SETBKBITMAP ,0,0);
+ SendMessage(hwndList,CLM_SETBKCOLOR ,GetSysColor(COLOR_WINDOW),0);
+ SendMessage(hwndList,CLM_SETGREYOUTFLAGS,0,0);
+ SendMessage(hwndList,CLM_SETLEFTMARGIN ,2,0);
+ SendMessage(hwndList,CLM_SETINDENT ,10,0);
+ for i:=0 to FONTID_MAX do
+ SendMessage(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT));
+ SetWindowLongPtr(hwndList,GWL_STYLE,GetWindowLongPtr(hwndList,GWL_STYLE) or CLS_SHOWHIDDEN);
+end;
+
+procedure SetHistMask(Dlg:HWND);
+begin
+ CheckDlgButton(Dlg,IDC_IN_REQUEST ,ORD((HistMask and hmInRequest )<>0));
+ CheckDlgButton(Dlg,IDC_OUT_REQUEST,ORD((HistMask and hmOutRequest)<>0));
+ CheckDlgButton(Dlg,IDC_IN_INFO ,ORD((HistMask and hmInInfo )<>0));
+ CheckDlgButton(Dlg,IDC_OUT_INFO ,ORD((HistMask and hmOutInfo )<>0));
+ CheckDlgButton(Dlg,IDC_IN_ERROR ,ORD((HistMask and hmInError )<>0));
+ CheckDlgButton(Dlg,IDC_OUT_ERROR ,ORD((HistMask and hmOutError )<>0));
+ CheckDlgButton(Dlg,IDC_IREQUEST ,ORD((HistMask and hmIRequest )<>0));
+ CheckDlgButton(Dlg,IDC_ISEND ,ORD((HistMask and hmISend )<>0));
+end;
+
+procedure SaveHistMask(Dlg:HWND);
+begin
+ HistMask:=0;
+ if IsDlgButtonChecked(Dlg,IDC_IN_REQUEST )<>BST_UNCHECKED then HistMask:=HistMask or hmInRequest;
+ if IsDlgButtonChecked(Dlg,IDC_OUT_REQUEST)<>BST_UNCHECKED then HistMask:=HistMask or hmOutRequest;
+ if IsDlgButtonChecked(Dlg,IDC_IN_INFO )<>BST_UNCHECKED then HistMask:=HistMask or hmInInfo;
+ if IsDlgButtonChecked(Dlg,IDC_OUT_INFO )<>BST_UNCHECKED then HistMask:=HistMask or hmOutInfo;
+ if IsDlgButtonChecked(Dlg,IDC_IN_ERROR )<>BST_UNCHECKED then HistMask:=HistMask or hmInError;
+ if IsDlgButtonChecked(Dlg,IDC_OUT_ERROR )<>BST_UNCHECKED then HistMask:=HistMask or hmOutError;
+ if IsDlgButtonChecked(Dlg,IDC_IREQUEST )<>BST_UNCHECKED then HistMask:=HistMask or hmIRequest;
+ if IsDlgButtonChecked(Dlg,IDC_ISEND )<>BST_UNCHECKED then HistMask:=HistMask or hmISend;
+end;
+
+function DlgProcOptions(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ Changed:integer=0;
+// hItemAll:THANDLE=0;
+var
+// cii:TCLCINFOITEM;
+ hList:HWND;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ Changed:=DLGED_INIT;
+
+ hList:=GetDlgItem(Dialog,IDC_SHARE);
+ ResetListOptions(hList);
+ SendMessage(hList,CLM_SETUSEGROUPS ,1,0);
+ SendMessage(hList,CLM_SETHIDEEMPTYGROUPS,1,0);
+
+// SendMessage(hList,CLM_SETEXTRACOLUMNS,2,0);
+{
+ FillChar(cii,SizeOf(cii),0);
+ cii.cbSize :=SizeOf(cii);
+ cii.flags :=CLCIIF_GROUPFONT or CLCIIF_CHECKBOX;
+ cii.pszText.w:=TranslateW('** All contacts **');
+ hItemAll:=SendMessage(hList,CLM_ADDINFOITEM,0,dword(@cii));
+}
+ SetAllContactStat(hList);
+ SetHistMask(Dialog);
+
+ SetDlgItemTextW(Dialog,IDC_PROTO_TEXT,ProtoText);
+
+ Changed:=0;
+ end;
+
+ WM_COMMAND: begin
+ if Changed<>DLGED_INIT then
+ begin
+ case wParam shr 16 of
+ BN_CLICKED,EN_CHANGE: SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ if Changed<>DLGED_INIT then
+ begin
+ if PNMHDR(lParam)^.idFrom=IDC_SHARE then
+ if integer(PNMHdr(lParam)^.code)=CLN_CHECKCHANGED then
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+
+ if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ begin
+ mFreeMem(ProtoText);
+ ProtoText:=GetDlgText(Dialog,IDC_PROTO_TEXT);
+
+ SaveAllContactStat(GetDlgItem(Dialog,IDC_SHARE));
+ SaveHistMask(Dialog);
+
+ WriteOptions;
+ end;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/proto/i_proto_opt.inc b/plugins/Watrack/proto/i_proto_opt.inc
new file mode 100644
index 0000000000..c1e2cbf36d
--- /dev/null
+++ b/plugins/Watrack/proto/i_proto_opt.inc
@@ -0,0 +1,35 @@
+{}
+const
+ defProtoText = '%artist% - %title%';
+const
+ opt_ModStatus:PAnsiChar = 'module/protocol';
+
+ opt_histmask :PAnsiChar = 'historymask';
+ opt_prototext:PAnsiChar = 'prototext';
+
+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 ReadOptions;
+begin
+ HistMask :=DBReadWord (0,PluginShort,opt_histmask,0);
+ ProtoText:=DBReadUnicode(0,PluginShort,opt_prototext,defProtoText);
+end;
+
+procedure WriteOptions;
+begin
+ DBWriteWord (0,PluginShort,opt_histmask ,HistMask);
+ DBWriteUnicode(0,PluginShort,opt_prototext,ProtoText);
+end;
+
+procedure FreeOptions;
+begin
+ mFreeMem(ProtoText);
+end;
diff --git a/plugins/Watrack/proto/i_proto_rc.inc b/plugins/Watrack/proto/i_proto_rc.inc
new file mode 100644
index 0000000000..f2d56ad329
--- /dev/null
+++ b/plugins/Watrack/proto/i_proto_rc.inc
@@ -0,0 +1,17 @@
+const
+ IDC_EXPORT = 1031;
+ IDC_SHARE = 1033;
+ IDC_IN_REQUEST = 1034;
+ IDC_OUT_REQUEST = 1035;
+ IDC_IN_INFO = 1036;
+ IDC_OUT_INFO = 1037;
+ IDC_IN_ERROR = 1038;
+ IDC_OUT_ERROR = 1039;
+ IDC_IREQUEST = 1040;
+ IDC_ISEND = 1041;
+ IDC_STAT_EXPORT = 1042;
+ IDC_STAT_TEXP = 1043;
+ IDC_STAT_LINE = 1044;
+ IDC_PROTO_TEXT = 1045;
+
+BTN_CONTEXT = 130;
diff --git a/plugins/Watrack/proto/proto.pas b/plugins/Watrack/proto/proto.pas
new file mode 100644
index 0000000000..254a02bac6
--- /dev/null
+++ b/plugins/Watrack/proto/proto.pas
@@ -0,0 +1,564 @@
+{Statistic}
+unit proto;
+{$include compilers.inc}
+interface
+{$Resource proto.res}
+implementation
+
+uses
+ windows,messages,commctrl,
+ common,m_api,mirutils,dbsettings,wrapper,
+ global,wat_api;
+
+{$include i_proto_rc.inc}
+
+const
+ ShareOptText = 'ShareMusic';
+const
+ IcoBtnContext:PAnsiChar='WATrack_Context';
+const
+ MenuUserInfoPos = 500050000;
+
+const
+ wpRequest = 'WAT###0_';
+ wpAnswer = 'WAT###1_';
+ wpError = 'WAT###2_';
+ wpMessage = 'WAT###3_';
+ wpRequestNew = 'ASKWAT';
+
+const
+ SendRequestText:PAnsiChar =
+ 'WATrack internal info - sorry!';
+{
+ 'If you see this message, probably you have no "WATrack" plugin installed or uses old '+
+ 'version. See http://miranda-im.org/download/details.php?action=viewfile&id=2345 or '+
+ 'http://awkward.miranda.im/ (beta versions) for more information and download.';
+}
+const
+ hmInRequest = $0001;
+ hmOutRequest = $0002;
+ hmInInfo = $0004;
+ hmOutInfo = $0008;
+ hmInError = $0010;
+ hmOutError = $0020;
+ hmIRequest = $0040;
+ hmISend = $0080;
+
+var
+ hSRM,
+ hGCI,
+ icchangedhook,
+ hAddUserHook,
+ hContactMenuItem,
+ contexthook:THANDLE;
+ ProtoText:pWideChar;
+ HistMask:cardinal;
+
+{$include i_proto_opt.inc}
+{$include i_proto_dlg.inc}
+
+procedure AddEvent(hContact:THANDLE;atype,flag:integer;data:pointer;size:integer;time:dword=0);
+var
+ dbeo:TDBEVENTINFO;
+begin
+ FillChar(dbeo,SizeOf(dbeo),0);
+ with dbeo do
+ begin
+ cbSize :=SizeOf(dbeo);
+ eventType:=atype;
+ szModule :=PluginShort;
+ if data=nil then
+ begin
+ PAnsiChar(data):='';
+ size:=1;
+ end;
+ pBlob :=data;
+ cbBlob :=size;
+ flags :=flag;
+ if time<>0 then
+ Timestamp:=time
+ else
+ Timestamp:=GetCurrentTime;
+ end;
+ CallService(MS_DB_EVENT_ADD,hContact,lparam(@dbeo));
+end;
+
+{SEND-time text translation}
+(*
+const
+ BufSize = 16384;
+
+function FormatToBBW(src:PWideChar):PWideChar;
+var
+ buf:array [0..32] of WideChar;
+ p:PWideChar;
+ i,j:integer;
+begin
+ result:=src;
+ StrReplaceW(src,'{b}' ,'[b]');
+ StrReplaceW(src,'{/b}' ,'[/b]');
+ StrReplaceW(src,'{u}' ,'[u]');
+ StrReplaceW(src,'{/u}' ,'[/u]');
+ StrReplaceW(src,'{i}' ,'[i]');
+ StrReplaceW(src,'{/i}' ,'[/i]');
+ StrReplaceW(src,'{/cf}','[/color]');
+ StrReplaceW(src,'{/bg}','');
+ StrCopyW(buf,'[color=');
+ repeat
+ i:=StrPosW(src,'{cf');
+ if i=0 then break;
+ j:=i;
+ dec(i);
+ while (src[j]<>#0) and (src[j]<>'}') do inc(j);
+ if src[j]='}' then inc(j);
+ case StrToInt(src+i+3) of
+ 4,10: p:='green]';
+ 5,6: p:='red]';
+ 7,14: p:='magenta]';
+ 3,11,
+ 12,13: p:='blue]';
+ 8,9: p:='yellow]';
+ 2,15: p:='black]';
+ else
+ {1,16:} p:='white]';
+ end;
+ StrCopyW(buf+7,p);
+ StrCopyW(src+i,src+j);
+ StrInsertW(buf,src,i);
+ until false;
+ repeat
+ i:=StrIndex(src,'{bg');
+ if i=0 then break;
+ j:=i;
+ dec(i);
+ while (src[j]<>#0) and (src[j]<>'}') do inc(j);
+ if src[j]='}' then inc(j);
+ StrCopyW(src+i,src+j);
+ until false;
+end;
+
+function SendMessageProcW(wParam:WPARAM; lParam:LPARAM):integer; cdecl;
+var
+ ccs:PCCSDATA;
+ uns,s,ss:pWideChar;
+ p:PAnsiChar;
+ present:boolean;
+ i:integer;
+begin
+ if DisablePlugin<>dsPermanent then
+ begin
+ ccs:=PCCSDATA(lParam);
+ if ccs^.wParam=0 then
+ present:=StrPos('%music%',PAnsiChar(ccs^.lParam))<>nil
+ else // not needed?
+ begin
+ uns:=PWideChar(ccs^.lParam+StrLen(PAnsiChar(ccs^.lParam))+1);
+ present:=StrPos(uns,'%music%')<>nil;
+ end;
+
+ if present then
+ begin
+ if CallService(MS_WAT_GETMUSICINFO,0,0)=WAT_PLS_NOTFOUND then
+ s:=nil
+ else
+ begin
+ if SimpleMode<>BST_UNCHECKED then
+ i:=0
+ else
+ i:=CallService(MS_PROTO_GETCONTACTBASEPROTO,ccs^.hContact,0);
+ s:=GetMacros(TM_MESSAGE,i);
+ end;
+ // if s<>nil then // for empty strings
+ begin
+ mGetMem(ss,BufSize*SizeOf(pWideChar));
+ FillChar(ss^,BufSize*SizeOf(pWideChar),0);
+ if ccs^.wParam=0 then
+ AnsiToWide(PAnsiChar(ccs^.lParam),uns,UserCP);
+ StrCopyW(ss,uns);
+ if ccs^.wParam=0 then
+ mFreeMem(uns);
+ StrReplaceW(ss,'%music%',s);
+ mFreeMem(s);
+ if StrPos(ss,'{')<>nil then
+ FormatToBBW(ss);
+ s:=PWideChar(ccs^.lParam);
+ WideToAnsi(ss,p,UserCP);
+ if ccs^.wParam=0 then
+ begin
+ ccs^.lParam:=dword(p);
+ end
+ else
+ begin
+ move(PAnsiChar(ss)^,(PAnsiChar(ss)+StrLen(p)+1)^,
+ (StrLenW(ss)+1)*SizeOf(WideChar));
+ StrCopy(PAnsiChar(ss),p);
+ ccs^.lParam:=dword(ss);
+ end;
+ result:=CallService(MS_PROTO_CHAINSEND,wParam,lParam);
+ mFreeMem(p);
+ ccs^.lParam:=dword(s);
+ mFreeMem(ss);
+ exit;
+ end;
+ end;
+ end;
+ result:=CallService(MS_PROTO_CHAINSEND,wParam,lParam);
+end;
+*)
+
+function ReceiveMessageProcW(wParam:WPARAM; lParam:LPARAM):integer; cdecl;
+const
+ bufsize = 4096*SizeOf(WideChar);
+var
+ ccs:PCCSDATA;
+ s:pWideChar;
+ buf:PWideChar;
+ base64:TNETLIBBASE64;
+// pos_artist,pos_title,pos_album:PwideChar;
+ pos_template:pWideChar;
+ curpos:pWideChar;
+ encbuf:pWideChar;
+ i:integer;
+ textpos:PWideChar;
+ pc:PAnsiChar;
+ isNewRequest:bool;
+ si:pSongInfo;
+begin
+ ccs:=PCCSDATA(lParam);
+ result:=0;
+ mGetMem(buf,bufsize);
+
+ isNewRequest:=StrCmp(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a,
+ wpRequestNew,Length(wpRequestNew))=0;
+
+ if isNewRequest or
+ (StrCmp(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a,
+ wpRequest,Length(wpRequest))=0) then
+ begin
+ StrCopy(PAnsiChar(buf),PAnsiChar(CallService(MS_PROTO_GETCONTACTBASEPROTO,ccs^.hContact,0)));
+ i:=DBReadWord(ccs^.hContact,PAnsiChar(buf),'ApparentMode');
+ StrCat(PAnsiChar(buf),PS_GETSTATUS);
+ if (i=ID_STATUS_OFFLINE) or
+ ((i=0) and (CallService(PAnsiChar(buf),0,0)=ID_STATUS_INVISIBLE)) then
+ begin
+ result:=CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+ end
+ else if DBReadByte(ccs^.hContact,strCList,ShareOptText,0)<>0 then
+// or (NotListedAllow and (DBReadByte(ccs^.hContact,strCList,'NotOnList',0))
+ begin
+ if (HistMask and hmInRequest)<>0 then
+ AddEvent(ccs^.hContact,EVENTTYPE_WAT_REQUEST,DBEF_READ,nil,0,
+ PPROTORECVEVENT(ccs^.lParam)^.Timestamp);
+ if GetContactStatus(ccs^.hContact)<>ID_STATUS_OFFLINE then
+ begin
+//!! Request Answer
+ curpos:=nil;
+ if DisablePlugin<>dsPermanent then
+ begin
+ if CallService(MS_WAT_GETMUSICINFO,0,0)=WAT_PLS_NOTFOUND then
+ begin
+ s:=#0#0#0'No player found at this time';
+ textpos:=s+3;
+ end
+ else
+ begin
+ if not isNewRequest then
+ begin
+ FillChar(buf^,bufsize,0);
+ si:=pSongInfo(CallService(MS_WAT_RETURNGLOBAL,0,0));
+ StrCopyW(buf ,si^.artist); curpos:=StrEndW(buf)+1;
+ StrCopyW(curpos,si^.title); curpos:=StrEndW(curpos)+1;
+ StrCopyW(curpos,si^.album); curpos:=StrEndW(curpos)+1;
+ end
+ else
+ curpos:=buf;
+//!! check to DisableTemporary
+
+ s:=PWideChar(CallService(MS_WAT_REPLACETEXT,0,tlparam(ProtoText)));
+ textpos:=StrCopyW(curpos,s);
+ mFreeMem(s);
+ curpos:=StrEndW(curpos)+1;
+ end;
+ end
+ else
+ begin
+ s:=#0#0#0'Sorry, but i don''t use WATrack right now!';
+ textpos:=s+3;
+ end;
+// encode
+ if not isNewRequest then
+ begin
+ if curpos<>nil then
+ begin
+ base64.pbDecoded:=PByte(buf);
+ base64.cbDecoded:=PAnsiChar(curpos)-PAnsiChar(buf);
+ end
+ else
+ begin
+ base64.pbDecoded:=PByte(s);
+ base64.cbDecoded:=(StrLenW(textpos)+3+1)*SizeOf(PWideChar);
+ end;
+ base64.cchEncoded:=Netlib_GetBase64EncodedBufferSize(base64.cbDecoded);
+ mGetMem(encbuf,base64.cchEncoded+1+Length(wpAnswer));
+ base64.pszEncoded:=PAnsiChar(encbuf)+Length(wpAnswer);
+ StrCopy(PAnsiChar(encbuf),wpAnswer);
+ CallService(MS_NETLIB_BASE64ENCODE,0,tlparam(@base64));
+ if (HistMask and hmOutInfo)<>0 then
+ AddEvent(ccs^.hContact,EVENTTYPE_WAT_ANSWER,DBEF_SENT,
+ base64.pbDecoded,base64.cbDecoded);
+ CallContactService(ccs^.hContact,PSS_MESSAGE,0,tlparam(encbuf));
+ end
+ else
+ begin
+ i:=WideToCombo(textpos,encbuf,UserCP);
+ if (HistMask and hmOutInfo)<>0 then
+ AddEvent(ccs^.hContact,EVENTTYPE_WAT_MESSAGE,DBEF_SENT,encbuf,i);
+// if CallContactService(ccs^.hContact,PSS_MESSAGEW,PREF_UNICODE,dword(encbuf))=
+// ACKRESULT_FAILED then
+ CallContactService(ccs^.hContact,PSS_MESSAGE,PREF_UNICODE,tlparam(encbuf));
+ end;
+ mFreeMem(encbuf);
+ end;
+ end
+ else
+ begin
+ if (HistMask and hmIRequest)<>0 then
+ AddEvent(ccs^.hContact,EVENTTYPE_WAT_REQUEST,DBEF_READ,nil,0,
+ PPROTORECVEVENT(ccs^.lParam)^.Timestamp);
+ if (HistMask and hmISend)<>0 then
+ begin
+//!! Request Error Answer
+ if isNewRequest then
+ pc:=PAnsiChar(buf)
+ else
+ begin
+ StrCopy(PAnsiChar(buf),wpError);
+ pc:=PAnsiChar(buf)+Length(wpError);
+ end;
+ StrCopy(pc,'Sorry, but you have no permission to obtain this info!');
+ CallContactService(ccs^.hContact,PSS_MESSAGE,0,tlparam(buf));
+ if (HistMask and hmOutError)<>0 then
+ begin
+ AddEvent(ccs^.hContact,EVENTTYPE_WAT_ERROR,DBEF_SENT,nil,0,
+ PPROTORECVEVENT(ccs^.lParam)^.Timestamp);
+ end;
+ end;
+ end;
+ end
+ else if StrCmp(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a,wpAnswer,Length(wpAnswer))=0 then
+ begin
+// decode
+ base64.pszEncoded:=PPROTORECVEVENT(ccs^.lParam)^.szMessage.a+Length(wpAnswer);
+ base64.cchEncoded:=StrLen(base64.pszEncoded);
+ base64.cbDecoded :=Netlib_GetBase64DecodedBufferSize(base64.cchEncoded);
+ mGetMem(base64.pbDecoded,base64.cbDecoded);
+
+ CallService(MS_NETLIB_BASE64DECODE,0,tlparam(@base64));
+
+ curpos:=pWideChar(base64.pbDecoded); // pos_artist:=curpos;
+ while curpos^<>#0 do inc(curpos); inc(curpos); // pos_title :=curpos;
+ while curpos^<>#0 do inc(curpos); inc(curpos); // pos_album :=curpos;
+ while curpos^<>#0 do inc(curpos); inc(curpos);
+ pos_template:=curpos;
+
+ if (HistMask and hmInInfo)<>0 then
+ AddEvent(ccs^.hContact,EVENTTYPE_WAT_ANSWER,DBEF_READ,
+ base64.pbDecoded,base64.cbDecoded,
+ PPROTORECVEVENT(ccs^.lParam)^.Timestamp);
+// Action
+
+ StrCopyW(buf,TranslateW('Music Info from '));
+ StrCatW (buf,PWideChar(CallService(MS_CLIST_GETCONTACTDISPLAYNAME,ccs^.hContact,GCDNF_UNICODE)));
+
+ MessageBoxW(0,TranslateW(pos_template),buf,MB_ICONINFORMATION);
+
+ mFreeMem(base64.pbDecoded);
+ end
+ else if StrCmp(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a,wpError,Length(wpError))=0 then
+ begin
+ if (HistMask and hmInError)<>0 then
+ AddEvent(ccs^.hContact,EVENTTYPE_WAT_ERROR,DBEF_READ,nil,0,
+ PPROTORECVEVENT(ccs^.lParam)^.Timestamp);
+{
+ AnsiToWide(PAnsiChar(CallService(MS_CLIST_GETCONTACTDISPLAYNAME,ccs^.hContact,0)),s);
+ StrCopyW(buf,s);
+ StrCatW (buf,TranslateW(' answer you'));
+ mFreeMem(s);
+}
+ MessageBoxA(0,Translate(PPROTORECVEVENT(ccs^.lParam)^.szMessage.a+Length(wpError)),
+ Translate('You Get Error'),MB_ICONERROR);
+ end
+ else
+ result:=CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+ mFreeMem(buf);
+end;
+
+function SendRequest(hContact:WPARAM;lParam:LPARAM):integer; cdecl;
+var
+ buf:array [0..2047] of AnsiChar;
+begin
+ result:=0;
+ StrCopy(buf,wpRequest);
+ StrCopy(buf+Length(wpRequest),SendRequestText);
+ CallContactService(hContact,PSS_MESSAGE,0,tlparam(@buf));
+ if (HistMask and hmOutRequest)<>0 then
+ AddEvent(hContact,EVENTTYPE_WAT_REQUEST,DBEF_SENT,nil,0);
+end;
+
+procedure RegisterContacts;
+var
+ hContact:integer;
+begin
+ hContact:=CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while hContact<>0 do
+ begin
+ if not IsChat(hContact) then
+ CallService(MS_PROTO_ADDTOCONTACT,hContact,lparam(PluginShort));
+ hContact:=CallService(MS_DB_CONTACT_FINDNEXT,hContact,0);
+ end;
+end;
+
+function HookAddUser(hContact:WPARAM;lParam:LPARAM):integer; cdecl;
+begin
+ result:=0;
+ if not IsChat(hContact) then
+ CallService(MS_PROTO_ADDTOCONTACT,hContact,tlparam(PluginShort));
+end;
+
+function OnContactMenu(hContact:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ mi:TCListMenuItem;
+begin
+ FillChar(mi,SizeOf(mi),0);
+ mi.cbSize:=sizeof(mi);
+ if IsMirandaUser(hContact)<=0 then
+ mi.flags:=CMIF_NOTOFFLINE or CMIF_NOTOFFLIST or CMIM_FLAGS or CMIF_HIDDEN
+ else
+ mi.flags:=CMIF_NOTOFFLINE or CMIF_NOTOFFLIST or CMIM_FLAGS;
+ CallService(MS_CLIST_MODIFYMENUITEM,hContactMenuItem,tlparam(@mi));
+ result:=0;
+end;
+
+procedure SetProtocol;
+var
+ desc:TPROTOCOLDESCRIPTOR;
+begin
+ desc.cbSize:=PROTOCOLDESCRIPTOR_V3_SIZE;//SizeOf(desc);
+ desc.szName:=PluginShort;
+ desc._type :=PROTOTYPE_TRANSLATION;
+
+ CallService(MS_PROTO_REGISTERMODULE,0,lparam(@desc));
+// CreateProtoServiceFunction(PluginShort,PSS_MESSAGE ,@SendMessageProcW);
+// CreateProtoServiceFunction(PluginShort,PSS_MESSAGEW,@SendMessageProcW);
+ hSRM:=CreateProtoServiceFunction(PluginShort,PSR_MESSAGE ,@ReceiveMessageProcW);
+// CreateProtoServiceFunction(PluginShort,PSR_MESSAGEW,@ReceiveMessageProcW);
+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(IcoBtnContext));
+ CallService(MS_CLIST_MODIFYMENUITEM,hContactMenuItem,tlparam(@mi));
+end;
+
+procedure RegisterIcons;
+var
+ sid:TSKINICONDESC;
+begin
+ FillChar(sid,SizeOf(TSKINICONDESC),0);
+ sid.cbSize:=SizeOf(TSKINICONDESC);
+ sid.cx:=16;
+ sid.cy:=16;
+ sid.szSection.a:=PluginShort;
+
+ sid.hDefaultIcon :=LoadImage(hInstance,MAKEINTRESOURCE(BTN_CONTEXT),IMAGE_ICON,16,16,0);
+ sid.pszName :=IcoBtnContext;
+ sid.szDescription.a:='Context Menu';
+ Skin_AddIcon(@sid);
+ DestroyIcon(sid.hDefaultIcon);
+//!!
+ icchangedhook:=HookEvent(ME_SKIN2_ICONSCHANGED,@IconChanged);
+end;
+
+// ------------ base interface functions -------------
+
+function InitProc(aGetStatus:boolean=false):integer;
+var
+ mi:TCListMenuItem;
+begin
+ if aGetStatus then
+ begin
+ if GetModStatus=0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ end
+ else
+ SetModStatus(1);
+ result:=1;
+
+ ReadOptions;
+ RegisterIcons;
+
+ FillChar(mi, sizeof(mi), 0);
+ mi.cbSize :=sizeof(mi);
+ mi.szPopupName.a:=PluginShort;
+ mi.flags :=CMIF_NOTOFFLINE or CMIF_NOTOFFLIST;
+// mi.popupPosition:=MenuUserInfoPos;
+ mi.hIcon :=CallService(MS_SKIN2_GETICON,0,lparam(IcoBtnContext));
+ mi.szName.a :='Get user''s Music Info';
+ mi.pszService :=MS_WAT_GETCONTACTINFO;
+ hContactMenuItem:=Menu_AddContactMenuItem(@mi);
+
+ SetProtocol;
+ RegisterContacts;
+ hGCI:=CreateServiceFunction(MS_WAT_GETCONTACTINFO,@SendRequest);
+ contexthook :=HookEvent(ME_CLIST_PREBUILDCONTACTMENU,@OnContactMenu);
+ hAddUserHook:=HookEvent(ME_DB_CONTACT_ADDED ,@HookAddUser);
+end;
+
+procedure DeInitProc(aSetDisable:boolean);
+begin
+ if aSetDisable then
+ SetModStatus(0);
+
+ UnhookEvent(hAddUserHook);
+ UnhookEvent(contexthook);
+ UnhookEvent(icchangedhook);
+
+ DestroyServiceFunction(hSRM);
+ DestroyServiceFunction(hGCI);
+ mFreeMem(ProtoText);
+end;
+
+function AddOptionsPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+begin
+ tmpl:='MISC';
+ proc:=@DlgProcOptions;
+ name:='Misc';
+ result:=0;
+end;
+
+var
+ vproto:twModule;
+
+procedure Init;
+begin
+ vproto.Next :=ModuleLink;
+ vproto.Init :=@InitProc;
+ vproto.DeInit :=@DeInitProc;
+ vproto.AddOption :=@AddOptionsPage;
+ vproto.ModuleName:='Protocol';
+ ModuleLink :=@vproto;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Watrack/proto/proto.rc b/plugins/Watrack/proto/proto.rc
new file mode 100644
index 0000000000..dcf5be2faa
--- /dev/null
+++ b/plugins/Watrack/proto/proto.rc
@@ -0,0 +1,36 @@
+#include "i_proto_rc.inc"
+
+LANGUAGE 0,0
+
+MISC 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
+{
+ CONTROL "",IDC_SHARE, "CListControl", WS_TABSTOP | 0x3CA, 4, 4, 144, 180, WS_EX_CLIENTEDGE
+
+ CTEXT "Save events in database",-1, 154, 4, 144, 12, SS_CENTERIMAGE
+ LTEXT "Input" ,-1, 154, 16, 70, 12, SS_CENTERIMAGE
+ RTEXT "Output" ,-1, 226, 16, 70, 12, SS_CENTERIMAGE
+
+ CTEXT "Music Info Request",-1, 170, 30, 112, 14, SS_CENTERIMAGE
+ AUTOCHECKBOX "", IDC_IN_REQUEST , 154, 30, 14, 14, BS_VCENTER | BS_NOTIFY
+ AUTOCHECKBOX "", IDC_OUT_REQUEST , 284, 30, 14, 14, BS_VCENTER | BS_NOTIFY | BS_RIGHT | BS_LEFTTEXT
+
+ CTEXT "Music Info" ,-1, 170, 44, 112, 14, SS_CENTERIMAGE
+ AUTOCHECKBOX "", IDC_IN_INFO , 154, 44, 14, 14, BS_VCENTER | BS_NOTIFY
+ AUTOCHECKBOX "", IDC_OUT_INFO , 284, 44, 14, 14, BS_VCENTER | BS_NOTIFY | BS_RIGHT | BS_LEFTTEXT
+
+ CTEXT "Request Error" ,-1, 170, 58, 112, 14, SS_CENTERIMAGE
+ AUTOCHECKBOX "", IDC_IN_ERROR , 154, 58, 14, 14, BS_VCENTER | BS_NOTIFY
+ AUTOCHECKBOX "", IDC_OUT_ERROR , 284, 58, 14, 14, BS_VCENTER | BS_NOTIFY | BS_RIGHT | BS_LEFTTEXT
+
+ AUTOCHECKBOX "Save ignored requests" , IDC_IREQUEST, 154, 76, 144, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Answer to ignored requests", IDC_ISEND , 154, 90, 144, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+
+ RTEXT "User music info text", -1, 154, 154, 142, 10
+ RTEXT "(%artist%, %title%, %album% and %year% macros can be used only)", -1, 154, 164, 142, 22
+ EDITTEXT IDC_PROTO_TEXT, 4, 186, 296, 36, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+}
+
+BTN_CONTEXT ICON "wat_context.ico"
diff --git a/plugins/Watrack/proto/proto.res b/plugins/Watrack/proto/proto.res
new file mode 100644
index 0000000000..7899ef50cc
--- /dev/null
+++ b/plugins/Watrack/proto/proto.res
Binary files differ
diff --git a/plugins/Watrack/proto/wat_context.ico b/plugins/Watrack/proto/wat_context.ico
new file mode 100644
index 0000000000..37d8413c66
--- /dev/null
+++ b/plugins/Watrack/proto/wat_context.ico
Binary files differ
diff --git a/plugins/Watrack/res/i_const.inc b/plugins/Watrack/res/i_const.inc
new file mode 100644
index 0000000000..b1cafde523
--- /dev/null
+++ b/plugins/Watrack/res/i_const.inc
@@ -0,0 +1,27 @@
+const
+ IDC_FIRST = 1025;
+
+{DLG 1 - base}
+const
+ IDC_CODEPAGE = 1025;
+ IDC_TIMER = 1026;
+ IDC_CHECKTIME = 1027;
+ IDC_IMPLANTANT = 1028;
+ IDC_MTHCHECK = 1029;
+ IDC_KEEPOLD = 1030;
+ IDC_STAT_TIMER = 1031;
+ IDC_COVERFN = 1032;
+ IDC_PLAYERLIST = 1033;
+ IDC_FORMATLIST = 1034;
+ IDC_CHK_PLAYER = 1035;
+ IDC_CHK_FORMAT = 1036;
+ IDC_APPCOMMAND = 1037;
+ IDC_CHECKALL = 1038;
+ IDC_TIMEOUT = 1039;
+
+{DLG 0 - modules}
+ IDC_MODULEGROUP = 1025;
+
+{Icons - same as in waticons.inc}
+IDI_PLUGIN_ENABLE = 100;
+IDI_PLUGIN_DISABLE = 101;
diff --git a/plugins/Watrack/res/wat_disable.ico b/plugins/Watrack/res/wat_disable.ico
new file mode 100644
index 0000000000..390f0852a2
--- /dev/null
+++ b/plugins/Watrack/res/wat_disable.ico
Binary files differ
diff --git a/plugins/Watrack/res/wat_enable.ico b/plugins/Watrack/res/wat_enable.ico
new file mode 100644
index 0000000000..0e20d3a616
--- /dev/null
+++ b/plugins/Watrack/res/wat_enable.ico
Binary files differ
diff --git a/plugins/Watrack/res/watrack.rc b/plugins/Watrack/res/watrack.rc
new file mode 100644
index 0000000000..2d3e6585d2
--- /dev/null
+++ b/plugins/Watrack/res/watrack.rc
@@ -0,0 +1,104 @@
+#include "i_const.inc"
+
+LANGUAGE 0,0
+
+BASIC 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
+{
+ CTEXT "Unicode to Ansi translation codepage:", -1, 192, 2, 108, 20
+ COMBOBOX IDC_CODEPAGE, 192, 22, 108, 56, CBS_DROPDOWNLIST | WS_VSCROLL | NOT WS_TABSTOP
+ CTEXT "Refresh time, sec", IDC_STAT_TIMER, 226, 36, 76, 16, SS_CENTERIMAGE
+ EDITTEXT IDC_TIMER, 192, 38, 32, 12, ES_RIGHT | ES_NUMBER
+ AUTOCHECKBOX "Check file time" , IDC_CHECKTIME , 192, 52, 108, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Keep old file" , IDC_KEEPOLD , 192, 68, 108, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Emulate Multimedia keys" , IDC_APPCOMMAND, 192, 84, 108, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Use process implantation" , IDC_IMPLANTANT, 192, 100, 108, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Check all players" , IDC_CHECKALL , 192, 116, 108, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+ AUTOCHECKBOX "Other thread handle check" , IDC_MTHCHECK , 192, 132, 108, 16, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+
+ EDITTEXT IDC_TIMEOUT , 192, 149, 20, 12, ES_RIGHT | ES_NUMBER
+ LTEXT "Timeout, ms", -1, 214, 148, 86, 14, SS_CENTERIMAGE
+
+ CONTROL "", IDC_PLAYERLIST, "SysListView32",
+ WS_BORDER | WS_TABSTOP | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT,
+ 2, 18, 120, 190, WS_EX_CONTROLPARENT
+ CONTROL "", IDC_FORMATLIST, "SysListView32",
+ WS_BORDER | WS_TABSTOP | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT,
+ 125, 18, 60, 190, WS_EX_CONTROLPARENT
+ CTEXT "Formats", -1, 125, 4, 64, 12
+ CTEXT "Players list\n(F1 for note)", -1, 2, 0, 120, 18
+ CTEXT "Check", -1, 2, 210, 72, 12, SS_CENTERIMAGE
+ PUSHBUTTON "None", IDC_CHK_PLAYER, 74, 210, 48, 12
+ PUSHBUTTON "None", IDC_CHK_FORMAT, 125, 210, 60, 12
+
+ CTEXT "Cover filenames", -1, 192, 164, 108, 10
+ EDITTEXT IDC_COVERFN, 192, 174, 108, 48, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+}
+
+COLOR DIALOGEX 0, 0, 96, 116, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Color codes"
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ DEFPUSHBUTTON "OK", IDOK, 35, 98, 26, 16, NOT WS_TABSTOP
+ RTEXT "1", -1, 4, 6, 10, 10
+ RTEXT "2", -1, 4, 17, 10, 10
+ RTEXT "3", -1, 4, 28, 10, 10
+ RTEXT "4", -1, 4, 39, 10, 10
+ RTEXT "5", -1, 4, 50, 10, 10
+ RTEXT "6", -1, 4, 61, 10, 10
+ RTEXT "7", -1, 4, 72, 10, 10
+ RTEXT "8", -1, 4, 83, 10, 10
+ RTEXT "9", -1, 46, 6, 10, 10
+ RTEXT "10", -1, 46, 17, 10, 10
+ RTEXT "11", -1, 46, 28, 10, 10
+ RTEXT "12", -1, 46, 39, 10, 10
+ RTEXT "13", -1, 46, 50, 10, 10
+ RTEXT "14", -1, 46, 61, 10, 10
+ RTEXT "15", -1, 46, 72, 10, 10
+ RTEXT "16", -1, 46, 83, 10, 10
+}
+
+IDI_PLUGIN_ENABLE ICON "wat_enable.ico"
+IDI_PLUGIN_DISABLE ICON "wat_disable.ico"
+
+PARTS 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
+{
+ GROUPBOX "Switch ON these modules", IDC_MODULEGROUP, 2, 2, 188, 218, WS_TABSTOP
+}
+
+LANGUAGE 0,0
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,0,6,12
+ PRODUCTVERSION 0,0,6,12
+ FILEFLAGSMASK $3F
+ FILEOS 4
+ FILETYPE 2
+ FILESUBTYPE 0
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "CompanyName",""
+ VALUE "Comments", "Plugin to get, insert to messages and show currently played song info"
+ VALUE "FileDescription", "WATrack plugin for Miranda NG"
+ VALUE "FileVersion", "0, 0, 6, 12 "0
+ VALUE "InternalName", "WATrack"
+ VALUE "OriginalFilename", "watrack.dll"
+ VALUE "ProductName", " WATrack Dynamic Link Library (DLL)"
+ VALUE "ProductVersion", "0, 0, 6, 12 "0
+ VALUE "SpecialBuild", "17.11.2009 "0
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation",0,1200
+ END
+END
diff --git a/plugins/Watrack/res/watrack.res b/plugins/Watrack/res/watrack.res
new file mode 100644
index 0000000000..3c2d4932df
--- /dev/null
+++ b/plugins/Watrack/res/watrack.res
Binary files differ
diff --git a/plugins/Watrack/srv_format.pas b/plugins/Watrack/srv_format.pas
new file mode 100644
index 0000000000..aa892bb7da
--- /dev/null
+++ b/plugins/Watrack/srv_format.pas
@@ -0,0 +1,394 @@
+{format service}
+unit srv_format;
+
+interface
+
+uses windows,wat_api;
+
+procedure DefFillFormatList (hwndList:hwnd);
+procedure DefCheckFormatList(hwndList:hwnd);
+function ProcessFormatLink:integer;
+
+function GetFileFormatInfo(var dst:tSongInfo):integer;
+function CheckExt(fname:pWideChar):integer;
+
+function DeleteKnownExt(src:pWideChar):pWideChar;
+function KnownFileType(fname:PWideChar):boolean;
+function isContainer(fname:PWideChar):boolean;
+
+function ServiceFormat(wParam:WPARAM;lParam:LPARAM):integer;cdecl;
+procedure RegisterFormat(ext:PAnsiChar;proc:tReadFormatProc;flags:dword=0);
+procedure ClearFormats;
+
+type
+ MusEnumProc = function(param:PAnsiChar;lParam:LPARAM):bool;stdcall;
+
+function EnumFormats(param:MusEnumProc;lParam:LPARAM):bool;
+
+type
+ pwFormat = ^twFormat;
+ twFormat = record
+ This:tMusicFormat;
+ Next:pwFormat;
+ end;
+
+const
+ FormatLink:pwFormat=nil;
+
+implementation
+
+uses
+ CommCtrl,common;
+type
+ pFmtArray = ^tFmtArray;
+ tFmtArray = array [0..10] of tMusicFormat;
+
+const
+ StartSize = 32;
+ Step = 8;
+
+const
+ fmtLink:pFmtArray=nil;
+ FmtNum:integer=0;
+ FmtMax:integer=0;
+
+function ProcessFormatLink:integer;
+var
+ ptr:pwFormat;
+begin
+ result:=0;
+ ptr:=FormatLink;
+ while ptr<>nil do
+ begin
+ RegisterFormat(@ptr.This.ext,ptr.This.proc,ptr.This.flags);
+ inc(result);
+ ptr:=ptr^.Next;
+ end;
+end;
+
+function EnumFormats(param:MusEnumProc;lParam:LPARAM):bool;
+var
+ tmp:pFmtArray;
+ i,j:integer;
+ s:array [0..8] of AnsiChar;
+begin
+ if (FmtNum>0) and (@param<>nil) then
+ begin
+ GetMem(tmp,FmtNum*SizeOf(tMusicFormat));
+ move(fmtLink^,tmp^,FmtNum*SizeOf(tMusicFormat));
+ i:=0;
+ j:=FmtNum;
+ s[8]:=#0;
+ repeat
+ move(tmp^[i].ext,s,8);
+ if not param(s,lParam) then break;
+ inc(i);
+ until i=j;
+ FreeMem(tmp);
+ result:=true;
+ end
+ else
+ result:=false;
+end;
+
+function FindFormat(ext:PAnsiChar):integer;
+var
+ i:integer;
+ ss:array [0..7] of AnsiChar;
+begin
+ i:=0;
+ int64(ss):=0;
+ StrCopy(ss,ext,7);
+ while i<FmtNum do
+ begin
+ if int64(fmtLink^[i].ext)=int64(ss) then
+ begin
+ result:=i;
+ exit;
+ end;
+ inc(i);
+ end;
+ result:=WAT_RES_NOTFOUND;
+end;
+
+procedure DefFillFormatList(hwndList:hwnd);
+var
+ item:LV_ITEMA;
+ lvc:LV_COLUMN;
+ newItem:integer;
+ i:integer;
+ p:pMusicFormat;
+begin
+ FillChar(item,SizeOf(item),0);
+ FillChar(lvc,SizeOf(lvc),0);
+ ListView_SetExtendedListViewStyle(hwndList, LVS_EX_CHECKBOXES);
+ lvc.mask:=LVCF_FMT;
+ lvc.fmt :={LVCFMT_IMAGE or} LVCFMT_LEFT;
+ ListView_InsertColumn(hwndList,0,lvc);
+
+ item.mask:=LVIF_TEXT or LVIF_PARAM;
+ item.iItem:=1000;
+ i:=0;
+ while i<FmtNum do
+ begin
+ p:=@fmtLink^[i];
+ item.pszText:=@p^.ext;
+ item.lParam := p^.flags;
+ newItem:=SendMessageA(hwndList,LVM_INSERTITEMA,0,LPARAM(@item));
+ if newItem>=0 then
+ begin
+ if (p^.flags and WAT_OPT_DISABLED)=0 then
+ ListView_SetCheckState(hwndList,newItem,TRUE);
+ end;
+ inc(i);
+ end;
+ ListView_SetColumnWidth(hwndList,0,LVSCW_AUTOSIZE);
+end;
+
+procedure DefCheckFormatList(hwndList:hwnd);
+var
+ i,j,k:integer;
+ item:LV_ITEMA;
+ szTemp:array [0..109] of AnsiChar;
+ p:pMusicFormat;
+begin
+ FillChar(item,SizeOf(item),0);
+ item.mask:=LVIF_TEXT;
+ item.pszText:=@szTemp;
+ item.cchTextMax:=100;
+ k:=ListView_GetItemCount(hwndList)-1;
+ for i:=0 to k do
+ begin
+ item.iItem:=i;
+ SendMessageA(hwndList,LVM_GETITEMA,0,LPARAM(@item));
+ j:=FindFormat(item.pszText);
+ if j<>WAT_RES_NOTFOUND then // always?
+ begin
+ p:=@fmtLink^[j];
+ if ListView_GetCheckState(hwndList,i)=0 then
+ p^.flags:=p^.flags or WAT_OPT_DISABLED
+ else
+ p^.flags:=p^.flags and not WAT_OPT_DISABLED;
+ end;
+ end;
+end;
+
+function DeleteKnownExt(src:pWideChar):pWideChar;
+var
+ s :array [0..7] of WideChar;
+ ss:array [0..7] of AnsiChar;
+ i,j:integer;
+begin
+ GetExt(src,s);
+ if s[0]<>#0 then
+ begin
+ int64(ss):=0;
+ i:=0;
+ while (s[i]<>#0) and (i<8) do
+ begin
+ ss[i]:=AnsiChar(s[i]);
+ inc(i);
+ end;
+ j:=0;
+ while j<FmtNum do
+ begin
+ if int64(fmtLink^[j].ext)=int64(ss) then
+ begin
+ i:=StrLenW(s);
+ src[integer(StrLenW(src))-i-1]:=#0;
+ break;
+ end;
+ inc(j);
+ end;
+ end;
+ result:=src;
+end;
+
+function KnownFileType(fname:PWideChar):boolean;
+var
+ i:integer;
+ s :array [0..7] of WideChar;
+ ss:array [0..7] of AnsiChar;
+begin
+ result:=false;
+ if (fname=nil) or (fname^=#0) then
+ exit;
+ GetExt(fname,s);
+ int64(ss):=0;
+ if s[0]<>#0 then
+ begin
+ i:=0;
+ while (s[i]<>#0) and (i<8) do
+ begin
+ ss[i]:=AnsiChar(s[i]);
+ inc(i);
+ end;
+ i:=0;
+ while i<FmtNum do
+ begin
+ if (int64(fmtLink^[i].ext)=int64(ss)) then
+ begin
+ if ((fmtLink^[i].flags and WAT_OPT_DISABLED)=0) then
+ result:=true;
+ break;
+ end;
+ inc(i);
+ end;
+ end;
+end;
+
+function isContainer(fname:PWideChar):boolean;
+begin
+ if CheckExt(fname)=WAT_RES_OK then
+ begin
+ result:=(fmtLink^[0].flags and WAT_OPT_CONTAINER)<>0;
+ end
+ else
+ result:=false;
+end;
+
+function GetFileFormatInfo(var dst:tSongInfo):integer;
+begin
+ result:=CheckExt(dst.mfile);
+ if result=WAT_RES_OK then
+ begin
+ fmtLink^[0].proc(dst);
+ end;
+end;
+
+function CheckExt(fname:pWideChar):integer;
+var
+ i:integer;
+ tmp:tMusicFormat;
+ ls:array [0..7] of WideChar;
+ ss:array [0..7] of AnsiChar;
+begin
+ GetExt(fname,ls);
+ i:=0;
+ int64(ss):=0;
+ while (ls[i]<>#0) and (i<8) do
+ begin
+ ss[i]:=AnsiChar(ls[i]);
+ inc(i);
+ end;
+ i:=0;
+ while i<FmtNum do
+ begin
+ if (int64(fmtLink^[i].ext)=int64(ss)) then
+ begin
+ if ((fmtLink^[i].flags and WAT_OPT_DISABLED)=0) then
+ begin
+ if i>0 then
+ begin
+ tmp:=fmtLink^[i];
+ move(fmtLink^[0],fmtLink^[1],SizeOf(tMusicFormat)*i);
+ fmtLink^[0]:=tmp;
+ end;
+ result:=WAT_RES_OK;
+ exit;
+ end
+ else
+ break;
+ end;
+ inc(i);
+ end;
+ result:=WAT_RES_NOTFOUND;
+end;
+
+function ServiceFormat(wParam:WPARAM;lParam:LPARAM):integer;cdecl;
+var
+ p:integer;
+ nl:pFmtArray;
+begin
+ result:=WAT_RES_NOTFOUND;
+ if LoWord(wParam)<>WAT_ACT_REGISTER then
+ p:=FindFormat(PAnsiChar(lParam))
+ else
+ p:=0;
+ case LoWord(wParam) of
+ WAT_ACT_REGISTER: begin
+ if @pMusicFormat(lParam)^.proc=nil then
+ exit;
+ p:=FindFormat(pMusicFormat(lParam)^.ext);
+ if (p=WAT_RES_NOTFOUND) or ((wParam and WAT_ACT_REPLACE)<>0) then
+ begin
+ if (p<>WAT_RES_NOTFOUND) and ((fmtLink^[p].flags and WAT_OPT_ONLYONE)<>0) then
+ exit;
+ if FmtNum=FmtMax then // expand array when append
+ begin
+ if FmtMax=0 then
+ FmtMax:=StartSize
+ else
+ inc(FmtMax,Step);
+ GetMem(nl,FmtMax*SizeOf(tMusicFormat));
+ if fmtLink<>nil then
+ begin
+ move(fmtLink^,nl^,FmtNum*SizeOf(tMusicFormat));
+ FreeMem(fmtLink);
+ end;
+ fmtLink:=nl;
+ end;
+ if p=WAT_RES_NOTFOUND then
+ begin
+ p:=FmtNum;
+ result:=WAT_RES_OK;
+ inc(FmtNum);
+ end
+ else
+ result:=int_ptr(@fmtLink^[p].proc);
+ move(pMusicFormat(lParam)^,fmtLink^[p],SizeOf(tMusicFormat));// fill
+ end;
+ end;
+ WAT_ACT_UNREGISTER: begin
+ if p<>WAT_RES_NOTFOUND then
+ begin
+ dec(FmtNum);
+ if p<FmtNum then // last
+ Move(fmtLink^[p+1],fmtLink^[p],SizeOf(tMusicFormat)*(FmtNum-p));
+ result:=WAT_RES_OK;
+ end;
+ end;
+ WAT_ACT_DISABLE: begin
+ if p<>WAT_RES_NOTFOUND then
+ begin
+ fmtLink^[p].flags:=fmtLink^[p].flags or WAT_OPT_DISABLED;
+ result:=WAT_RES_DISABLED
+ end;
+ end;
+ WAT_ACT_ENABLE: begin
+ if p<>WAT_RES_NOTFOUND then
+ begin
+ fmtLink^[p].flags:=fmtLink^[p].flags and not WAT_OPT_DISABLED;
+ result:=WAT_RES_ENABLED
+ end;
+ end;
+ WAT_ACT_GETSTATUS: begin
+ if p<>WAT_RES_NOTFOUND then
+ begin
+ if (fmtLink^[p].flags and WAT_OPT_DISABLED)<>0 then
+ result:=WAT_RES_DISABLED
+ else
+ result:=WAT_RES_ENABLED;
+ end;
+ end;
+ end;
+end;
+
+procedure RegisterFormat(ext:PAnsiChar;proc:tReadFormatProc;flags:dword=0);
+var
+ tmp:tMusicFormat;
+begin
+ FillChar(tmp,SizeOf(tMusicFormat),0);
+ StrCopy (tmp.ext,ext,7);
+ tmp.proc:=proc;
+ tmp.flags:=flags;
+ ServiceFormat(WAT_ACT_REGISTER,LPARAM(@tmp));
+end;
+
+procedure ClearFormats;
+begin
+ if FmtNum>0 then
+ FreeMem(fmtLink);
+end;
+
+end.
diff --git a/plugins/Watrack/srv_player.pas b/plugins/Watrack/srv_player.pas
new file mode 100644
index 0000000000..60fd6534f4
--- /dev/null
+++ b/plugins/Watrack/srv_player.pas
@@ -0,0 +1,1220 @@
+{player service}
+unit srv_player;
+
+interface
+
+uses windows,common,wat_api;
+
+function GetPlayerNote(name:PAnsiChar):pWideChar;
+
+function SetPlayerIcons(fname:pAnsiChar):integer;
+
+function LoadFromFile(fname:PAnsiChar):integer;
+function ProcessPlayerLink:integer;
+
+function ServicePlayer(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+function SendCommand (wParam:WPARAM;lParam:LPARAM;flags:integer):int_ptr;
+
+procedure ClearPlayers;
+
+// options procedures
+procedure DefFillPlayerList (hwndList:hwnd);
+procedure DefCheckPlayerList(hwndList:hwnd);
+
+type
+ MusEnumProc = function(param:PAnsiChar;lParam:LPARAM):bool;stdcall;
+
+function EnumPlayers(param:MusEnumProc;lParam:LPARAM):bool;
+
+// "Get info" procedures
+function CheckPlayers (var dst:tSongInfo;flags:cardinal):integer;
+function CheckFile (var dst:tSongInfo;flags:cardinal;timeout:cardinal):integer;
+function GetChangingInfo(var dst:tSongInfo;flags:cardinal):integer;
+function GetInfo (var dst:tSongInfo;flags:cardinal):integer;
+
+// support procedures
+procedure ClearSongInfoData(var dst:tSongInfo;withFree:bool);
+procedure ClearPlayerInfo (var dst:tSongInfo;withFree:bool);
+procedure ClearFileInfo (var dst:tSongInfo;withFree:bool);
+procedure ClearChangingInfo(var dst:tSongInfo;withFree:bool);
+procedure ClearTrackInfo (var dst:tSongInfo;withFree:bool);
+
+procedure CopyPlayerInfo (const src:tSongInfo;var dst:tSongInfo);
+procedure CopyFileInfo (const src:tSongInfo;var dst:tSongInfo);
+procedure CopyChangingInfo(const src:tSongInfo;var dst:tSongInfo);
+procedure CopyTrackInfo (const src:tSongInfo;var dst:tSongInfo);
+
+type
+ pwPlayer = ^twPlayer;
+ twPlayer = record
+ This:pPlayerCell;
+ Next:pwPlayer;
+ end;
+
+const
+ PlayerLink:pwPlayer=nil;
+
+implementation
+
+uses
+ shellapi,CommCtrl
+ ,appcmdapi,io,syswin,wrapper,srv_format,winampapi,msninfo,memini;
+
+type
+ pPlyArray = ^tPlyArray;
+ tPlyArray = array [0..10] of tPlayerCell;
+
+type
+ pTmplCell = ^tTmplCell;
+ tTmplCell = record
+ p_class,
+ p_text :PAnsiChar;
+ p_class1,
+ p_text1 :PAnsiChar;
+ p_file :PAnsiChar;
+ p_prefix :pWideChar;
+ p_postfix:pWideChar;
+ end;
+
+const
+ StartSize = 32;
+ Step = 8;
+ buflen = 2048;
+
+const
+ plyLink:pPlyArray=nil;
+ PlyNum:integer=0;
+ PlyMax:integer=0;
+
+function ProcessPlayerLink:integer;
+var
+ ptr:pwPlayer;
+begin
+ ptr:=PlayerLink;
+ result:=0;
+ while ptr<>nil do
+ begin
+ ServicePlayer(WAT_ACT_REGISTER,lparam(ptr.This));
+ ptr:=ptr^.Next;
+ inc(result);
+ end;
+end;
+
+function SetPlayerIcons(fname:pAnsiChar):integer;
+var
+ i,j:integer;
+ buf:array [0..255] of AnsiChar;
+ p,pp:pAnsiChar;
+ lhIcon:HICON;
+begin
+ result:=LoadLibraryA(fname);
+ if result<>0 then
+ begin
+ p:=StrCopyE(buf,'Player_');
+ i:=0;
+ while i<PlyNum do
+ begin
+ with plyLink^[i] do
+ begin
+ pp:=p;
+ for j:=0 to StrLen(Desc)-1 do
+ begin
+ if Desc[j] in sLatWord then
+ pp^:=UpCase(Desc[j])
+ else
+ pp^:='_';
+ inc(pp);
+ end;
+ pp^:=#0;
+ lhIcon:=LoadImageA(result,buf,IMAGE_ICON,16,16,0);
+ if lhIcon>0 then
+ begin
+ if Icon<>0 then
+ DestroyIcon(Icon);
+ Icon:=lhIcon;
+ end;
+ end;
+ inc(i);
+ end;
+ FreeLibrary(result);
+ end;
+end;
+
+function EnumPlayers(param:MusEnumProc;lParam:LPARAM):bool;
+var
+ tmp:pPlyArray;
+ i,j:integer;
+begin
+ if (PlyNum>0) and (@param<>nil) then
+ begin
+ GetMem(tmp,PlyNum*SizeOf(tPlayerCell));
+ move(PlyLink^,tmp^,PlyNum*SizeOf(tPlayerCell));
+ i:=0;
+ j:=PlyNum;
+ repeat
+ if not param(tmp^[i].Desc,lParam) then break;
+ inc(i);
+ until i=j;
+ FreeMem(tmp);
+ result:=true;
+ end
+ else
+ result:=false;
+end;
+
+procedure PreProcess; // BASS to start
+var
+ i:integer;
+ tmp:tPlayerCell;
+begin
+ i:=1;
+ while i<(PlyNum-1) do
+ begin
+ if (plyLink^[i].flags and WAT_OPT_FIRST)<>0 then
+ begin
+ tmp:=plyLink^[i];
+ move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*i);
+ plyLink^[0]:=tmp;
+{
+ move(plyLink^[i],tmp,SizeOf(tPlayerCell));
+ move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*i);
+ move(tmp,plyLink^[0],SizeOf(tPlayerCell));
+}
+ break;
+ end;
+ inc(i);
+ end;
+ if (plyLink^[0].flags and WAT_OPT_LAST)<>0 then
+ begin
+ tmp:=plyLink^[0];
+ move(plyLink^[1],plyLink^[0],SizeOf(tPlayerCell)*(PlyNum-1));
+ plyLink^[PlyNum-1]:=tmp;
+{
+ move(plyLink^[0],tmp,SizeOf(tPlayerCell));
+ move(plyLink^[1],plyLink^[0],SizeOf(tPlayerCell)*(PlyNum-1));
+ move(tmp,plyLink^[PlyNum-1],SizeOf(tPlayerCell));
+}
+ end;
+end;
+
+procedure PostProcess; // Winamp clone to the end
+var
+ i,j:integer;
+ tmp:tPlayerCell;
+begin
+ i:=1;
+ j:=PlyNum-1;
+ while i<j do
+ begin
+ if (plyLink^[i].flags and WAT_OPT_LAST)<>0 then
+ begin
+ tmp:=plyLink^[i];
+ move(plyLink^[i+1],plyLink^[i],SizeOf(tPlayerCell)*(PlyNum-i-1));
+ plyLink^[PlyNum-1]:=tmp;
+{
+ move(plyLink^[i],tmp,SizeOf(tPlayerCell));
+ move(plyLink^[i+1],plyLink^[i],SizeOf(tPlayerCell)*(PlyNum-i-1));
+ move(tmp,plyLink^[PlyNum-1],SizeOf(tPlayerCell));
+}// break;
+ i:=1;
+ dec(j);
+ continue;
+ end;
+ inc(i);
+ end;
+end;
+
+function FindPlayer(desc:PAnsiChar):integer;
+var
+ i:integer;
+begin
+ if (desc<>nil) and (desc^<>#0) then
+ begin
+ i:=0;
+ while i<PlyNum do
+ begin
+ if lstrcmpia(plyLink^[i].Desc,desc)=0 then
+ begin
+ result:=i;
+ exit;
+ end;
+ inc(i);
+ end;
+ end;
+ result:=WAT_RES_NOTFOUND;
+end;
+
+function GetPlayerNote(name:PAnsiChar):pWideChar;
+var
+ i:integer;
+begin
+ i:=FindPlayer(name);
+ if i>=0 then
+ result:=plyLink^[i].Notes
+ else
+ result:=nil;
+end;
+
+procedure DefFillPlayerList(hwndList:hwnd);
+var
+ item:LV_ITEMA;
+ lvc:TLVCOLUMN;
+ i,newItem:integer;
+
+ il:HIMAGELIST; //!!
+begin
+ FillChar(item,SizeOf(item),0);
+ FillChar(lvc,SizeOf(lvc),0);
+ ListView_SetExtendedListViewStyle(hwndList, LVS_EX_CHECKBOXES);
+ lvc.mask:=LVCF_FMT or LVCF_WIDTH;
+
+ lvc.fmt:=LVCFMT_LEFT;
+ lvc.cx:=160;
+ ListView_InsertColumn(hwndList,0,lvc);
+
+ item.mask:=LVIF_TEXT or LVIF_IMAGE; //!!
+ i:=0;
+
+ il:=ImageList_Create(16,16,ILC_COLOR32 or ILC_MASK,0,1); //!!
+ while i<PlyNum do
+ begin
+ item.iImage:=ImageList_AddIcon(il,plyLink^[i].Icon);
+ item.iItem:=i;
+ item.pszText:=plyLink^[i].Desc;
+ newItem:=SendMessageA(hwndList,LVM_INSERTITEMA,0,lparam(@item));
+ if newItem>=0 then
+ begin
+ if (plyLink^[i].flags and WAT_OPT_DISABLED)=0 then
+ ListView_SetCheckState(hwndList,newItem,TRUE);
+ end;
+ inc(i);
+ end;
+ ImageList_Destroy(SendMessage(hwndList,LVM_SETIMAGELIST,LVSIL_SMALL,il)); //!!
+// ListView_SetColumnWidth(hwndList,0,LVSCW_AUTOSIZE);
+end;
+
+procedure DefCheckPlayerList(hwndList:hwnd);
+var
+ i,j,k:integer;
+ item:LV_ITEMA;
+ szTemp:array [0..109] of AnsiChar;
+ p:pPlayerCell;
+begin
+ FillChar(item,SizeOf(item),0);
+ item.mask :=LVIF_TEXT;
+ item.pszText :=@szTemp;
+ item.cchTextMax:=100;
+ k:=ListView_GetItemCount(hwndList)-1;
+ for i:=0 to k do
+ begin
+ item.iItem:=i;
+ SendMessageA(hwndList,LVM_GETITEMA,0,lparam(@item));
+ j:=FindPlayer(item.pszText);
+ if j<>WAT_RES_NOTFOUND then
+ begin
+ p:=@plyLink^[j];
+ if ListView_GetCheckState(hwndList,i)=0 then
+ p^.flags:=p^.flags or WAT_OPT_DISABLED
+ else
+ p^.flags:=p^.flags and not WAT_OPT_DISABLED;
+ end;
+ end;
+end;
+
+procedure ClearTemplate(tmpl:pTmplCell);
+begin
+ with tmpl^ do
+ begin
+ mFreeMem(p_class);
+ mFreeMem(p_text);
+ mFreeMem(p_class1);
+ mFreeMem(p_text1);
+ mFreeMem(p_file);
+ mFreeMem(p_prefix);
+ mFreeMem(p_postfix);
+ end;
+ FreeMem(tmpl);
+end;
+
+function ServicePlayer(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ p:integer;
+ i:integer;
+ nl:pPlyArray;
+ tmp:tPlayerCell;
+begin
+ result:=WAT_RES_ERROR;
+ if LoWord(wParam)=WAT_ACT_REGISTER then
+ begin
+ if pPlayerCell(lParam)^.Check=nil then
+ exit;
+ p:=0;
+ end
+ else
+ p:=FindPlayer(PAnsiChar(lParam));
+ case LoWord(wParam) of
+
+ WAT_ACT_REGISTER: begin
+ p:=FindPlayer(pPlayerCell(lParam)^.Desc);
+ if (p=WAT_RES_NOTFOUND) or ((wParam and WAT_ACT_REPLACE)<>0) then
+ begin
+ if (p<>WAT_RES_NOTFOUND) and ((plyLink^[p].flags and WAT_OPT_ONLYONE)<>0) then
+ exit;
+
+ if p=WAT_RES_NOTFOUND then
+ begin
+ p:=PlyNum;
+ result:=WAT_RES_OK;
+ inc(PlyNum);
+
+ if PlyNum>PlyMax then // expand array when append
+ begin
+ if PlyMax=0 then
+ PlyMax:=StartSize
+ else
+ inc(PlyMax,Step);
+ GetMem(nl,PlyMax*SizeOf(tPlayerCell));
+ if plyLink<>nil then
+ begin
+ move(plyLink^,nl^,PlyNum*SizeOf(tPlayerCell));
+ FreeMem(plyLink);
+ end;
+ plyLink:=nl;
+ end;
+ FillChar(plyLink^[p],SizeOf(tPlayerCell),0);
+// doubling notes
+ if (pPlayerCell(lParam)^.Notes<>nil) and
+ ((pPlayerCell(lParam)^.flags and WAT_OPT_TEMPLATE)=0) then
+ begin
+ i:=(StrLenW(pPlayerCell(lParam)^.Notes)+1)*SizeOf(WideChar);
+ GetMem(plyLink^[p].Notes,i);
+ move(pPlayerCell(lParam)^.Notes^,plyLink^[p].Notes^,i);
+ end
+ else
+ plyLink^[p].Notes:=pPlayerCell(lParam)^.Notes;
+
+// doubling description
+ i:=StrLen(pPlayerCell(lParam)^.Desc)+1;
+ GetMem(plyLink^[p].Desc,i);
+ move(pPlayerCell(lParam)^.Desc^,plyLink^[p].Desc^,i);
+
+// doubling url
+
+ if pPlayerCell(lParam)^.URL<>nil then
+ begin
+ with plyLink^[p] do
+ begin
+ i:=StrLen(pPlayerCell(lParam)^.URL)+1;
+ GetMem(URL,i);
+ move(pPlayerCell(lParam)^.URL^,URL^,i);
+ end;
+ end
+ else
+ plyLink^[p].URL:=nil;
+
+ end
+ else // existing player
+ begin
+ if (plyLink^[p].flags and WAT_OPT_TEMPLATE)=0 then
+ result:=int_ptr(plyLink^[p].Check)
+ else
+ begin // remove any info from templates
+ result:=WAT_RES_OK;
+ ClearTemplate(pTmplCell(plyLink^[p].Check));
+ end;
+ end;
+ // fill info
+ with plyLink^[p] do
+ begin
+ flags:=pPlayerCell(lParam)^.flags;
+ if URL<>nil then
+ flags:=flags or WAT_OPT_HASURL;
+ if pPlayerCell(lParam)^.Icon<>0 then
+ begin
+ if icon<>0 then
+ DestroyIcon(icon);
+ icon:=CopyIcon(pPlayerCell(lParam)^.Icon);
+ end;
+ Init :=pPlayerCell(lParam)^.Init;
+ DeInit :=pPlayerCell(lParam)^.DeInit;
+ Check :=pPlayerCell(lParam)^.Check;
+ GetStatus:=pPlayerCell(lParam)^.GetStatus;
+ GetName :=pPlayerCell(lParam)^.GetName;
+ GetInfo :=pPlayerCell(lParam)^.GetInfo;
+ Command :=pPlayerCell(lParam)^.Command;
+ if Init<>nil then
+ tInitProc(Init);
+ end;
+
+// PreProcess;
+ PostProcess;
+ end;
+ end;
+
+ WAT_ACT_UNREGISTER: begin
+ if p<>WAT_RES_NOTFOUND then
+ begin
+ dec(PlyNum);
+ if plyLink^[p].DeInit<>nil then
+ tDeInitProc(plyLink^[p].DeInit);
+ FreeMem(plyLink^[p].Desc);
+ if (plyLink^[p].flags and WAT_OPT_TEMPLATE)<>0 then
+ ClearTemplate(pTmplCell(plyLink^[p].Check));
+ if p<PlyNum then // not last
+ Move(plyLink^[p+1],plyLink^[p],SizeOf(tPlayerCell)*(PlyNum-p));
+ result:=WAT_RES_OK;
+ end;
+ end;
+
+ WAT_ACT_DISABLE: begin
+ if p<>WAT_RES_NOTFOUND then
+ begin
+ plyLink^[p].flags:=plyLink^[p].flags or WAT_OPT_DISABLED;
+ result:=WAT_RES_DISABLED
+ end;
+ end;
+
+ WAT_ACT_ENABLE: begin
+ if p<>WAT_RES_NOTFOUND then
+ begin
+ plyLink^[p].flags:=plyLink^[p].flags and not WAT_OPT_DISABLED;
+ result:=WAT_RES_ENABLED
+ end;
+ end;
+
+ WAT_ACT_GETSTATUS: begin
+ if p<>WAT_RES_NOTFOUND then
+ begin
+ if (plyLink^[p].flags and WAT_OPT_DISABLED)<>0 then
+ result:=WAT_RES_DISABLED
+ else
+ result:=WAT_RES_ENABLED;
+ end;
+ end;
+
+ WAT_ACT_SETACTIVE: begin
+ if p>0 then
+ begin
+ tmp:=plyLink^[p];
+ move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*p);
+ plyLink^[0]:=tmp;
+{
+ move(plyLink^[p],tmp ,SizeOf(tPlayerCell));
+ move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*p);
+ move(tmp ,plyLink^[0],SizeOf(tPlayerCell));
+}
+ end;
+// PreProcess;
+// PostProcess;
+ end;
+
+ end;
+end;
+
+function LoadFromFile(fname:PAnsiChar):integer;
+var
+ buf:pAnsiChar;
+ ptr:PAnsiChar;
+ NumPlayers:integer;
+ pcell:pTmplCell;
+ rec:tPlayerCell;
+ st,sec:pointer;
+begin
+ result:=0;
+ st:=OpenStorage(fname);
+ if st=nil then exit;
+
+ buf:=GetSectionList(st);
+ ptr:=buf;
+ NumPlayers:=0;
+ while ptr^<>#0 do
+ begin
+ sec:=SearchSection(st,ptr);
+
+ FillChar(rec,SizeOf(rec),0);
+
+ GetMem(pcell,SizeOf(tTmplCell));
+ StrDup(pcell^.p_class ,GetParamSectionStr(sec,'class' ));
+ StrDup(pcell^.p_text ,GetParamSectionStr(sec,'text' ));
+ StrDup(pcell^.p_class1,GetParamSectionStr(sec,'class1'));
+ StrDup(pcell^.p_text1 ,GetParamSectionStr(sec,'text1' ));
+ StrDup(pcell^.p_file ,GetParamSectionStr(sec,'file' ));
+
+ AnsiToWide(GetParamSectionStr(sec,'prefix' ),pcell^.p_prefix );
+ AnsiToWide(GetParamSectionStr(sec,'postfix'),pcell^.p_postfix);
+
+ rec.URL :=GetParamSectionStr(sec,'url');
+ rec.Desc :=ptr;
+ rec.flags:=GetParamSectionInt(sec,'flags') or WAT_OPT_TEMPLATE;
+ rec.Check:=pointer(pcell);
+
+ UTF8ToWide(GetParamSectionStr(sec,'notes'),rec.Notes);
+
+ ServicePlayer(WAT_ACT_REGISTER,lparam(@rec));
+
+ inc(NumPlayers);
+ while ptr^<>#0 do inc(ptr);
+ inc(ptr);
+ end;
+
+ FreeSectionList(buf);
+ CloseStorage(st);
+ result:=NumPlayers;
+end;
+
+function CheckTmpl(lwnd:HWND;cell:pTmplCell;flags:integer):HWND;
+var
+ tmp,EXEName:PAnsiChar;
+ ltmp,lcycle:boolean;
+ lclass,ltext:PAnsiChar;
+begin
+ lclass:=cell.p_class;
+ ltext :=cell.p_text;
+ lcycle:=false;
+ repeat
+ result:=lwnd;
+ if (lclass<>nil) or (ltext<>nil) then
+ repeat
+ result:=FindWindowExA(0,result,lclass,ltext);
+ if result=0 then
+ break;
+// check filename
+ if cell.p_file<>NIL then
+ begin
+ tmp:=Extract(GetEXEByWnd(result,EXEName),true);
+ mFreeMem(EXEName);
+ ltmp:=lstrcmpia(tmp,cell.p_file)=0;
+ mFreeMem(tmp);
+ if not ltmp then
+ continue;
+ end;
+ exit;
+ until false;
+ if lcycle then break;
+ lclass:=cell.p_class1;
+ ltext :=cell.p_text1;
+ if (lclass=nil) and (ltext=nil) then break;
+ lcycle:=not lcycle;
+ until false;
+end;
+
+// find active player
+function CheckAllPlayers(flags:integer;var status:integer; var PlayerChanged:bool):integer;
+const
+ PrevPlayerName:PAnsiChar=nil;
+var
+ stat,act,oldstat,i,j:integer;
+ tmp:tPlayerCell;
+ wwnd,lwnd:HWND;
+begin
+ i:=0;
+ result:=WAT_RES_NOTFOUND;
+ PlayerChanged:=true;
+ PreProcess;
+ oldstat:=-1;
+ act:=-1;
+ stat:=WAT_MES_UNKNOWN;
+ wwnd:=0;
+ while i<PlyNum do
+ begin
+ if (plyLink^[i].flags and WAT_OPT_DISABLED)=0 then
+ begin
+
+ lwnd:=0;
+ repeat
+ wwnd:=0;
+ stat:=WAT_MES_UNKNOWN;
+ if (plyLink^[i].flags and WAT_OPT_TEMPLATE)<>0 then
+ begin
+ lwnd:=CheckTmpl(lwnd,plyLink^[i].Check,plyLink^[i].flags);
+// find "Winamp" window
+ if (lwnd<>dword(WAT_RES_NOTFOUND)) and (lwnd<>0) and
+ ((plyLink^[i].flags and WAT_OPT_WINAMPAPI)<>0) then
+ begin
+ wwnd:=WinampFindWindow(lwnd);
+ if wwnd<>0 then
+ stat:=WinampGetStatus(wwnd);
+ end;
+ end
+ else
+ begin
+ with plyLink^[i] do
+ begin
+ lwnd:=tCheckProc(Check)(lwnd,flags);
+ if (lwnd<>dword(WAT_RES_NOTFOUND)) and (lwnd<>0) and (GetStatus<>nil) then
+ stat:=tStatusProc(GetStatus)(lwnd);
+ end;
+ end;
+ if (lwnd<>dword(WAT_RES_NOTFOUND)) and (lwnd<>0) then
+ begin
+ if (stat=WAT_MES_PLAYING) or ((flags and WAT_OPT_CHECKALL)=0) then
+ begin
+ act :=i;
+ result:=lwnd;
+ break;
+ end
+ else
+ begin
+ case stat of
+ WAT_MES_STOPPED: j:=00;
+ WAT_MES_UNKNOWN: j:=10;
+ WAT_MES_PAUSED : j:=20;
+ else
+ j:=00;
+ end;
+ if oldstat<j then
+ begin
+ oldstat:=j;
+ act :=i;
+ result :=lwnd;
+ end;
+ end;
+ end
+ else
+ break;
+ if (plyLink^[i].flags and WAT_OPT_SINGLEINST)<>0 then
+ break;
+ until false;
+ if (result<>WAT_RES_NOTFOUND) and (result<>0) and
+ ((stat=WAT_MES_PLAYING) or ((flags and WAT_OPT_CHECKALL)=0)) then
+ break;
+ end;
+ inc(i);
+ end;
+
+ if act>=0 then
+ begin
+ if result=1 then result:=0 //!! for example, mradio
+ else if wwnd<>0 then
+ result:=wwnd;
+ if act>0 then // to first position
+ begin
+ tmp:=plyLink^[act];
+ move(plyLink^[0],plyLink^[1],SizeOf(tPlayerCell)*act);
+ plyLink^[0]:=tmp;
+{
+ move(plyLink^[act],tmp ,SizeOf(tPlayerCell));
+ move(plyLink^[0 ],plyLink^[1],SizeOf(tPlayerCell)*act);
+ move(tmp ,plyLink^[0],SizeOf(tPlayerCell));
+}
+ end;
+ if PrevPlayerName=plyLink^[0].Desc then
+ PlayerChanged:=false
+ else
+ PrevPlayerName:=plyLink^[0].Desc;
+ status:=stat;
+ end
+ else
+ begin
+ PrevPlayerName:=nil;
+ status:=WAT_PLS_NOTFOUND+WAT_MES_UNKNOWN shl 16;
+ end;
+ PostProcess;
+end;
+
+function TranslateToApp(code:integer):integer;
+begin
+ case code of
+ WAT_CTRL_PREV : result:=APPCOMMAND_MEDIA_PREVIOUSTRACK;
+ WAT_CTRL_PLAY : begin
+ if IsW2K then // Win2k+ only
+ result:=APPCOMMAND_MEDIA_PLAY_PAUSE
+ else
+ result:=APPCOMMAND_MEDIA_PLAY;
+ end;
+ WAT_CTRL_PAUSE: result:=APPCOMMAND_MEDIA_PLAY_PAUSE;
+ WAT_CTRL_STOP : result:=APPCOMMAND_MEDIA_STOP;
+ WAT_CTRL_NEXT : result:=APPCOMMAND_MEDIA_NEXTTRACK;
+ WAT_CTRL_VOLDN: result:=APPCOMMAND_VOLUME_DOWN;
+ WAT_CTRL_VOLUP: result:=APPCOMMAND_VOLUME_UP;
+ else
+ result:=-1;
+ end;
+end;
+
+function SendCommand(wParam:WPARAM;lParam:LPARAM;flags:integer):int_ptr;
+var
+ dummy:bool;
+ wnd:HWND;
+ lstat:integer;
+begin
+ result:=WAT_RES_ERROR;
+ wnd:=CheckAllPlayers(flags,lstat,dummy);
+ if wnd<>dword(WAT_RES_NOTFOUND) then
+ if plyLink^[0].Command<>nil then
+ result:=tCommandProc(plyLink^[0].Command)(wnd,wParam,lParam)
+ else if (plyLink^[0].flags and WAT_OPT_WINAMPAPI)<>0 then
+ result:=WinampCommand(wnd,wParam+(lParam shl 16))
+ else if (flags and WAT_OPT_APPCOMMAND)<>0 then
+ begin
+ result:=TranslateToApp(wParam);
+ if result>=0 then
+ result:=SendMMCommand(wnd,result);
+ end;
+end;
+
+// Get Info (default)
+
+function GetSeparator(str:pWideChar):dword;
+begin
+ result:=StrIndexW(str,' '#$2013' ');
+ if result=0 then
+ result:=StrIndexW(str,' - ');
+ if result<>0 then
+ begin
+ result:=result-1 + (3 SHL 16);
+ exit;
+ end;
+ result:=StrIndexW(str,#$2013);
+ if result=0 then
+ result:=StrIndexW(str,'-');
+ if result>0 then
+ result:=result-1 + (1 SHL 16);
+end;
+
+function DefGetTitle(wnd:HWND;fname,wndtxt:pWideChar):pWideChar;
+var
+ i:integer;
+ tmp:pWideChar;
+begin
+ if fname<>nil then
+ tmp:=DeleteKnownExt(ExtractW(fname,true))
+ else
+ tmp:=wndtxt;
+ if tmp=nil then
+ begin
+ result:=nil;
+ exit;
+ end;
+ StrDupW(result,tmp);
+ i:=GetSeparator(result);
+ if i>0 then
+ StrCopyW(result,result+LoWord(i)+HiWord(i));
+ if fname<>nil then
+ mFreeMem(tmp);
+end;
+
+function DefGetArtist(wnd:HWND;fname,wndtxt:pWideChar):pWideChar;
+var
+ i:integer;
+ tmp:pWideChar;
+begin
+ if fname<>nil then
+ tmp:=DeleteKnownExt(ExtractW(fname,true))
+ else
+ tmp:=wndtxt;
+ if tmp=nil then
+ begin
+ result:=nil;
+ exit;
+ end;
+ StrDupW(result,tmp);
+ i:=GetSeparator(result);
+ if i>0 then
+ result[LoWord(i)]:=#0;
+ if fname<>nil then
+ mFreeMem(tmp);
+end;
+
+function DefGetVersionText(ver:integer):pWideChar;
+begin
+ if ver<>0 then
+ begin
+ mGetMem(result,10*SizeOf(WideChar));
+ IntToHex(result,ver);
+ end
+ else
+ result:=nil;
+end;
+
+function DefGetWndText(wnd:HWND):pWideChar;
+var
+ p:pWideChar;
+begin
+ if wnd<>0 then
+ begin
+ result:=GetDlgText(wnd);
+ if result<>nil then
+ begin
+ if (plyLink^[0].flags and WAT_OPT_TEMPLATE)<>0 then
+ begin
+ with pTmplCell(plyLink^[0].Check)^ do
+ begin
+ if p_prefix<>nil then
+ begin
+ p:=StrPosW(result,p_prefix);
+ if p=result then
+ StrCopyW(result,result+StrLenW(p_prefix));
+ end;
+ if p_postfix<>nil then
+ begin
+ p:=StrPosW(result,p_postfix);
+ if p<>nil then
+ p^:=#0;
+ end;
+ end;
+ end;
+ end;
+ end
+ else
+ result:=nil;
+end;
+
+procedure ClearSongInfoData(var dst:tSongInfo;withFree:bool);
+begin
+ ClearPlayerInfo (dst,withFree);
+ ClearChangingInfo(dst,withFree);
+ ClearFileInfo (dst,withFree);
+ ClearTrackInfo (dst,withFree);
+end;
+
+procedure CopyChangingInfo(const src:tSongInfo;var dst:tSongInfo);
+begin
+ dst.time :=src.time;
+ dst.volume :=src.volume;
+ dst.wndtext:=src.wndtext;
+end;
+
+procedure ClearChangingInfo(var dst:tSongInfo;withFree:bool);
+begin
+ dst.time :=0;
+ dst.volume:=0;
+
+ if withFree then
+ mFreeMem(dst.wndtext)
+ else
+ dst.wndtext:=nil;
+end;
+
+procedure CopyFileInfo(const src:tSongInfo;var dst:tSongInfo);
+begin
+ dst.fsize:=src.fsize;
+ dst.date :=src.date;
+ dst.mfile:=src.mfile;
+end;
+
+procedure ClearFileInfo(var dst:tSongInfo;withFree:bool);
+begin
+ if withFree then
+ mFreeMem(dst.mfile)
+ else
+ dst.mfile:=nil;
+ dst.fsize:=0;
+ dst.date :=0;
+end;
+
+procedure CopyPlayerInfo(const src:tSongInfo;var dst:tSongInfo);
+begin
+ dst.player :=src.player;
+ dst.txtver :=src.txtver;
+ dst.url :=src.url;
+ dst.icon :=src.icon;
+ dst.plyver :=src.plyver;
+ dst.plwnd :=src.plwnd;
+ dst.winampwnd:=src.winampwnd;
+end;
+
+procedure ClearPlayerInfo(var dst:tSongInfo;withFree:bool);
+begin
+ if withFree then
+ begin
+ mFreeMem(dst.player);
+ mFreeMem(dst.txtver);
+ mFreeMem(dst.url);
+ if dst.icon<>0 then
+ DestroyIcon(dst.icon);
+ end
+ else
+ begin
+ dst.player:=nil;
+ dst.txtver:=nil;
+ dst.url :=nil;
+ end;
+ dst.icon :=0;
+ dst.plyver :=0;
+ dst.plwnd :=0;
+ dst.winampwnd:=0;
+end;
+
+procedure CopyTrackInfo(const src:tSongInfo;var dst:tSongInfo);
+begin
+ dst.artist :=src.artist;
+ dst.title :=src.title;
+ dst.album :=src.album;
+ dst.genre :=src.genre;
+ dst.comment :=src.comment;
+ dst.year :=src.year;
+ dst.lyric :=src.lyric;
+ dst.cover :=src.cover;
+ dst.kbps :=src.kbps;
+ dst.khz :=src.khz;
+ dst.channels:=src.channels;
+ dst.track :=src.track;
+ dst.total :=src.total;
+ dst.vbr :=src.vbr;
+ dst.codec :=src.codec;
+ dst.width :=src.width;
+ dst.height :=src.height;
+ dst.fps :=src.fps;
+end;
+
+procedure ClearTrackInfo(var dst:tSongInfo;withFree:bool);
+begin
+ if withFree then
+ begin
+ mFreeMem(dst.artist);
+ mFreeMem(dst.title);
+ mFreeMem(dst.album);
+ mFreeMem(dst.genre);
+ mFreeMem(dst.comment);
+ mFreeMem(dst.year);
+ mFreeMem(dst.lyric);
+ mFreeMem(dst.cover);
+ end
+ else
+ begin
+ dst.artist :=nil;
+ dst.title :=nil;
+ dst.album :=nil;
+ dst.genre :=nil;
+ dst.comment:=nil;
+ dst.year :=nil;
+ dst.lyric :=nil;
+ dst.cover :=nil;
+ end;
+ dst.kbps :=0;
+ dst.khz :=0;
+ dst.channels:=0;
+ dst.track :=0;
+ dst.total :=0;
+ dst.vbr :=0;
+ dst.codec :=0;
+ dst.width :=0;
+ dst.height :=0;
+ dst.fps :=0;
+end;
+
+function CheckPlayers(var dst:tSongInfo;flags:cardinal):integer;
+var
+ PlayerChanged:bool;
+ fname:pWideChar;
+begin
+ result:=CheckAllPlayers(flags,dst.status,PlayerChanged);
+
+ if result<>WAT_RES_NOTFOUND then
+ begin
+ if PlayerChanged then
+ begin
+ ClearPlayerInfo(dst,false);
+ AnsiToWide(plyLink^[0].Desc,dst.player);
+ dst.plwnd:=result;
+ FastAnsiToWide(plyLink^[0].URL,dst.url);
+ if plyLink^[0].icon<>0 then
+ dst.icon:=CopyIcon(plyLink^[0].icon)
+ else if result<>0 then
+ begin
+ if GetEXEByWnd(dst.plwnd,fname)<>nil then
+ begin
+ dst.icon:=ExtractIconW(hInstance,fname,0);
+ if dst.icon=1 then
+ dst.icon:=0;
+ if dst.icon<>0 then
+ plyLink^[0].icon:=CopyIcon(dst.icon);
+ mFreeMem(fname);
+ end;
+ end;
+
+ if plyLink^[0].GetInfo<>nil then
+ tInfoProc(plyLink^[0].GetInfo)(dst,flags or WAT_OPT_PLAYERDATA)
+ else if (plyLink^[0].flags and WAT_OPT_WINAMPAPI)<>0 then
+ WinampGetInfo(wparam(@dst),flags or WAT_OPT_PLAYERDATA);
+
+ if (plyLink^[0].flags and WAT_OPT_PLAYERINFO)=0 then
+ if dst.txtver=NIL then dst.txtver:=DefGetVersionText(dst.plyver);
+
+ result:=WAT_RES_NEWPLAYER;
+ end
+ else
+ begin
+ dst.plwnd:=result; // to prevent same player, another instance
+ result:=WAT_RES_OK;
+ end
+ end;
+end;
+
+function CheckFile(var dst:tSongInfo;flags:cardinal;timeout:cardinal):integer;
+var
+ fname:pWideChar;
+ tmp:integer;
+ remote,FileChanged:boolean;
+ f:THANDLE;
+ ftime:int64;
+begin
+ if plyLink^[0].GetName<>nil then
+ fname:=tNameProc(plyLink^[0].GetName)(dst.plwnd,flags)
+ else
+ fname:=nil;
+
+ if (fname=nil) and (dst.plwnd<>0) then
+ begin
+ tmp:=0;
+ if (flags and WAT_OPT_MULTITHREAD)<>0 then tmp:=tmp or gffdMultiThread;
+ if (flags and WAT_OPT_KEEPOLD )<>0 then tmp:=tmp or gffdOld;
+ fname:=GetFileFromWnd(dst.plwnd,KnownFileType,tmp,timeout);
+ end;
+
+ if fname<>nil then
+ begin
+ remote:=StrPosW(fname,'://')<>nil;
+ // file changing time (local/lan only)
+ if not remote then
+ begin
+ f:=Reset(fname);
+
+ if f<>THANDLE(INVALID_HANDLE_VALUE) then
+ begin
+ GetFileTime(f,nil,nil,@ftime);
+ CloseHandle(f);
+ end;
+ end;
+ // same file
+ if (dst.mfile<>nil) and (lstrcmpiw(dst.mfile,fname)=0) then
+ begin
+ if (not remote) and ((flags and WAT_OPT_CHECKTIME)<>0) then
+ FileChanged:=dst.date<>ftime
+ else
+ FileChanged:=false;
+ end
+ else // new filename
+ begin
+ FileChanged:=true;
+ end;
+
+ // if not proper ext (we don't working with it)
+ //!!!! check for remotes
+ if (not remote) and (CheckExt(fname)=WAT_RES_NOTFOUND) then
+ begin
+ mFreeMem(fname);
+ result:=WAT_RES_NOTFOUND;
+ exit;
+ end;
+ if FileChanged {or isContainer(fname)} then
+ begin
+ ClearFileInfo(dst,false);
+ dst.mfile:=fname; //!! must be when format recognized or remote
+ dst.date:=ftime; //!!
+ dst.fsize:=GetFSize(dst.mfile);
+ result:=WAT_RES_NEWFILE;
+ end
+ else
+ begin
+ result:=WAT_RES_OK;
+ mFreeMem(fname);
+ end;
+ end
+ else
+ begin
+ result:=WAT_RES_NOTFOUND;
+ end;
+end;
+
+// Get Info - main procedure
+function GetChangingInfo(var dst:tSongInfo;flags:cardinal):integer;
+begin
+ result:=WAT_RES_OK;
+
+ ClearChangingInfo(dst,false);
+
+ if plyLink^[0].GetInfo<>nil then
+ tInfoProc(plyLink^[0].GetInfo)(dst,flags or WAT_OPT_CHANGES)
+ else if (plyLink^[0].flags and WAT_OPT_WINAMPAPI)<>0 then
+ WinampGetInfo(wparam(@dst),flags or WAT_OPT_CHANGES);
+
+ if (plyLink^[0].flags and WAT_OPT_PLAYERINFO)=0 then
+ if dst.wndtext=NIL then dst.wndtext:=DefGetWndText(dst.plwnd);
+end;
+
+function GetInfo(var dst:tSongInfo;flags:cardinal):integer;
+var
+ oldartist,oldtitle:pWideChar;
+ fname:pWideChar;
+ remote:boolean;
+ lmsnInfo:pMSNInfo;
+begin
+ result:=WAT_RES_OK;
+ remote:=StrPosW(dst.mfile,'://')<>nil;
+
+// if remote or ((plyLink^[0].flags and WAT_OPT_PLAYERINFO)<>0) then
+ oldartist:=dst.artist; oldtitle:=dst.title;
+
+ ClearTrackInfo(dst,false);
+
+ // info from player
+ if plyLink^[0].GetInfo<>nil then
+ tInfoProc(plyLink^[0].GetInfo)(dst,flags and not WAT_OPT_CHANGES)
+ else if (plyLink^[0].flags and WAT_OPT_WINAMPAPI)<>0 then
+ WinampGetInfo(wparam(@dst),flags and not WAT_OPT_CHANGES);
+ // info from file
+ GetFileFormatInfo(dst);
+
+ if (plyLink^[0].flags and WAT_OPT_PLAYERINFO)=0 then
+ with dst do
+ begin
+ if remote then
+ fname:=nil
+ else
+ fname:=mfile;
+
+ lmsnInfo:=GetMSNInfo;
+
+ if lmsnInfo<>nil then
+ begin
+ if artist=NIL then StrDupW(artist,lmsnInfo.msnArtist);
+ if title =NIL then StrDupW(title ,lmsnInfo.msnTitle);
+ if album =NIL then StrDupW(album ,lmsnInfo.msnAlbum);
+ end;
+
+ if artist=NIL then artist:=DefGetArtist(plwnd,fname,wndtext);
+ if title =NIL then title :=DefGetTitle (plwnd,fname,wndtext);
+ end;
+ if remote or ((plyLink^[0].flags and WAT_OPT_PLAYERINFO)<>0) or
+ isContainer(dst.mfile) then
+ begin
+ if (oldartist=oldtitle) or
+ ((oldartist<>nil) and (StrCmpW(dst.artist,oldartist)<>0)) or
+ ((oldtitle <>nil) and (StrCmpW(dst.title ,oldtitle )<>0)) then
+ begin
+ result:=WAT_RES_NEWFILE;
+ end;
+ end;
+end;
+
+procedure ClearPlayers;
+begin
+ if PlyNum>0 then
+ begin
+ repeat
+ dec(PlyNum);
+ with plyLink^[PlyNum] do
+ begin
+ if DeInit<>nil then
+ tDeInitProc(DeInit);
+ FreeMem(Desc);
+ if URL<>nil then
+ FreeMem(URL);
+ if icon<>0 then
+ DestroyIcon(icon);
+ if (flags and WAT_OPT_TEMPLATE)<>0 then
+ begin
+ ClearTemplate(pTmplCell(Check));
+ mFreeMem(Notes);
+ end
+ else if Notes<>nil then
+ FreeMem(Notes);
+ end;
+ until PlyNum=0;
+ FreeMem(plyLink);
+ end;
+end;
+
+end.
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
new file mode 100644
index 0000000000..eca192d5ba
--- /dev/null
+++ b/plugins/Watrack/stat/stat.res
Binary files differ
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
new file mode 100644
index 0000000000..8e9c02fb93
--- /dev/null
+++ b/plugins/Watrack/stat/wat_report.ico
Binary files differ
diff --git a/plugins/Watrack/status/i_hotkey.inc b/plugins/Watrack/status/i_hotkey.inc
new file mode 100644
index 0000000000..3ad23ae656
--- /dev/null
+++ b/plugins/Watrack/status/i_hotkey.inc
@@ -0,0 +1,62 @@
+{main hotkey code}
+function InsertProc(wParam:WPARAM;lParam:LPARAM):int_ptr; cdecl;
+var
+ CurWin:HWND;
+ s:pWideChar;
+ p:PAnsiChar;
+ isUnicode:boolean;
+ i:integer;
+ j:integer;
+ tt:tTemplateType;
+begin
+ result:=0;
+ if DisablePlugin=dsPermanent then
+ exit;
+ if Loword(LastStatus)<>WAT_PLS_NORMAL then
+ exit;
+// i:=CallService(MS_WAT_GETMUSICINFO,0,0);
+ if UseMessages=BST_CHECKED then
+ begin
+ CurWin:=GetFocus;
+ if CurWin<>0 then
+ begin
+// j:=WndToContact(WaitFocusedWndChild(GetForegroundwindow){GetFocus});
+ j:=WndToContact(CurWin);
+ p:=GetContactProtoAcc(j);
+// p:=PAnsiChar(CallService(MS_PROTO_GETCONTACTBASEPROTO,j,0));
+ if DBReadByte(j,p,'ChatRoom',0)=1 then
+ begin
+ isUnicode:=false;
+ tt:=tmpl_chat;
+ end
+ else
+ begin
+ isUnicode:=true;
+ tt:=tmpl_pm;
+ end;
+ if SimpleMode<>BST_UNCHECKED then
+ i:=0
+ else
+ i:=FindProto(p);
+ s:=GetMacros(tt,i);
+ // not empty and not disabled
+ if (s<>nil) and (uint_ptr(s)<>uint_ptr(-1)) then
+ begin
+ if StrScanW(s,'{')<>nil then
+ SendRTF(CurWin,s,isUnicode,UserCP)
+ else
+ begin
+ if isUnicode then
+ SendMessageW(CurWin,EM_REPLACESEL,0,tlparam(s))
+ else
+ begin
+ SendMessageA(CurWin,EM_REPLACESEL,0,tlparam(WideToAnsi(s,p,UserCP)));
+ mFreeMem(p);
+ end;
+ end;
+ mFreeMem(s);
+ end;
+ result:=1;
+ end;
+ end;
+end;
diff --git a/plugins/Watrack/status/i_opt_11.inc b/plugins/Watrack/status/i_opt_11.inc
new file mode 100644
index 0000000000..55279d3156
--- /dev/null
+++ b/plugins/Watrack/status/i_opt_11.inc
@@ -0,0 +1,459 @@
+{Templates}
+const
+ DLGED_INIT = $1000; // dialog init, not activate Apply button
+ DLGED_PROT = $0800; // proto changed
+ DLGED_STAT = $0400; // status changed
+ DLGED_PACK = $0200; // needed string packing
+ DLGED_CHGD = $0100; // something changed
+ DLGED_MSG = $0001; // message template changed
+ DLGED_STTT = $0004; // status template changed
+ DLGED_CHNL = $0008; // channel template changed
+ DLGED_XTTL = $0010; // xstatus title changed
+ DLGED_XTTT = $0020; // xstatus template changed
+ DLGED_TUNE = $0040; // tunes template changed
+ DLGED_BASE = DLGED_MSG +DLGED_STTT+DLGED_CHNL+
+ DLGED_TUNE+DLGED_XTTL+DLGED_XTTT;
+
+const
+ maxShowControls = 7;
+ aListFields:array [0..maxShowControls-1] of integer= (
+ IDC_STATUS_TEXT,
+ IDC_XSTATUS_TITLE, IDC_XSTATUS_TEXT,
+ IDC_LISTENING_TEXT,
+ IDC_STAT_ENABLE,IDC_XSTAT_ENABLE,IDC_TUNES_ENABLE);
+
+ aShowFields: array [0..2,0..maxShowControls-1] of integer = (
+{status} (SW_SHOW, SW_HIDE, SW_HIDE, SW_HIDE, SW_SHOW, SW_HIDE, SW_HIDE),
+{xstatus} (SW_HIDE, SW_SHOW, SW_SHOW, SW_HIDE, SW_HIDE, SW_SHOW, SW_HIDE),
+{tunes} (SW_HIDE, SW_HIDE, SW_HIDE, SW_SHOW, SW_HIDE, SW_HIDE, SW_SHOW));
+
+var
+ CurProto,
+ CurStatus:integer;
+
+procedure RedrawFields(Dialog:hwnd;proto:integer=-1);
+var
+ wnd1,wnd:HWND;
+ p:pWideChar;
+ i:integer;
+begin
+ Changed:=Changed or DLGED_INIT;
+ if proto<0 then
+ proto:=CurProto;
+
+ SetDlgItemTextW(Dialog,IDC_EDIT_MSG,
+ GetTemplateStr(tmpl_pm,proto,CurStatus));
+
+ p:=GetTemplateStr(tmpl_stext,proto,CurStatus);
+
+ wnd:=GetDlgItem(Dialog,IDC_STATUS_TEXT);
+
+ SendMessageW(wnd,WM_SETTEXT,0,lparam(p));
+ if IsTemplateActive(tmpl_stext,proto,CurStatus) then
+ begin
+ EnableWindow(wnd,true);
+ i:=BST_CHECKED;
+ end
+ else
+ begin
+ EnableWindow(wnd,false);
+ i:=BST_UNCHECKED;
+ end;
+ CheckDlgButton(Dialog,IDC_STAT_ENABLE,i);
+
+ if IsXStatusSupported(CurProto) then
+ begin
+ wnd :=GetDlgItem(Dialog,IDC_XSTATUS_TITLE);
+ wnd1:=GetDlgItem(Dialog,IDC_XSTATUS_TEXT);
+ p:=GetTemplateStr(tmpl_xtitle,proto,CurStatus);
+ SendMessageW(wnd ,WM_SETTEXT,0,lparam(p));
+ SendMessageW(wnd1,WM_SETTEXT,0,
+ lparam(GetTemplateStr(tmpl_xtext,proto,CurStatus)));
+
+ if IsTemplateActive(tmpl_xtitle,proto,CurStatus) then
+ begin
+ EnableWindow(wnd ,true);
+ EnableWindow(wnd1,true);
+ i:=BST_CHECKED;
+ end
+ else
+ begin
+ EnableWindow(wnd ,false);
+ EnableWindow(wnd1,false);
+ i:=BST_UNCHECKED;
+ end;
+ CheckDlgButton(Dialog,IDC_XSTAT_ENABLE,i);
+ end;
+
+ if IsTunesSupported(CurProto) then
+ begin
+ p:=GetTemplateStr(tmpl_tunes,proto,CurStatus);
+ wnd:=GetDlgItem(Dialog,IDC_LISTENING_TEXT);
+ SendMessageW(wnd,WM_SETTEXT,0,lparam(p));
+ if IsTemplateActive(tmpl_tunes,proto,CurStatus) then
+ begin
+ EnableWindow(wnd,true);
+ i:=BST_CHECKED;
+ end
+ else
+ begin
+ EnableWindow(wnd,false);
+ i:=BST_UNCHECKED;
+ end;
+ CheckDlgButton(Dialog,IDC_TUNES_ENABLE,i);
+ end;
+
+ if IsChatSupported(CurProto) then
+ SetDlgItemTextW(Dialog,IDC_EDIT_CHANNEL,
+ GetTemplateStr(tmpl_chat,proto,CurStatus));
+
+ Changed:=Changed and not DLGED_INIT;
+end;
+
+procedure SetScreenFull(Dialog:hwnd);
+var
+ show:integer;
+ buf:array [0..127] of AnsiChar;
+ endis:boolean;
+ wnd:HWND;
+begin
+ Changed:=Changed or DLGED_INIT;
+ CurStatus:=0;
+
+ CheckDlgButton(Dialog,IDC_IRC_USER ,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_IRC_CHANNEL,BST_UNCHECKED);
+ ShowWindow(GetDlgItem(Dialog,IDC_EDIT_MSG ),SW_SHOW);
+ ShowWindow(GetDlgItem(Dialog,IDC_EDIT_CHANNEL),SW_HIDE);
+
+ if IsChatSupported(CurProto) then
+ show:=SW_SHOW
+ else
+ show:=SW_HIDE;
+
+ ShowWindow(GetDlgItem(Dialog,IDC_IRC_USER ),show);
+ ShowWindow(GetDlgItem(Dialog,IDC_IRC_CHANNEL),show);
+
+// wnd:=GetDlgItem(Dialog,IDC_PROTOLIST);
+
+//!!!! SendMessage(wnd,CB_SETCURSEL,0,0); //???
+
+// SendMessageA(wnd,LVM_GETITEMTEXTA,);
+// ListView_GetItemTextA(wnd,CurProto,0,@buf,SizeOf(buf));
+
+ StrCopy(buf,GetProtoName(CurProto));
+ StrCat(buf,PS_ICQ_GETCUSTOMSTATUSICON);
+ endis:=ServiceExists(buf)<>0;
+
+ EnableWindow(GetDlgItem(Dialog,IDC_CBEX ),endis);
+ EnableWindow(GetDlgItem(Dialog,IDC_XSTAT_AUDIO),endis);
+ EnableWindow(GetDlgItem(Dialog,IDC_XSTAT_VIDEO),endis);
+ if endis then
+ begin
+ CheckDlgButton(Dialog,IDC_XSTAT_AUDIO,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_XSTAT_VIDEO,BST_UNCHECKED);
+ end;
+
+ wnd:=GetDlgItem(Dialog,IDC_STATUSLIST);
+ FillStatusList(CurProto,wnd,true);
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+ RedrawFields(Dialog);
+end;
+
+procedure SetTemplate(Dialog:hwnd;idc:integer;Tmpl:tTemplateType);
+begin
+ SetTemplateStr (GetDlgText(Dialog,ABS(idc)),Tmpl,CurProto,CurStatus);
+ SetTemplateActive(idc>0 ,Tmpl,CurProto,CurStatus);
+end;
+
+procedure SaveChanges(Dialog:hwnd);
+var
+ i,j:integer;
+begin
+ if (Changed and DLGED_BASE)<>0 then
+ begin
+ if (Changed and DLGED_MSG )<>0 then SetTemplate(Dialog,IDC_EDIT_MSG ,tmpl_pm);
+ if (Changed and DLGED_CHNL)<>0 then SetTemplate(Dialog,IDC_EDIT_CHANNEL,tmpl_chat);
+
+
+ if (Changed and DLGED_STTT)<>0 then
+ begin
+ if IsDlgButtonChecked(Dialog,IDC_STAT_ENABLE)<>BST_UNCHECKED then
+ i:=IDC_STATUS_TEXT
+ else
+ i:=-IDC_STATUS_TEXT;
+ SetTemplate(Dialog,i,tmpl_stext);
+ end;
+
+ if (Changed and DLGED_TUNE)<>0 then
+ begin
+ if IsDlgButtonChecked(Dialog,IDC_TUNES_ENABLE)<>BST_UNCHECKED then
+ i:=IDC_LISTENING_TEXT
+ else
+ i:=-IDC_LISTENING_TEXT;
+ SetTemplate(Dialog,i,tmpl_tunes);
+ end;
+
+ if (Changed and (DLGED_XTTL or DLGED_XTTT))<>0 then
+ begin
+ if IsDlgButtonChecked(Dialog,IDC_XSTAT_ENABLE)<>BST_UNCHECKED then
+ begin
+ i:=IDC_XSTATUS_TITLE;
+ j:=IDC_XSTATUS_TEXT;
+ end
+ else
+ begin
+ i:=-IDC_XSTATUS_TITLE;
+ j:=-IDC_XSTATUS_TEXT;
+ end;
+ if (Changed and DLGED_XTTL)<>0 then SetTemplate(Dialog,i,tmpl_xtitle);
+ if (Changed and DLGED_XTTT)<>0 then SetTemplate(Dialog,j,tmpl_xtext);
+ end;
+
+ Changed:=Changed and (not DLGED_BASE);
+ end;
+end;
+
+function SaveCBExValue(Dialog:HWnd;direct:boolean):cardinal;
+var
+ wnd:HWND;
+ i,j,shift:cardinal;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_CBEX);
+ i:=GetProtoSetting(CurProto,true);
+
+ if (IsDlgButtonChecked(Dialog,IDC_XSTAT_VIDEO)<>BST_UNCHECKED) xor direct then
+ shift:=0
+ else
+ shift:=8;
+
+ j:=SendMessage(wnd,CB_GETCURSEL,0,0);
+ i:=(i and ($FFFF0000 or ($FF shl (8-shift)))) or (j shl shift);
+
+ SetProtoSetting(CurProto,i,true);
+
+ result:=(i shr (8-shift)) and $FF;
+end;
+
+procedure FillCBType(Dialog:hwnd;proto:pAnsiChar=nil);
+var
+ wnd:HWND;
+ j:integer;
+begin
+ wnd:=GetDlgItem(Dialog,IDC_CBSTATYPE);
+ SendMessage(wnd,CB_RESETCONTENT,0,0);
+
+ CB_AddStrDataW(wnd,TranslateW('Status'),0);
+ if IsXStatusSupported(uint_ptr(proto)) then CB_AddStrDataW(wnd,TranslateW('XStatus'),1);
+ if IsTunesSupported (uint_ptr(proto)) then CB_AddStrDataW(wnd,TranslateW('Tunes' ),2);
+
+ SendMessage(wnd,CB_SETCURSEL,0,0);
+
+ for j:=0 to maxShowControls-1 do
+ ShowWindow(GetDlgItem(Dialog,aListFields[j]),aShowFields[0][j]);
+end;
+
+function DlgProcOptions11(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+var
+ Item:LV_ITEMA;
+ buf:array [0..127] of AnsiChar;
+ i,j:integer;
+ wnd:HWND;
+ b:boolean;
+begin
+ result:=0;
+ case hMessage of
+ WM_DESTROY: begin
+ ListView_SetImageList(GetDlgItem(Dialog,IDC_STATUSLIST),0,LVSIL_SMALL);
+ ListView_SetImageList(GetDlgItem(Dialog,IDC_PROTOLIST ),0,LVSIL_SMALL);
+ end;
+
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ Changed:=DLGED_INIT;
+ FillProtoList(GetDlgItem(Dialog,IDC_PROTOLIST),true);
+ CurProto :=0;
+ SetScreenFull(Dialog);
+ FillCBType(Dialog,nil);
+ SendMessage(Dialog,WM_COMMAND,(CBN_SELCHANGE shl 16)+IDC_CBSTATYPE,
+ GetDlgItem(Dialog,IDC_CBSTATYPE));
+ result:=0;
+ Changed:=0;
+ end;
+
+ WM_COMMAND: begin
+ case wParam shr 16 of
+ EN_CHANGE: begin
+ if (Changed and DLGED_INIT)=0 then
+ begin
+ Changed:=Changed or DLGED_CHGD or DLGED_PACK;
+ case loword(wParam) of
+ IDC_EDIT_MSG : Changed:=Changed or DLGED_MSG;
+ IDC_EDIT_CHANNEL : Changed:=Changed or DLGED_CHNL;
+ IDC_STATUS_TEXT : Changed:=Changed or DLGED_STTT;
+ IDC_XSTATUS_TITLE : Changed:=Changed or DLGED_XTTL;
+ IDC_XSTATUS_TEXT : Changed:=Changed or DLGED_XTTT;
+ IDC_LISTENING_TEXT: Changed:=Changed or DLGED_TUNE;
+ end;
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+
+ CBN_SELCHANGE: begin
+ case loword(wParam) of
+ IDC_CBSTATYPE: begin
+ i:=CB_GetData(lParam);
+ for j:=0 to maxShowControls-1 do
+ ShowWindow(GetDlgItem(Dialog,aListFields[j]),aShowFields[i][j]);
+ end;
+
+ IDC_CBEX: begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+ end;
+
+ BN_CLICKED: begin
+ case LoWord(wParam) of
+ IDC_CMD_DEFAULT: begin
+ RedrawFields(Dialog,0);
+ Changed:=Changed or DLGED_CHGD or DLGED_BASE;
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ IDC_CMD_RESET: begin
+ RedrawFields(Dialog);
+ end;
+
+ IDC_STAT_ENABLE, IDC_XSTAT_ENABLE, IDC_TUNES_ENABLE: begin
+ case LoWord(wParam) of
+ IDC_STAT_ENABLE: begin
+ Changed:=Changed or DLGED_STTT;
+ EnableWindow(GetDlgItem(Dialog,IDC_STATUS_TEXT),
+ IsDlgButtonChecked(Dialog,IDC_STAT_ENABLE)<>BST_UNCHECKED);
+ end;
+ IDC_XSTAT_ENABLE: begin
+ b:=IsDlgButtonChecked(Dialog,IDC_XSTAT_ENABLE)<>BST_UNCHECKED;
+ EnableWindow(GetDlgItem(Dialog,IDC_XSTATUS_TITLE),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_XSTATUS_TEXT ),b);
+ Changed:=Changed or DLGED_XTTL;
+ Changed:=Changed or DLGED_XTTT;
+ end;
+ IDC_TUNES_ENABLE: begin
+ Changed:=Changed or DLGED_TUNE;
+ EnableWindow(GetDlgItem(Dialog,IDC_LISTENING_TEXT),
+ IsDlgButtonChecked(Dialog,IDC_TUNES_ENABLE)<>BST_UNCHECKED);
+ end;
+ end;
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ IDC_XSTAT_VIDEO, IDC_XSTAT_AUDIO: begin
+ SendDlgItemMessage(Dialog,IDC_CBEX,CB_SETCURSEL,SaveCBExValue(Dialog,false),0);
+ end;
+ IDC_HELP_COLOR: begin
+ ShowColorHelpDlg(Dialog);
+ exit;
+ end;
+ IDC_HELP_FORMAT: begin
+ MessageBoxW(0,TranslateW(sFormatHelp),TranslateW('Format text Info'),0);
+ exit;
+ end;
+ IDC_HELP_VARIABLES: begin
+ CallService(MS_WAT_MACROHELP,Dialog,0);
+ exit;
+ end;
+ IDC_IRC_USER: begin
+// CheckDlgButton(Dialog,IDC_IRC_USER ,BST_CHECKED);
+// CheckDlgButton(Dialog,IDC_IRC_CHANNEL,BST_UNCHECKED);
+ ShowWindow(GetDlgItem(Dialog,IDC_EDIT_MSG ),SW_SHOW);
+ ShowWindow(GetDlgItem(Dialog,IDC_EDIT_CHANNEL),SW_HIDE);
+ end;
+ IDC_IRC_CHANNEL: begin
+// CheckDlgButton(Dialog,IDC_IRC_USER ,BST_UNCHECKED);
+// CheckDlgButton(Dialog,IDC_IRC_CHANNEL,BST_CHECKED);
+ ShowWindow(GetDlgItem(Dialog,IDC_EDIT_CHANNEL),SW_SHOW);
+ ShowWindow(GetDlgItem(Dialog,IDC_EDIT_MSG ),SW_HIDE);
+ end;
+ else
+ SaveChanges(Dialog); //??
+ end;
+ end;
+ end;
+
+ end;
+
+ WM_HELP: begin
+ case PHELPINFO(lParam).iCtrlId of
+ IDC_EDIT_MSG,IDC_EDIT_CHANNEL,IDC_XSTATUS_TITLE,
+ IDC_STATUS_TEXT,IDC_XSTATUS_TEXT,IDC_LISTENING_TEXT:
+ CallService(MS_WAT_MACROHELP,Dialog,0);
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ if (Changed and DLGED_INIT)<>0 then
+ exit;
+ if integer(PNMLISTVIEW(lParam)^.hdr.code)=LVN_ITEMCHANGED then
+ begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ if ((PNMLISTVIEW(lParam)^.uNewState and LVIS_FOCUSED)<>0) then
+ begin
+ SaveChanges(Dialog);
+
+ if PNMLISTVIEW(lParam)^.hdr.idFrom=IDC_PROTOLIST then
+ begin
+ CheckStatusList(GetDlgItem(Dialog,IDC_STATUSLIST),CurProto);
+ SaveCBExValue(Dialog,true);
+ CurProto:=PNMLISTVIEW(lParam)^.iItem;
+ SetScreenFull(Dialog);
+// ListView_GetItemTextA(PNMLISTVIEW(lParam)^.hdr.hwndFrom,CurProto,0,@buf,SizeOf(buf));
+ StrCopy(buf,GetProtoName(CurProto));
+ wnd:=GetDlgItem(Dialog,IDC_CBEX);
+ FillCBType(Dialog,buf);
+ if AddCBEx(wnd,buf)<>0 then
+ begin
+ i:=GetProtoSetting(CurProto,true);
+ SendMessage(wnd,CB_SETCURSEL,i and $FF,0);
+ end;
+ end
+
+ else //IDC_STATUSLIST
+ begin
+ Item.iItem:=PNMLISTVIEW(lParam)^.iItem;
+ Item.mask:=LVIF_PARAM;
+ SendMessageA(PNMLISTVIEW(lParam)^.hdr.hwndFrom,LVM_GETITEMA,0,tlparam(@Item));
+// ListView_GetItemA(PNMLISTVIEW(lParam)^.hdr.hwndFrom,Item);
+ CurStatus:=GetStatusNum(Item.lParam);
+ RedrawFields(Dialog);
+ end;
+ end
+
+ else if PNMLISTVIEW(lParam)^.uNewState<>0 then
+ begin
+ if PNMLISTVIEW(lParam)^.hdr.idFrom=IDC_PROTOLIST then
+ Changed:=Changed or DLGED_PROT or DLGED_CHGD
+ else
+ Changed:=Changed or DLGED_STAT or DLGED_CHGD;
+ end;
+ end
+
+ else if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ begin
+ if (Changed and DLGED_PROT)<>0 then
+ begin
+ CheckProtoList(GetDlgItem(Dialog,IDC_PROTOLIST));
+ Changed:=Changed and not DLGED_PROT;
+ end;
+ if (Changed and DLGED_STAT)<>0 then
+ begin
+ CheckStatusList(GetDlgItem(Dialog,IDC_STATUSLIST),CurProto);
+ Changed:=Changed and not DLGED_STAT;
+ end;
+ SaveCBExValue(Dialog,true);
+ SaveChanges(Dialog);
+ SaveTemplates;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/status/i_opt_12.inc b/plugins/Watrack/status/i_opt_12.inc
new file mode 100644
index 0000000000..7414ecf9d7
--- /dev/null
+++ b/plugins/Watrack/status/i_opt_12.inc
@@ -0,0 +1,108 @@
+{Templates}
+
+procedure SetScreenLite(Dialog:HWnd);
+var
+ p:pWideChar;
+begin
+ Changed:=Changed or DLGED_INIT;
+
+ p:=GetTemplateStr(tmpl_pm ,0,0);
+ SetDlgItemTextW(Dialog,IDC_EDIT_MSG ,p);
+ p:=GetTemplateStr(tmpl_xtitle,0,0);
+ SetDlgItemTextW(Dialog,IDC_XSTATUS_TITLE,p);
+ p:=GetTemplateStr(tmpl_stext ,0,0);
+ SetDlgItemTextW(Dialog,IDC_STATUS_TEXT ,p);
+ p:=GetTemplateStr(tmpl_chat ,0,0);
+ SetDlgItemTextW(Dialog,IDC_EDIT_CHANNEL ,p);
+
+ Changed:=Changed and not DLGED_INIT;
+end;
+
+procedure SetTemplateLite(Dialog:HWnd;idc:integer;Tmpl:tTemplateType);
+begin
+ SetTemplateStr(GetDlgText(Dialog,idc),Tmpl,0,0);
+end;
+
+procedure SaveChangesLite(Dialog:HWnd);
+begin
+ if (Changed and DLGED_BASE)<>0 then
+ begin
+ if (Changed and DLGED_MSG )<>0 then SetTemplateLite(Dialog,IDC_EDIT_MSG ,tmpl_pm);
+ if (Changed and DLGED_CHNL)<>0 then SetTemplateLite(Dialog,IDC_EDIT_CHANNEL,tmpl_chat);
+ if (Changed and DLGED_XTTL)<>0 then
+ begin
+ SetTemplateLite(Dialog,IDC_XSTATUS_TITLE,tmpl_xtitle);
+ end;
+ if (Changed and DLGED_STTT)<>0 then
+ begin
+ SetTemplateLite(Dialog,IDC_STATUS_TEXT,tmpl_stext);
+ SetTemplateLite(Dialog,IDC_STATUS_TEXT,tmpl_xtext);
+ SetTemplateLite(Dialog,IDC_STATUS_TEXT,tmpl_tunes);
+ end;
+
+ Changed:=Changed and (not DLGED_BASE);
+ SaveTemplates;
+ end;
+end;
+
+function DlgProcOptions12(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lparam; stdcall;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+ SetScreenLite(Dialog);
+ result:=0;
+ Changed:=0;
+ end;
+
+ WM_COMMAND: begin
+ if (Changed and DLGED_INIT)=0 then
+ begin
+ case wParam shr 16 of
+ EN_CHANGE: begin
+ Changed:=Changed or DLGED_CHGD or DLGED_PACK;
+ case loword(wParam) of
+ IDC_EDIT_MSG : Changed:=Changed or DLGED_MSG;
+ IDC_XSTATUS_TITLE : Changed:=Changed or DLGED_XTTL;
+ IDC_STATUS_TEXT : Changed:=Changed or DLGED_STTT;
+ IDC_EDIT_CHANNEL : Changed:=Changed or DLGED_CHNL;
+ end;
+ end;
+ BN_CLICKED: begin
+ case LoWord(wParam) of
+ IDC_CMD_RESET: begin
+ SetScreenLite(Dialog);
+ end;
+ IDC_HELP_COLOR: begin
+ ShowColorHelpDlg(Dialog);
+ exit;
+ end;
+ IDC_HELP_FORMAT: begin
+ MessageBoxW(0,TranslateW(sFormatHelp),TranslateW('Format text Info'),0);
+ exit;
+ end;
+ IDC_HELP_VARIABLES: begin
+ CallService(MS_WAT_MACROHELP,Dialog,0);
+ exit;
+ end;
+ end;
+ end;
+ else
+ exit;
+ end;
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ end;
+
+ WM_HELP: CallService(MS_WAT_MACROHELP,Dialog,0);
+
+ WM_NOTIFY: begin
+ if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ SaveChangesLite(Dialog);
+ end;
+
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/status/i_opt_3.inc b/plugins/Watrack/status/i_opt_3.inc
new file mode 100644
index 0000000000..3defc68b54
--- /dev/null
+++ b/plugins/Watrack/status/i_opt_3.inc
@@ -0,0 +1,106 @@
+{format specific}
+
+function DlgProcOptions3(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall;
+const
+ dlginit:boolean=false;
+var
+ wnd:HWND;
+ b:boolean;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ dlginit:=false;
+ TranslateDialogDefault(Dialog);
+
+ MakeHint(Dialog,IDC_SIMPLEMODE,
+ 'If this option is "ON", one templates will be used with all '+
+ 'protocols, protocol and player (media) statuses. Template option page will be '+
+ 'changed next time.');
+ CheckDlgButton(Dialog,IDC_SIMPLEMODE,SimpleMode);
+ MakeHint(Dialog,IDC_INDEPENDED,
+ 'If this option is "ON", XStatus doesn''t depend of protocol status.');
+ CheckDlgButton(Dialog,IDC_INDEPENDED,XIndepended);
+ MakeHint(Dialog,IDC_USESTATUS,
+ 'If this option is "ON", status text will be replaced by music info.');
+ CheckDlgButton(Dialog,IDC_USESTATUS,UseStatus);
+ MakeHint(Dialog,IDC_USEMSGS,
+ 'If this option is "ON", you can paste music info to your '+
+ 'message window pressing hotkey.');
+ CheckDlgButton(Dialog,IDC_USEMSGS,UseMessages);
+ MakeHint(Dialog,IDC_KEEPSTATUS,
+ 'If this option is "ON", XStatus not changed when player shutdowned.');
+ CheckDlgButton(Dialog,IDC_KEEPSTATUS,KeepStatus);
+ MakeHint(Dialog,IDC_CLEARXSTAT,
+ 'xStatus will cleared before text changing and restored with new text later.');
+ CheckDlgButton(Dialog,IDC_CLEARXSTAT,ClearXStat);
+ MakeHint(Dialog,IDC_EXTSTATUS,
+ 'If this option is "ON", XStatus will be changed to "Music" and '+
+ 'status text will be replaced by music info.');
+ CheckDlgButton(Dialog,IDC_EXTSTATUS ,UseExtStatus);
+ MakeHint(Dialog,IDC_LISTENINGTO,
+ 'If this option is "ON", "Listening To" protocol property will be filled '+
+ 'by music info.');
+ CheckDlgButton(Dialog,IDC_LISTENINGTO,UseListeningTo);
+
+ wnd:=GetDlgItem(Dialog,IDC_SETXSTATUS);
+// SendMessage(wnd,CB_RESETCONTENT,0,0);
+ CB_AddStrDataW(wnd,TranslateW('any XStatus is set' ),0,0);
+ CB_AddStrDataW(wnd,TranslateW('''Music'' status is set' ),1,1);
+ CB_AddStrDataW(wnd,TranslateW('XStatus is empty or ''Music'''),2,2);
+ CB_SelectData(wnd,XStatusSet);
+
+ SendMessage(Dialog,WM_COMMAND,(BN_CLICKED shl 16)+IDC_EXTSTATUS,
+ GetDlgItem(Dialog,IDC_EXTSTATUS));
+
+ dlginit:=true;
+ result:=0;
+ end;
+
+ WM_COMMAND: begin
+ if ((wParam shr 16)=BN_CLICKED) and (LoWord(wParam)=IDC_EXTSTATUS) then
+ begin
+ b:=IsDlgButtonchecked(Dialog,IDC_EXTSTATUS)<>BST_UNCHECKED;
+ EnableWindow(GetDlgItem(Dialog,IDC_INDEPENDED),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_CLEARXSTAT),b);
+// EnableWindow(GetDlgItem(Dialog,IDC_OLDXSTATUS),b);
+// EnableWindow(GetDlgItem(Dialog,IDC_ONLYMUSIC ),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_SETXSTATUS),b);
+ EnableWindow(GetDlgItem(Dialog,IDC_KEEPSTATUS),b);
+ end;
+
+ case wParam shr 16 of
+ CBN_SELCHANGE,
+ EN_CHANGE,
+ BN_CLICKED: SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+ result:=1;
+ end;
+
+ WM_NOTIFY: begin
+ if dlginit then
+ begin
+ case integer(PNMHdr(lParam)^.code) of
+ LVN_ITEMCHANGED: begin
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ end;
+
+ PSN_APPLY: begin
+ SimpleMode :=IsDlgButtonChecked(Dialog,IDC_SIMPLEMODE);
+ XIndepended :=IsDlgButtonChecked(Dialog,IDC_INDEPENDED);
+ UseMessages :=IsDlgButtonChecked(Dialog,IDC_USEMSGS);
+ UseStatus :=IsDlgButtonChecked(Dialog,IDC_USESTATUS);
+ UseExtStatus :=IsDlgButtonChecked(Dialog,IDC_EXTSTATUS);
+ KeepStatus :=IsDlgButtonChecked(Dialog,IDC_KEEPSTATUS);
+ ClearXStat :=IsDlgButtonChecked(Dialog,IDC_CLEARXSTAT);
+ UseListeningTo:=IsDlgButtonChecked(Dialog,IDC_LISTENINGTO);
+ XStatusSet :=CB_GetData(GetDlgItem(Dialog,IDC_SETXSTATUS));
+ SaveOpt;
+ end;
+ end;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/status/i_opt_status.inc b/plugins/Watrack/status/i_opt_status.inc
new file mode 100644
index 0000000000..09e0c208ce
--- /dev/null
+++ b/plugins/Watrack/status/i_opt_status.inc
@@ -0,0 +1,49 @@
+{}
+const
+ opt_ModStatus :PAnsiChar = 'module/statuses';
+
+ opt_UseStatus :PAnsiChar = 'usestatus';
+ opt_UseExtStat :PAnsiChar = 'useextstat';
+ opt_UseMsgs :PAnsiChar = 'usemsgs';
+ opt_XStatusSet :PAnsiChar = 'xstatusset';
+ opt_KeepStatus :PAnsiChar = 'keepstatus';
+ opt_Independed :PAnsiChar = 'independed';
+ opt_ClearXStat :PAnsiChar = 'clearxstat';
+ opt_SimplMode :PAnsiChar = 'simplemode';
+ opt_ListeningTo:PAnsiChar = 'listeningto';
+
+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 LoadOpt;
+begin
+ SimpleMode :=DBReadByte(0,PluginShort,opt_SimplMode ,BST_CHECKED);
+ UseStatus :=DBReadByte(0,PluginShort,opt_UseStatus ,BST_CHECKED);
+ UseExtStatus :=DBReadByte(0,PluginShort,opt_UseExtStat ,BST_CHECKED);
+ UseMessages :=DBReadByte(0,PluginShort,opt_UseMsgs ,BST_CHECKED);
+ KeepStatus :=DBReadByte(0,PluginShort,opt_KeepStatus ,BST_UNCHECKED);
+ XIndepended :=DBReadByte(0,PluginShort,opt_Independed ,BST_CHECKED);
+ ClearXStat :=DBReadByte(0,PluginShort,opt_ClearXStat ,BST_UNCHECKED);
+ UseListeningTo:=DBReadByte(0,PluginShort,opt_ListeningTo,BST_UNCHECKED);
+ XStatusSet :=DBReadByte(0,PluginShort,opt_XStatusSet ,1);
+end;
+
+procedure SaveOpt;
+begin
+ DBWriteByte(0,PluginShort,opt_SimplMode ,SimpleMode);
+ DBWriteByte(0,PluginShort,opt_UseStatus ,UseStatus);
+ DBWriteByte(0,PluginShort,opt_UseExtStat ,UseExtStatus);
+ DBWriteByte(0,PluginShort,opt_UseMsgs ,UseMessages);
+ DBWriteByte(0,PluginShort,opt_KeepStatus ,KeepStatus);
+ DBWriteByte(0,PluginShort,opt_Independed ,XIndepended);
+ DBWriteByte(0,PluginShort,opt_ClearXStat ,ClearXStat);
+ DBWriteByte(0,PluginShort,opt_ListeningTo,UseListeningTo);
+ DBWriteByte(0,PluginShort,opt_XStatusSet ,XStatusSet);
+end;
diff --git a/plugins/Watrack/status/i_opt_tmpl.inc b/plugins/Watrack/status/i_opt_tmpl.inc
new file mode 100644
index 0000000000..9f5ea87907
--- /dev/null
+++ b/plugins/Watrack/status/i_opt_tmpl.inc
@@ -0,0 +1,244 @@
+{Save/load options}
+
+const
+ opt_numstr:PAnsiChar = 'template/numstr';
+const
+ ppref = 'proto/';
+ spref = 'strings/';
+
+procedure SaveTemplates;
+var
+ i,lProtoStatus:cardinal;
+ lTmplType:tTemplateType;
+ p:PAnsiChar;
+ buf:PAnsiChar;
+ NumProto:cardinal;
+ tmpl:pStrTemplate;
+ tmp:SmallInt;
+ setting:array [0..63] of AnsiChar;
+ pset:PAnsiChar;
+begin
+ DBWriteWord(0,PluginShort,opt_numstr,NumString);
+ StrCopy(setting,spref);
+ pset:=StrEnd(setting);
+ for i:=1 to NumString do
+ begin
+ IntToStr(pset,i);
+ DBWriteUnicode(0,PluginShort,setting,strings^[i].text);
+ end;
+
+ NumProto:=GetNumProto;
+ mGetMem(buf,16384);
+ for i:=0 to NumProto do
+ begin
+ pset:=StrCopyE(setting,ppref);
+ pset:=StrCopyE(pset,GetProtoName(i));
+
+ StrCopy(pset,'/XStatus');
+ DBWriteWord(0,PluginShort,setting,GetProtoSetting(i,true));
+ inc(pset);
+ if i<>0 then
+ begin
+ StrCopy(pset,'enabled');
+ DBWriteWord(0,PluginShort,setting,GetProtoSetting(i));
+ end;
+
+ p:=buf;
+ tmpl:=@StrTemplates^[i];
+ pset[3]:=#0;
+ for lProtoStatus:=0 to NumStatus-1 do
+ for lTmplType:=tmpl_first to tmpl_last do
+ begin
+ tmp:=tmpl^[lProtoStatus,lTmplType];
+ if tmp=0 then
+ begin
+ if p<>buf then
+ begin
+ p^:=',';
+ inc(p);
+ end;
+ p^:='0'; inc(p); // for compatibility
+ p^:=AnsiChar(lProtoStatus +ORD('0')); inc(p);
+ p^:=AnsiChar(ORD(lTmplType)+ORD('0')); inc(p);
+ end
+ else if (tmp<>0) and (tmp<>smallint(dubtmpl)) then
+ begin
+ pset[0]:='0'; // for compatibility
+ pset[1]:=AnsiChar(lProtoStatus +ORD('0'));
+ pset[2]:=AnsiChar(ORD(lTmplType)+ORD('0'));
+ DBWriteWord(0,PluginShort,setting,word(tmp));
+ end;
+ end;
+ if p<>buf then
+ begin
+ p^:=#0;
+ StrCopy(pset,'empty');
+ DBWriteString(0,PluginShort,setting,buf);
+ end;
+ end;
+ mFreeMem(buf);
+end;
+
+procedure InitDefault;
+var
+ tmpl:pStrTemplate;
+begin
+ NumString:=8;
+ mGetMem (strings ,SizeOf(tMyString)*NumString);
+ FillChar(strings^,SizeOf(tMyString)*NumString,0);
+
+ if isVarsInstalled then
+ begin
+ StrDupW(strings^[1].text,defAltTemplate);
+ StrDupW(strings^[4].text,defAltChannelText);
+ end
+ else
+ begin
+ StrDupW(strings^[1].text,defTemplate);
+ StrDupW(strings^[4].text,defChannelText);
+ end;
+ StrDupW(strings^[2].text,defStatusTitle);
+ StrDupW(strings^[3].text,defStatusText);
+
+ tmpl:=@StrTemplates^[DefaultTemplate];
+ if tmpl^[0,tmpl_first]=smallint(dubtmpl) then
+ begin
+ // music played
+ tmpl^[0,tmpl_pm ]:=1;
+ tmpl^[0,tmpl_chat ]:=4;
+ tmpl^[0,tmpl_xtitle]:=2;
+ tmpl^[0,tmpl_stext ]:=3;
+ tmpl^[0,tmpl_xtext ]:=3;
+ end;
+end;
+
+function EnumSettingsProc(const szSetting:PAnsiChar;lParam:LPARAM):int; cdecl;
+var
+ p:^PAnsiChar;
+ i:cardinal;
+ pp:AnsiChar;
+begin
+ if StrCmp(ppref,szSetting,Length(ppref))=0 then
+ begin
+ i:=StrLen(szSetting)+1;
+ pp:=szSetting[i-2];
+ if (pp>='0') and (pp<='9') then
+ begin
+ p:=pointer(lParam);
+ move(szSetting^,p^^,i);
+ inc(p^,i);
+ end;
+ end;
+ result:=0;
+end;
+
+function EnumTemplates:PAnsiChar;
+var
+ ces:TDBCONTACTENUMSETTINGS;
+ p:PAnsiChar;
+begin
+ mGetMem(result,16384);
+ result^:=#0;
+ p:=result;
+ ces.pfnEnumProc:=@EnumSettingsProc;
+ ces.lParam :=lparam(@p);
+ ces.szModule :=PluginShort;
+ ces.ofsSettings:=0;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS,0,lparam(@ces));
+end;
+
+procedure LoadTemplates;
+var
+ buf:PAnsiChar;
+ lProtoStatus,i,j:cardinal;
+ lTmplType:tTemplateType;
+ p:PAnsiChar;
+ pc:PAnsiChar;
+ NumProto:cardinal;
+ tmpl:pStrTemplate;
+ setting:array [0..63] of AnsiChar;
+ pset:PAnsiChar;
+begin
+ NumString:=DBReadWord(0,PluginShort,opt_numstr,0);
+ if NumString>0 then
+ begin
+ mGetMem (strings ,SizeOf(tMyString)*NumString);
+ FillChar(strings^,SizeOf(tMyString)*NumString,0);
+ StrCopy(setting,spref);
+ pset:=StrEnd(setting);
+ for i:=1 to NumString do
+ begin
+ IntToStr(pset,i);
+ strings^[i].text:=DBReadUnicode(0,PluginShort,setting,nil);
+ end;
+
+ NumProto:=GetNumProto;
+ buf:=EnumTemplates;
+ for i:=0 to NumProto do
+ begin
+ pset:=StrCopyE(setting,ppref);
+ pset:=StrCopyE(pset,GetProtoName(i));
+
+ StrCopy(pset,'/XStatus');
+ j:=DBReadWord(0,PluginShort,setting,$080B);
+{!!
+ if j=0 then
+ j:=DefaultXStatus;
+}
+ SetProtoSetting(i,j,true);
+
+ inc(pset);
+ if i<>0 then
+ begin
+ StrCopy(pset,'enabled');
+ SetProtoSetting(i,DBReadWord(0,PluginShort,setting,psf_all));
+ end;
+
+ tmpl:=@StrTemplates^[i];
+ StrCopy(pset,'empty');
+ pc:=DBReadString(0,PluginShort,setting,nil);
+ if pc<>nil then
+ begin
+ p:=pc;
+ if (p^>='0') and (p^<='9') then
+ while p^<>#0 do
+ begin
+ lProtoStatus := ORD(p[1])-ORD('0');
+ lTmplType :=tTemplateType(ORD(p[2])-ORD('0'));
+ tmpl^[lProtoStatus,lTmplType]:=0;
+ inc(p,3);
+ if p^=',' then
+ inc(p);
+ end;
+ mFreeMem(pc);
+ end;
+
+ pc:=buf;
+ pset^:=#0;
+ j:=StrLen(setting);
+ pset[3]:=#0;
+ while pc^<>#0 do
+ begin
+ if StrCmp(pc,setting,j)=0 then // only proper proto
+ begin
+ pc:=StrEnd(pc);
+ lProtoStatus := ORD((pc-2)^)-ORD('0');
+ lTmplType :=tTemplateType(ORD((pc-1)^)-ORD('0'));
+
+ pset[0]:='0';
+ pset[1]:=AnsiChar(lProtoStatus +ORD('0'));
+ pset[2]:=AnsiChar(ORD(lTmplType)+ORD('0'));
+
+ tmpl^[lProtoStatus,lTmplType]:=
+ DBReadWord(0,PluginShort,setting,dubtmpl);
+ end
+ else
+ pc:=StrEnd(pc);
+ inc(pc);
+ end;
+ end;
+ mFreeMem(buf);
+ end
+ else
+ InitDefault;
+end;
diff --git a/plugins/Watrack/status/i_st_rc.inc b/plugins/Watrack/status/i_st_rc.inc
new file mode 100644
index 0000000000..c17768c2e7
--- /dev/null
+++ b/plugins/Watrack/status/i_st_rc.inc
@@ -0,0 +1,45 @@
+{DLG 1 - common}
+const
+ IDC_USEMSGS = 2025;
+ IDC_HOTKEYGLOB = 2026;
+ IDC_STAT_HOTKEY = 2027;
+ IDC_USESTATUS = 2028;
+ IDC_EXTSTATUS = 2029;
+// IDC_ONLYMUSIC = 2030;
+ IDC_KEEPSTATUS = 2031;
+ IDC_SIMPLEMODE = 2032;
+// IDC_NOTES = 2033;
+ IDC_INDEPENDED = 2034;
+// IDC_OLDXSTATUS = 2035;
+ IDC_CLEARXSTAT = 2036;
+ IDC_LISTENINGTO = 2037;
+
+ IDC_SETXSTATUS = 2030;
+
+{DLG 2 - templates}
+const
+ IDC_HELP_FORMAT = 1025;
+ IDC_HELP_COLOR = 1027;
+ IDC_HELP_VARIABLES = 1028;
+ {special}
+ IDC_EDIT_MSG = 2032;
+ IDC_STATUS_TEXT = 2034;
+ IDC_EDIT_CHANNEL = 2035;
+ IDC_XSTATUS_TITLE = 2036;
+ IDC_XSTATUS_TEXT = 2037;
+ IDC_LISTENING_TEXT = 2038;
+ IDC_STAT_ENABLE = 2039;
+ IDC_CBSTATYPE = 2040;
+ IDC_XSTAT_ENABLE = 2041;
+ IDC_TUNES_ENABLE = 2042;
+
+ IDC_PROTOLIST = 1037;
+ IDC_STATUSLIST = 1038;
+ IDC_IRC_CHANNEL = 1041;
+ IDC_IRC_USER = 1042;
+ IDC_CMD_RESET = 1044;
+ IDC_CMD_DEFAULT = 1045;
+
+ IDC_CBEX = 1046;
+ IDC_XSTAT_VIDEO = 1047;
+ IDC_XSTAT_AUDIO = 1048;
diff --git a/plugins/Watrack/status/i_st_vars.inc b/plugins/Watrack/status/i_st_vars.inc
new file mode 100644
index 0000000000..e1696c3621
--- /dev/null
+++ b/plugins/Watrack/status/i_st_vars.inc
@@ -0,0 +1,26 @@
+{}
+const
+{
+ OldStatusText:array [0..15] of pWideChar =
+ (nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil);
+}
+ OldXStatus:array [0..31] of byte =
+ (255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255);
+var
+ UseListeningTo:cardinal;
+ SimpleMode :cardinal;
+ UseStatus :cardinal;
+ UseExtStatus :cardinal;
+ UseMessages :cardinal;
+ KeepStatus :cardinal;
+ XIndepended :cardinal;
+ XStatusSet :cardinal;
+ ClearXStat :cardinal;
+ hINS :THANDLE;
+// hLTo :THANDLE;
+ plStatusHook :THANDLE;
+
+const
+ Changed:cardinal=0;
+ LastStatus:integer=WAT_PLS_NOTFOUND;
diff --git a/plugins/Watrack/status/i_status.inc b/plugins/Watrack/status/i_status.inc
new file mode 100644
index 0000000000..a7e3d2e5ef
--- /dev/null
+++ b/plugins/Watrack/status/i_status.inc
@@ -0,0 +1,223 @@
+{Status and XStatus processing}
+
+// XStatus
+const
+ xsnum = 31;
+
+function ListenProc(wParam:WPARAM;lParam:LPARAM):int_ptr; cdecl;
+begin
+ // ignoring incoming ListeningTo info, uses internal
+ if PLISTENINGTOINFO(lParam).cbSize=SizeOf(TLISTENINGTOINFO) then
+ begin
+ result:=int_ptr(GetMacros(tmpl_tunes,0)); // need real proto number here
+ if result=-1 then result:=0;
+ end
+ else
+ begin
+ result:=CallService(MS_WAT_REPLACETEXT,0,wParam);
+ end;
+end;
+
+function IsOurStatus(protomask,status:dword):boolean;
+var
+ mask:dword;
+begin
+{ if status=ID_STATUS_OFFLINE then mask:=M_STAT_OFFLINE
+ else }
+ if status=ID_STATUS_ONLINE then mask:=psf_online
+ else if status=ID_STATUS_INVISIBLE then mask:=psf_invisible
+ else if status=ID_STATUS_AWAY then mask:=psf_shortaway
+ else if status=ID_STATUS_NA then mask:=psf_longaway
+ else if status=ID_STATUS_DND then mask:=psf_heavydnd
+ else if status=ID_STATUS_OCCUPIED then mask:=psf_lightdnd
+ else if status=ID_STATUS_FREECHAT then mask:=psf_freechat
+ else if status=ID_STATUS_ONTHEPHONE then mask:=psf_onthephone
+ else if status=ID_STATUS_OUTTOLUNCH then mask:=psf_outtolunch
+ else mask:=0;
+ result:=(protomask and mask)<>0;
+end;
+
+function NewPlStatus(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ si:pSongInfo;
+ i,j:integer;
+ xstat:integer;
+ txt,title:pWideChar;
+ proto,ls:PAnsiChar;
+ mask,status:dword;
+ todo,isvideo:bool;
+ oldstatus:integer;
+ staudio,stvideo:integer;
+ lti:TLISTENINGTOINFO;
+ buf,buf1:array [0..31] of WideChar;
+ doClear:boolean;
+begin
+ result:=0;
+ si:=pSongInfo(lParam);
+
+ case wParam of
+ WAT_EVENT_NEWTRACK: begin
+ isvideo:=pSongInfo(lParam)^.width<>0;
+ doClear:=false;
+ end;
+
+ WAT_EVENT_PLAYERSTATUS: begin
+ LastStatus:=lParam;
+ if (loword(lParam)=WAT_PLS_NORMAL) then
+ exit;
+ doClear:=true;
+ end;
+ else
+ exit; // not accept template changes
+ end;
+
+ i:=GetNumProto;
+ for j:=1 to i do
+ begin
+ proto:=GetProtoName(j);
+ mask:=GetProtoSetting(j);
+
+ if (SimpleMode<>BST_UNCHECKED) or ((mask and psf_enabled)<>0) then
+ begin
+
+ if (UseStatus<>BST_UNCHECKED) or (UseExtStatus<>BST_UNCHECKED) then
+ begin
+ status:=CallProtoService(proto,PS_GETSTATUS,0,0);
+ todo :=(SimpleMode<>BST_UNCHECKED) or IsOurStatus(mask,status);
+ end
+ else
+ begin
+ status:=ID_STATUS_ONLINE;
+ todo :=true;
+ end;
+
+ if (UseListeningTo<>BST_UNCHECKED) and
+ IsTunesSupported(j) then
+// (ProtoServiceExists(proto,PS_SET_LISTENINGTO)<>0) then
+ begin
+ if doClear then
+ CallProtoService(proto,PS_SET_LISTENINGTO,0,0)
+ else if (wParam=WAT_EVENT_NEWTRACK) then
+ begin
+ lti.cbSize :=SizeOf(lti);
+ if si.width<>0 then
+ lti.szType.W:='Video'
+ else
+ lti.szType.W:='Music';
+ lti.szArtist.W:=si.artist;
+ lti.szAlbum .W:=si.album;
+ lti.szTitle .W:=si.title;
+ lti.szTrack .W:=IntToStr(buf1,si.track);
+ lti.szYear .W:=si.year;
+ lti.szGenre .W:=si.genre;
+ lti.szLength.W:=IntToStr(buf,si.total);
+ lti.szPlayer.W:=si.player;
+ lti.dwFlags :=LTI_UNICODE;
+
+ CallProtoService(proto,PS_SET_LISTENINGTO,0,tlparam(@lti));
+ end;
+ end;
+
+ if UseStatus<>BST_UNCHECKED then
+ if todo then
+ begin
+ if SimpleMode<>BST_UNCHECKED then
+ txt:=GetMacros(tmpl_stext,0)
+ else
+ txt:=GetMacros(tmpl_stext,j);
+ if uint_ptr(txt)<>uint_ptr(-1) then
+ begin
+ if (txt=nil) or (txt^=#0) then
+ ls:=nil
+ else
+ WideToAnsi(txt,ls,UserCP);
+ SetStatus(proto,-status,ls);
+ mFreeMem(ls);
+ mFreeMem(txt);
+ end;
+ end;
+
+ if UseExtStatus<>BST_UNCHECKED then
+ begin
+ if todo or (XIndepended<>BST_UNCHECKED) then
+ begin
+ if IsXStatusSupported(j) then
+ begin
+ if doClear then // player status changed to no music/no player
+ begin
+
+ if KeepStatus=BST_UNCHECKED then
+ begin
+ // just restoring savedstatus if was. no text changing
+ if OldXStatus[j]<>255 then
+ begin
+ oldstatus:=OldXStatus[j];
+ OldXStatus[j]:=255;
+ SetXStatus(proto,oldstatus,pWideChar(-1),pWideChar(-1));
+ end;
+ end;
+
+ end
+ else
+ begin
+ if SimpleMode<>BST_UNCHECKED then
+ txt:=GetMacros(tmpl_xtext,0)
+ else
+ txt:=GetMacros(tmpl_xtext,j);
+ if uint_ptr(txt)<>uint_ptr(-1) then // status template presents
+ begin
+ // XStatus for audio/video
+ if SimpleMode<>BST_UNCHECKED then
+ begin
+ stvideo := 8;
+ staudio := 11;
+ end
+ else
+ begin
+ mask:=GetProtoSetting(j,true);
+ staudio:=mask and $FF;
+ stvideo:=(mask shr 8) and $FF;
+ end;
+ // Check, what we able to do something
+ oldstatus:=GetXStatus(proto,nil,nil);
+ if XStatusSet<>0 then // no matter which xstatus
+ begin
+ if not ((oldstatus=staudio) or (oldstatus=stvideo) or // music
+ ((oldstatus=0) and (XStatusSet=2))) then // empty
+ begin
+ mFreeMem(txt);
+ continue; //!! do nothing!
+ end;
+ end;
+ if isvideo then
+ xstat:=stvideo
+ else
+ xstat:=staudio;
+
+ if xstat=0 then // not choosed, keep old (current)
+ xstat:=oldstatus
+ else
+ begin
+ if OldXStatus[j]=255 then
+ OldXStatus[j]:=oldstatus;
+ end;
+
+ if ClearXStat<>BST_UNCHECKED then
+ SetXStatus(proto,0);
+
+ if SimpleMode<>BST_UNCHECKED then
+ title:=GetMacros(tmpl_xtitle,0)
+ else
+ title:=GetMacros(tmpl_xtitle,j);
+ SetXStatus(proto,xstat,txt,title);
+ mFreeMem(title);
+ mFreeMem(txt);
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ end;
+ end;
+end;
diff --git a/plugins/Watrack/status/status.pas b/plugins/Watrack/status/status.pas
new file mode 100644
index 0000000000..b5db16bb1c
--- /dev/null
+++ b/plugins/Watrack/status/status.pas
@@ -0,0 +1,142 @@
+{Statistic}
+unit Status;
+{$include compilers.inc}
+interface
+{$Resource status.res}
+implementation
+
+uses
+ windows,messages,commctrl,
+ common,m_api,mirutils,protocols,dbsettings,wrapper,
+ global,wat_api,hlpdlg,CBEx,myRTF,Tmpl;
+
+const
+ HKN_INSERT:PansiChar = 'WAT_Insert';
+
+procedure reghotkey;
+var
+ hkrec:HOTKEYDESC;
+begin
+// if DisablePlugin=dsPermanent then
+// exit;
+ FillChar(hkrec,SizeOf(hkrec),0);
+ with hkrec do
+ begin
+ cbSize :=HOTKEYDESC_SIZE_V1;
+ pszName :=HKN_INSERT;
+ pszDescription.a:='Global WATrack hotkey';
+ pszSection.a :=PluginName;
+ pszService :=MS_WAT_INSERT;
+ DefHotKey :=((HOTKEYF_ALT or HOTKEYF_CONTROL) shl 8) or VK_F5;
+// lParam :=0;
+ end;
+ CallService(MS_HOTKEY_REGISTER,0,lparam(@hkrec));
+end;
+
+{$include i_st_vars.inc}
+{$include i_st_rc.inc}
+{$include i_opt_status.inc}
+{$include i_hotkey.inc}
+{$include i_status.inc}
+{$include i_opt_3.inc}
+{$include i_opt_11.inc}
+{$include i_opt_12.inc}
+
+// ------------ base interface functions -------------
+
+var
+ mStatus:twModule;
+
+function InitProc(aGetStatus:boolean=false):integer;
+begin
+ if aGetStatus then
+ begin
+ if GetModStatus=0 then
+ begin
+ result:=0;
+ exit;
+ end;
+ end
+ else
+ SetModStatus(1);
+ result:=1;
+
+ LoadOpt;
+ CreateProtoList;
+ CreateTemplates;
+ hINS:=CreateServiceFunction(MS_WAT_INSERT,@InsertProc);
+ reghotkey;
+ plStatusHook:=HookEvent(ME_WAT_NEWSTATUS,@NewPlStatus);
+
+// mStatus.ModuleStat:=1;
+
+// if ServiceExists(MS_LISTENINGTO_GETPARSEDTEXT)<>0 then
+// hLTo:=CreateServiceFunction(MS_LISTENINGTO_GETPARSEDTEXT,@ListenProc);
+end;
+
+procedure DeInitProc(aSetDisable:boolean);
+var
+ j:integer;
+begin
+ if aSetDisable then
+ SetModStatus(0);
+
+ for j:=1 to GetNumProto do
+ begin
+ if (SimpleMode<>BST_UNCHECKED) or ((GetProtoSetting(j) and psf_enabled)<>0) then
+ CallProtoService(GetProtoName(j),PS_SET_LISTENINGTO,0,0);
+ end;
+// DestroyServiceFunction(hLTo);
+ DestroyServiceFunction(hINS);
+ UnhookEvent(plStatusHook);
+ FreeProtoList;
+ FreeTemplates;
+
+// mStatus.ModuleStat:=0;
+end;
+
+function AddOptionsPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+const
+ count:integer=2;
+begin
+ if count=0 then
+ count:=2;
+ case count of
+ 2: begin
+ tmpl:='COMMON';
+ proc:=@DlgProcOptions3;
+ name:='Status (common)';
+ end;
+ 1: begin
+ if SimpleMode=BST_UNCHECKED then
+ begin
+ tmpl:='TEMPLATE11';
+ proc:=@DlgProcOptions11;
+ end
+ else
+ begin
+ tmpl:='TEMPLATE12';
+ proc:=@DlgProcOptions12;
+ end;
+ name:='Status (templates)';
+ end
+ end;
+
+ dec(count);
+ result:=count;
+end;
+
+procedure Init;
+begin
+ mStatus.Next :=ModuleLink;
+ mStatus.Init :=@InitProc;
+ mStatus.DeInit :=@DeInitProc;
+ mStatus.AddOption :=@AddOptionsPage;
+ mStatus.ModuleName:='Statuses';
+// mStatus.ModuleStat:=0;
+ ModuleLink :=@mStatus;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Watrack/status/status.rc b/plugins/Watrack/status/status.rc
new file mode 100644
index 0000000000..9a1c78c476
--- /dev/null
+++ b/plugins/Watrack/status/status.rc
@@ -0,0 +1,88 @@
+#include "i_st_rc.inc"
+
+LANGUAGE 0,0
+
+COMMON 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
+{
+ GROUPBOX "Options", -1, 2, 2, 188, 218, WS_TABSTOP
+ AUTOCHECKBOX "Simple Template mode", IDC_SIMPLEMODE , 6, 12, 182, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+
+ AUTOCHECKBOX "Insert in messages" , IDC_USEMSGS , 6, 34, 182, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+ AUTOCHECKBOX "Use status messages" , IDC_USESTATUS , 6, 50, 182, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+ AUTOCHECKBOX "Use listening info" , IDC_LISTENINGTO, 6, 66, 182, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+
+ AUTOCHECKBOX "Use XStatus" , IDC_EXTSTATUS , 6, 86, 182, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+ AUTOCHECKBOX "Independed XStatus" , IDC_INDEPENDED, 14, 102, 174, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+ AUTOCHECKBOX "Clear xStatus before set new one" , IDC_CLEARXSTAT, 14, 118, 174, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+ AUTOCHECKBOX "Keep 'Music' XStatus" , IDC_KEEPSTATUS, 14, 134, 174, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+// AUTOCHECKBOX "Use existing XStatus" , IDC_OLDXSTATUS, 14, 134, 174, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+// AUTOCHECKBOX "Only if 'Music' status was set", IDC_ONLYMUSIC , 14, 150, 174, 14, BS_VCENTER | BS_MULTILINE// | BS_NOTIFY
+ LTEXT "Set XStatus when...", -1, 14, 150, 174, 14
+ COMBOBOX IDC_SETXSTATUS, 14, 166, 174, 96, CBS_DROPDOWNLIST | WS_VSCROLL
+}
+
+TEMPLATE11 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
+{
+ PUSHBUTTON "Color", IDC_HELP_COLOR , 184, 1, 26, 12
+ PUSHBUTTON "Format", IDC_HELP_FORMAT , 213, 1, 32, 12
+ PUSHBUTTON "Variables", IDC_HELP_VARIABLES, 248, 1, 52, 12
+
+ CTEXT "Protocols", -1, 6, 2, 80, 10
+ CONTROL "", IDC_PROTOLIST, "SysListView32", WS_BORDER | WS_TABSTOP | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT, 6, 12, 80, 92, WS_EX_CONTROLPARENT
+ CTEXT "Statuses", -1, 90, 2, 92, 10
+ CONTROL "", IDC_STATUSLIST, "SysListView32", WS_BORDER | WS_TABSTOP | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT, 90, 12, 92, 92, WS_EX_CONTROLPARENT
+
+ AUTORADIOBUTTON "User message", IDC_IRC_USER , 196, 51, 102, 12, NOT WS_TABSTOP | WS_GROUP
+ AUTORADIOBUTTON "Channel message", IDC_IRC_CHANNEL, 196, 63, 102, 12, NOT WS_TABSTOP
+
+ PUSHBUTTON "Reset", IDC_CMD_RESET , 184, 103, 56, 12
+ PUSHBUTTON "Default", IDC_CMD_DEFAULT, 242, 103, 56, 12
+
+ LTEXT "Template", -1, 16, 106, 166, 10, SS_CENTERIMAGE
+ EDITTEXT IDC_EDIT_MSG , 6, 116, 290, 44, ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ EDITTEXT IDC_EDIT_CHANNEL, 6, 116, 290, 44, ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+
+ AUTOCHECKBOX "Enable Status message" , IDC_STAT_ENABLE , 6, 161, 174, 12, BS_VCENTER | BS_MULTILINE
+ AUTOCHECKBOX "Enable XStatus message", IDC_XSTAT_ENABLE, 6, 161, 174, 12, BS_VCENTER | BS_MULTILINE
+ AUTOCHECKBOX "Enable Tunes message" , IDC_TUNES_ENABLE, 6, 161, 174, 12, BS_VCENTER | BS_MULTILINE
+ COMBOBOX IDC_CBSTATYPE,196,161,100,56,CBS_DROPDOWNLIST | WS_VSCROLL | NOT WS_TABSTOP
+ EDITTEXT IDC_STATUS_TEXT , 6, 175, 290, 45, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
+ EDITTEXT IDC_XSTATUS_TITLE , 6, 175, 290, 14, ES_AUTOHSCROLL
+ EDITTEXT IDC_XSTATUS_TEXT , 6, 192, 290, 28, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
+ EDITTEXT IDC_LISTENING_TEXT , 6, 175, 290, 45, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
+
+ AUTORADIOBUTTON "Audio", IDC_XSTAT_AUDIO, 186, 75, 54, 12, NOT WS_TABSTOP | BS_RIGHT | BS_LEFTTEXT | WS_GROUP
+ AUTORADIOBUTTON "Video", IDC_XSTAT_VIDEO, 244, 75, 54, 12, NOT WS_TABSTOP
+
+ CONTROL "", IDC_CBEX, "ComboBoxEx32",
+ WS_GROUP | WS_TABSTOP | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST, 186, 88, 112, 100
+}
+
+TEMPLATE12 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
+{
+ PUSHBUTTON "Color", IDC_HELP_COLOR , 184, 4, 26, 12
+ PUSHBUTTON "Format", IDC_HELP_FORMAT , 213, 4, 32, 12
+ PUSHBUTTON "Variables", IDC_HELP_VARIABLES, 248, 4, 52, 12
+
+ PUSHBUTTON "Reset", IDC_CMD_RESET, 6, 4, 56, 12
+ LTEXT "This is simplified version of template editor. This templates will be used with all protocols, protocol and player (media) statuses",
+ -1, 6,20,290,22
+
+ CTEXT "Template", -1, 6, 42, 290, 10
+ EDITTEXT IDC_EDIT_MSG, 6, 52, 290, 48, ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ CTEXT "Chat Template", -1, 6, 102, 290, 10
+ EDITTEXT IDC_EDIT_CHANNEL, 6, 112, 290, 48, ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+
+ CTEXT "[X]Status Title / Text", -1, 6, 165, 290, 10
+ EDITTEXT IDC_XSTATUS_TITLE, 6, 175, 290, 14, ES_AUTOHSCROLL
+ EDITTEXT IDC_STATUS_TEXT , 6, 192, 290, 28, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+}
diff --git a/plugins/Watrack/status/status.res b/plugins/Watrack/status/status.res
new file mode 100644
index 0000000000..fba2526583
--- /dev/null
+++ b/plugins/Watrack/status/status.res
Binary files differ
diff --git a/plugins/Watrack/status/tmpl.pas b/plugins/Watrack/status/tmpl.pas
new file mode 100644
index 0000000000..4adcd20bdf
--- /dev/null
+++ b/plugins/Watrack/status/tmpl.pas
@@ -0,0 +1,304 @@
+unit Tmpl;
+
+interface
+// ----- main data -----
+type
+ tTemplateType = (
+ tmpl_pm ,tmpl_chat,
+ tmpl_xtitle,tmpl_xtext,
+ tmpl_stext ,
+ tmpl_tunes);
+const
+ tmpl_first = tmpl_pm;
+ tmpl_last = tmpl_tunes;
+{
+const
+ TMPL_EMPTY = 0;
+ TMPL_PARENT = $4000;
+ TMPL_INACTIVE = ;
+}
+procedure CreateTemplates;
+procedure FreeTemplates;
+procedure SaveTemplates;
+
+function SetTemplateActive(active:boolean;aType:tTemplateType;proto:cardinal=0;
+ ProtoStatus:integer=0):boolean;
+function IsTemplateActive(aType:tTemplateType;proto:cardinal=0;
+ ProtoStatus:integer=0):boolean;
+function GetTemplateStr(aType:tTemplateType;proto:cardinal=0;
+ ProtoStatus:integer=0):PWideChar;
+function SetTemplateStr(aStr:PWideChar;aType:tTemplateType;proto:cardinal=0;
+ ProtoStatus:integer=0):integer;
+
+function GetMacros(TmplType:tTemplateType;proto:integer):pWideChar;
+
+implementation
+
+uses common, m_api, windows, dbsettings, mirutils, protocols,wat_api,global;
+
+const
+ dubtmpl = $4000;
+const
+ DefaultTemplate = 0;
+ NumStatus = 10;
+
+type
+ pStrTemplate = ^tStrTemplate;
+ tStrTemplate = array [0..NumStatus-1,tTemplateType] of SmallInt;
+
+type
+ pMyString = ^tMyString;
+ tMyString = record
+ count:cardinal; // link count
+ text :pWideChar;
+ end;
+ pMyStrArray = ^tMyStrArray;
+ tMyStrArray = array [1..1000] of tMyString;
+
+type
+ tTmpl = integer;
+ pStrTemplates = ^tStrTemplates;
+ tStrTemplates = array [0..100] of tStrTemplate;
+
+const
+ NumTemplates:cardinal=0;
+ StrTemplates:pStrTemplates=nil;
+
+var
+ strings:pMyStrArray;
+ NumString:cardinal;
+
+const
+ defTemplate = 'I am listening to %artist% - "%title%"';
+ defChannelText = '/me listening to %artist% - "%title%"';
+ defStatusTitle = 'Now listening to';
+ defStatusText = '%artist% - %title%';
+
+ defAltTemplate = 'I am listening to %artist% - %title%?iflonger(%album%,0, (from "%album%"),)';
+ defAltChannelText = '/me listening to %artist% - %title%?iflonger(%album%,0, (from "%album%"),)';
+
+// ----- procedures -----
+{$include i_opt_tmpl.inc}
+
+function AddString(var newstr:PWideChar):cardinal;
+var
+ i:cardinal;
+ tmp:pMyStrArray;
+begin
+ for i:=1 to NumString do // search in table
+ begin
+ if StrCmpW(newstr,strings^[i].text)=0 then
+ begin
+ result:=i;
+ mFreeMem(newstr);
+ exit;
+ end;
+ end;
+ Inc(NumString);
+ mGetMem(tmp,SizeOf(tMyString)*NumString);
+ move(strings^,tmp^,SizeOf(tMyString)*(NumString-1));
+ mFreeMem(strings);
+ strings:=tmp;
+ tmp^[NumString].count:=0;
+ tmp^[NumString].text:=newstr;
+ result:=NumString;
+end;
+
+procedure PackStrings;
+var
+ i,j:integer;
+ OldNumString:cardinal;
+ lTmplType:tTemplateType;
+ lProtoStatus:cardinal;
+ tmp:pMyStrArray;
+ NumProto:integer;
+ tmpl:pStrTemplate;
+begin
+ // clear counters
+ for i:=1 to NumString do
+ strings^[i].count:=0;
+ // counts strings
+ NumProto:=GetNumProto;
+ for i:=0 to NumProto do
+ begin
+ tmpl:=@StrTemplates^[i];
+ for lProtoStatus:=0 to NumStatus-1 do
+ for lTmplType:=tmpl_first to tmpl_last do
+ begin
+ j:=tmpl^[lProtoStatus,lTmplType];
+ if j>0 then
+ inc(strings^[j].count);
+ end;
+ end;
+ // delete strings
+ i:=1;
+ OldNumString:=NumString;
+
+ if DisablePlugin=dsEnabled then
+ DisablePlugin:=dsTemporary;
+
+ while Cardinal(i)<=NumString do
+ begin
+ if strings^[i].count=0 then
+ begin
+ mFreeMem(strings^[i].text);
+ if cardinal(i)<NumString then
+ begin
+ // shift strings
+ move(strings^[i+1],strings^[i],SizeOf(tMyString)*(NumString-cardinal(i)));
+ // shift protos
+ for j:=0 to NumProto do
+ begin
+ tmpl:=@StrTemplates^[j];
+ for lProtoStatus:=0 to NumStatus-1 do
+ for lTmplType:=tmpl_first to tmpl_last do
+ begin
+ if tmpl^[lProtoStatus,lTmplType]>i then
+ dec(tmpl^[lProtoStatus,lTmplType]);
+ end;
+ end;
+ end;
+ dec(NumString);
+ continue;
+ end;
+ inc(i);
+ end;
+ if OldNumString<>NumString then
+ begin
+ mGetMem(tmp,SizeOf(tMyString)*NumString);
+ move(strings^,tmp^,SizeOf(tMyString)*NumString);
+ mFreeMem(strings);
+ strings:=tmp;
+ end;
+
+// if DisablePlugin<0 then
+// SetTitle;
+ if DisablePlugin<>dsPermanent then
+ DisablePlugin:=dsEnabled;
+
+end;
+
+function SetTemplateActive(active:boolean;aType:tTemplateType;proto:cardinal=0;
+ ProtoStatus:integer=0):boolean;
+var
+ res:smallint;
+begin
+ if proto>NumTemplates then
+ proto:=0;
+
+ res:=ABS(StrTemplates^[proto][ProtoStatus,aType]);
+ if not active then res:=-res;
+ StrTemplates^[proto][ProtoStatus,aType]:=res;
+ result:=res>0;
+end;
+
+function IsTemplateActive(aType:tTemplateType;proto:cardinal=0;
+ ProtoStatus:integer=0):boolean;
+begin
+ if proto>NumTemplates then
+ proto:=0;
+
+ result:=StrTemplates^[proto][ProtoStatus,aType]>0;
+end;
+
+function GetTmplString(num:integer):pWideChar;
+begin
+ if (num>0) and (Cardinal(num)<=NumString) then
+ result:=strings^[num].text
+ else
+ result:=nil;
+end;
+
+function GetTemplateStr(aType:tTemplateType;proto:cardinal=0;
+ ProtoStatus:integer=0):PWideChar;
+var
+ i:smallint;
+begin
+ if proto>NumTemplates then
+ proto:=0;
+
+ i:=abs(StrTemplates^[proto ][ProtoStatus,aType]);
+ if i=smallint(dubtmpl) then begin i:=abs(StrTemplates^[proto ][0 ,aType]);
+ if i=smallint(dubtmpl) then begin i:=abs(StrTemplates^[DefaultTemplate][ProtoStatus,aType]);
+ if i=smallint(dubtmpl) then i:=abs(StrTemplates^[DefaultTemplate][0 ,aType]); end; end;
+ if i=smallint(dubtmpl) then
+ i:=0;
+
+ result:=GetTmplString(ABS(i)); //normalize
+end;
+
+function SetTemplateStr(aStr:PWideChar;aType:tTemplateType;proto:cardinal=0;
+ ProtoStatus:integer=0):integer;
+var
+ tmpl:pStrTemplate;
+ tmp,tmp1:smallint;
+begin
+ tmpl:=@StrTemplates^[proto];
+
+ if (aStr=nil) or (aStr^=#0) then
+ result:=0
+ else
+ result:=AddString(aStr);
+
+ tmp1:=result;
+ tmp:=tmpl^[0,aType];
+ if tmp1=tmp then
+ tmp1:=smallint(dubtmpl)
+ else if tmp=smallint(dubtmpl) then
+ begin
+ if tmp1=tmpl^[0,aType] then
+ tmp1:=smallint(dubtmpl);
+ end;
+ tmpl^[ProtoStatus,aType]:=tmp1;
+end;
+
+procedure CreateTemplates;
+var
+ i:integer;
+begin
+ NumTemplates:=GetNumProto;
+ // Size in bytes
+ i:=SizeOf(tStrTemplate)*(NumTemplates+1);
+ mGetMem(StrTemplates,i);
+ // size in words
+ FillWord(StrTemplates^,i div 2,dubtmpl);
+ LoadTemplates;
+end;
+
+procedure FreeTemplates;
+begin
+ mFreeMem(StrTemplates);
+ while NumString>0 do
+ begin
+ mFreeMem(strings^[NumString].text);
+ dec(NumString);
+ end;
+ mFreeMem(strings);
+end;
+
+function GetMacros(TmplType:tTemplateType;proto:integer):pWideChar;
+var
+ r:PWideChar;
+ status:integer;
+begin
+ if proto=0 then
+ r:=GetTemplateStr(TmplType,0,0)
+ else
+ begin
+ status:=GetProtoStatusNum(proto);
+ if IsTemplateActive(TmplType,proto,status) then
+ r:=GetTemplateStr(TmplType,proto,status)
+ else
+ begin
+ result:=pWideChar(-1);
+ exit;
+ end;
+ end;
+
+ if r=nil then
+ result:=nil
+ else
+ result:=pWideChar(CallService(MS_WAT_REPLACETEXT,0,lparam(r)));
+end;
+
+end.
diff --git a/plugins/Watrack/templates/i_expkey.inc b/plugins/Watrack/templates/i_expkey.inc
new file mode 100644
index 0000000000..f6594acebb
--- /dev/null
+++ b/plugins/Watrack/templates/i_expkey.inc
@@ -0,0 +1,34 @@
+{main hotkey code}
+const
+ HKN_EXPORT:PAnsiChar = 'WAT_Export';
+
+function ExportProc(wParam:WPARAM;lParam:LPARAM):int_ptr; cdecl;
+var
+ p:pWideChar;
+begin
+ result:=0;
+ if DisablePlugin<>dsPermanent then
+ begin
+ p:=pointer(CallService(MS_WAT_REPLACETEXT,0,tlparam(ExportText)));
+ SendString(0,p);
+ mFreeMem(p);
+ end;
+end;
+
+procedure reginshotkey;
+var
+ hkrec:HOTKEYDESC;
+begin
+ FillChar(hkrec,SizeOf(hkrec),0);
+ with hkrec do
+ begin
+ cbSize :=HOTKEYDESC_SIZE_V1;
+ pszName :=HKN_EXPORT;
+ pszDescription.a:='WATrack data insert hotkey';
+ pszSection.a :=PluginName;
+ pszService :=MS_WAT_EXPORT;
+ DefHotKey :=((HOTKEYF_ALT or HOTKEYF_SHIFT) shl 8) or VK_F7;
+// lParam :=0;
+ end;
+ CallService(MS_HOTKEY_REGISTER,0,lparam(@hkrec));
+end;
diff --git a/plugins/Watrack/templates/i_macro.inc b/plugins/Watrack/templates/i_macro.inc
new file mode 100644
index 0000000000..68c0be6e33
--- /dev/null
+++ b/plugins/Watrack/templates/i_macro.inc
@@ -0,0 +1,149 @@
+{Macro help dialog}
+
+procedure SaveAliases;
+var
+ buf:array [0..31] of AnsiChar;
+ i:integer;
+ p:PAnsiChar;
+begin
+ p:=StrCopyE(buf,'alias/');
+ for i:=0 to numvars-1 do
+ begin
+// if vars[i].alias<>nil then
+ DBWriteUnicode(0,PluginShort,IntToStr(p,i),vars[i].alias);
+ end;
+end;
+
+procedure LoadAliases;
+var
+ buf:array [0..31] of AnsiChar;
+ i:integer;
+ p:PAnsiChar;
+begin
+ p:=StrCopyE(buf,'alias/');
+ for i:=0 to numvars-1 do
+ vars[i].alias:=DBReadUnicode(0,PluginShort,IntToStr(p,i),nil);
+end;
+
+procedure FreeAliases;
+var
+ i:integer;
+begin
+ for i:=0 to numvars-1 do
+ mFreeMem(vars[i].alias);
+end;
+
+function MacroHelpDlg(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):integer; stdcall;
+const
+ Changed:bool=false;
+var
+ i:integer;
+ itemw:LV_ITEMW;
+ lvc:LV_COLUMN;
+ wnd:hwnd;
+ ws:PWideChar;
+ s:pAnsiChar;
+ rc:TRECT;
+begin
+ result:=0;
+ case hMessage of
+
+ WM_INITDIALOG: begin
+ FillChar(itemw,SizeOf(itemw),0);
+ FillChar(lvc ,SizeOf(lvc) ,0);
+ wnd:=GetDlgItem(Dialog,IDC_MACROHELP);
+ SendMessage(wnd,LVM_SETUNICODEFORMAT,1,0);
+ lvc.mask:=LVCF_FMT;
+ lvc.fmt :=LVCFMT_LEFT;
+ ListView_InsertColumn(wnd,0,lvc);
+ itemw.mask:=LVIF_TEXT;
+ for i:=0 to numvars-1 do
+ begin
+ itemw.iItem:=i;
+ ws:=vars[i].alias;
+ if ws=nil then
+ ws:=vars[i].name;
+ itemw.pszText:=ws;
+ SendMessageW(wnd,LVM_INSERTITEMW,0,tlparam(@itemw));
+ end;
+ ListView_SetColumnWidth(wnd,0,LVSCW_AUTOSIZE);
+ ListView_InsertColumn(wnd,1,lvc);
+ itemw.iSubItem:=1;
+ s:=nil;
+ for i:=0 to numvars-1 do
+ begin
+ itemw.iItem:=i;
+ if vars[i].help<>nil then
+ s:=vars[i].help;
+ itemw.pszText:=TranslateA2W(s);
+ SendMessageW(wnd,LVM_SETITEMTEXTW,i,tlparam(@itemw));
+ mFreeMem(itemw.pszText);
+ end;
+ ListView_SetColumnWidth(wnd,1,LVSCW_AUTOSIZE);
+ result:=1;
+ Changed:=false;
+ TranslateDialogDefault(Dialog);
+ end;
+
+ WM_SIZE: begin
+ GetClientRect(Dialog,rc);
+ InflateRect(rc,-8,-8);
+ MoveWindow(GetDlgItem(Dialog,IDC_MACROHELP),
+ rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,true);
+ end;
+
+ WM_COMMAND: begin
+ if (wParam shr 16)=BN_CLICKED then
+ case loword(wParam) of
+ IDOK, IDCANCEL: DestroyWindow(Dialog);
+ end;
+ end;
+
+ WM_DESTROY: begin
+ if Changed then
+ begin
+ SaveAliases;
+ Changed:=false;
+ RegisterVariables;
+ end;
+ end;
+
+ WM_NOTIFY: begin
+ if wParam=IDC_MACROHELP then
+ begin
+ case integer(PNMHdr(lParam)^.code) of
+ LVN_ENDLABELEDITW: begin
+ with PLVDISPINFO(lParam)^ do
+ begin
+ if item.pszText<>nil then
+ begin
+ item.mask:=LVIF_TEXT;
+ if pWideChar(item.pszText)^=#0 then
+ pWideChar(item.pszText):=vars[item.iItem].name;
+ SendMessageW(hdr.hWndFrom,LVM_SETITEMW,0,tlparam(@item));
+ mFreeMem(vars[item.iItem].alias);
+ StrDupW(vars[item.iItem].alias,pWideChar(item.pszText));
+ result:=1;
+ end;
+ Changed:=true;
+ end;
+ end;
+
+ NM_DBLCLK: begin
+ if PNMListView(lParam)^.iItem>=0 then
+ begin
+ SendMessage(PNMHdr(lParam)^.hWndFrom,LVM_EDITLABEL,
+ PNMListView(lParam)^.iItem,0);
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ end;
+end;
+
+function WATMacroHelp(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+begin
+ result:=CreateDialogParamW(hInstance,'MACRO',wParam,@MacroHelpDlg,0);
+end;
diff --git a/plugins/Watrack/templates/i_opt_it.inc b/plugins/Watrack/templates/i_opt_it.inc
new file mode 100644
index 0000000000..a9ce27ebea
--- /dev/null
+++ b/plugins/Watrack/templates/i_opt_it.inc
@@ -0,0 +1,50 @@
+{}
+const
+ opt_LoCaseType:PAnsiChar = 'locase';
+ opt_FSPrec :PAnsiChar = 'precision';
+ opt_FSizePost :PAnsiChar = 'fsizepost';
+ opt_FSizeMode :PAnsiChar = 'fsizemode';
+ opt_WriteCBR :PAnsiChar = 'writecbr';
+ opt_ReplaceSpc:PAnsiChar = 'replacespc';
+ opt_PlayerCaps:PAnsiChar = 'playercaps';
+ opt_ExportText:PAnsiChar = 'exporttext';
+
+ opt_export :PAnsiChar = 'template/export';
+ spref = 'strings/';
+
+procedure LoadOpt;
+var
+ setting:array [0..63] of AnsiChar;
+begin
+ PlayerCaps :=DBReadByte (0,PluginShort,opt_PlayerCaps,0);
+ LoCaseType :=DBReadByte (0,PluginShort,opt_LoCaseType,BST_UNCHECKED);
+ ReplaceSpc :=DBReadByte (0,PluginShort,opt_ReplaceSpc,BST_CHECKED);
+ FSPrecision:=DBReadByte (0,PluginShort,opt_FSPrec ,0);
+ FSizePost :=DBReadByte (0,PluginShort,opt_FSizePost ,0);
+ FSizeMode :=DBReadDWord (0,PluginShort,opt_FSizeMode ,1);
+ WriteCBR :=DBReadByte (0,PluginShort,opt_WriteCBR ,0);
+ if DBGetSettingType(0,PluginShort,opt_ExportText)=DBVT_DELETED then
+ begin
+ IntToStr(StrCopyE(setting,spref),DBReadWord(0,PluginShort,opt_export,3));
+ ExportText:=DBReadUnicode(0,PluginShort,setting,nil);
+ end
+ else
+ ExportText:=DBReadUnicode(0,PluginShort,opt_ExportText);
+end;
+
+procedure SaveOpt;
+begin
+ DBWriteByte (0,PluginShort,opt_PlayerCaps,PlayerCaps);
+ DBWriteByte (0,PluginShort,opt_LoCaseType,LoCaseType);
+ DBWriteByte (0,PluginShort,opt_ReplaceSpc,ReplaceSpc);
+ DBWriteByte (0,PluginShort,opt_FSPrec ,FSPrecision);
+ DBWriteByte (0,PluginShort,opt_FSizePost ,FSizePost);
+ DBWriteDWord (0,PluginShort,opt_FSizeMode ,FSizeMode);
+ DBWriteByte (0,PluginShort,opt_WriteCBR ,WriteCBR);
+ DBWriteUnicode(0,PluginShort,opt_ExportText,ExportText);
+end;
+
+procedure FreeOpt;
+begin
+ mFreeMem(ExportText);
+end;
diff --git a/plugins/Watrack/templates/i_text.inc b/plugins/Watrack/templates/i_text.inc
new file mode 100644
index 0000000000..fa0c966728
--- /dev/null
+++ b/plugins/Watrack/templates/i_text.inc
@@ -0,0 +1,135 @@
+{}
+procedure Replace(dst:pWideChar;macro:integer;value:PWideChar);
+var
+ buf:array [0..63] of WideChar;
+ pc:pWideChar;
+begin
+ buf[0]:='%';
+ pc:=vars[macro].alias;
+ if pc=nil then
+ pc:=vars[macro].name;
+ StrCopyW(buf+1,pc);
+ pc:=StrEndW(buf);
+ pc^:='%';
+ (pc+1)^:=#0;
+ StrReplaceW(dst,buf,value);
+end;
+
+function ReplaceAll(s:PWideChar):pWideChar;
+var
+ tmp:integer;
+ pp,p:pWideChar;
+ ws:array [0..127] of WideChar;
+ ls:pWideChar;
+ i:integer;
+ tmpstr:pWideChar;
+ Info:pSongInfo;
+begin
+ Info:=pointer(CallService(MS_WAT_RETURNGLOBAL,0,0));
+ mGetMem(ls,32768);
+ StrCopyW(ls,s);
+ StrReplaceW(ls,'{tab}',#9);
+
+ StrCopyW(ws,Info^.player);
+ case PlayerCaps of
+ 1: LowerCase(ws);
+ 2: UpperCase(ws);
+ end;
+ Replace(ls,mn_player,ws);
+ Replace(ls,mn_file ,Info^.mfile);
+ Replace(ls,mn_year ,Info^.year);
+ Replace(ls,mn_genre ,Info^.genre);
+ GetExt(Info^.mfile,ws);
+ if LoCaseType=BST_CHECKED then
+ LowerCase(ws)
+ else
+ UpperCase(ws);
+ Replace(ls,mn_type ,ws);
+ Replace(ls,mn_track,IntToStr(ws,Info^.track));
+// codec
+ ws[0]:=WideChar( Info^.codec and $FF);
+ ws[1]:=WideChar((Info^.codec shr 8) and $FF);
+ ws[2]:=WideChar((Info^.codec shr 16) and $FF);
+ ws[3]:=WideChar((Info^.codec shr 24) and $FF);
+ ws[4]:=#0;
+ //fps
+ IntToStr(ws,Info^.fps div 100);
+ i:=0;
+ repeat
+ inc(i);
+ until ws[i]=#0;
+ ws[i]:='.';
+ IntToStr(pWideChar(@ws[i+1]),Info^.fps mod 100);
+ Replace(ls,mn_fps ,ws);
+ Replace(ls,mn_txtver ,Info^.txtver);
+ Replace(ls,mn_height ,IntToStr(ws,Info^.height));
+ Replace(ls,mn_width ,IntToStr(ws,Info^.width));
+ Replace(ls,mn_kbps ,IntToStr(ws,Info^.kbps));
+ Replace(ls,mn_bitrate,ws);
+ if Info^.vbr<>0 then
+ p:=chVBR
+ else if WriteCBR=0 then
+ p:=nil
+ else
+ p:=chCBR;
+ Replace(ls,mn_vbr ,p);
+ Replace(ls,mn_khz ,IntToStr(ws,Info^.khz));
+ Replace(ls,mn_samplerate,ws);
+ Replace(ls,mn_channels ,IntToStr(ws,Info^.channels));
+ case Info^.channels of
+ 1: p:=chMono;
+ 2: p:=chStereo;
+ 5,6: p:=ch51;
+ end;
+ Replace(ls,mn_mono,p);
+ Replace(ls,mn_size,
+ IntToK(ws,Info^.fsize,FSizeMode,FSPrecision,FSizePost));
+ Replace(ls,mn_length,IntToTime(ws,Info^.total));
+ Replace(ls,mn_total ,ws);
+ case Info^.status of
+ WAT_MES_PLAYING: pp:=splPlaying;
+ WAT_MES_PAUSED : pp:=splPaused;
+ else
+ {WAT_MES_STOPPED:} pp:=splStopped;
+ end;
+ Replace(ls,mn_status,TranslateW(pp));
+ Replace(ls,mn_nstatus,pp);
+ Replace(ls,mn_lyric ,Info^.lyric);
+ Replace(ls,mn_cover ,Info^.cover);
+ Replace(ls,mn_volume,IntToStr(ws,loword(Info^.volume)));
+
+ mGetMem(tmpstr,32767);
+
+ StrCopyW(tmpstr,Info^.artist);
+ if ReplaceSpc=BST_CHECKED then CharReplaceW(tmpstr ,'_',' ');
+ Replace(ls,mn_artist,tmpstr);
+
+ StrCopyW(tmpstr,Info^.title);
+ if ReplaceSpc=BST_CHECKED then CharReplaceW(tmpstr ,'_',' ');
+ Replace(ls,mn_title,tmpstr);
+
+ StrCopyW(tmpstr,Info^.album);
+ if ReplaceSpc=BST_CHECKED then CharReplaceW(tmpstr ,'_',' ');
+ Replace(ls,mn_album,tmpstr);
+
+ StrCopyW(tmpstr,Info^.comment);
+ if ReplaceSpc=BST_CHECKED then CharReplaceW(tmpstr ,'_',' ');
+ Replace(ls,mn_comment,tmpstr);
+
+ StrCopyW(tmpstr,Info^.wndtext);
+ if ReplaceSpc=BST_CHECKED then CharReplaceW(tmpstr ,'_',' ');
+ Replace(ls,mn_wndtext,tmpstr);
+
+ mFreeMem(tmpstr);
+
+ Replace(ls,mn_version,IntToHex(ws,Info^.plyver));
+ Replace(ls,mn_time ,IntToTime(ws,Info^.time));
+ if Info^.total>0 then
+ tmp:=(Info^.time*100) div Info^.total
+ else
+ tmp:=0;
+ Replace(ls,mn_percent,IntToStr(ws,tmp));
+ Replace(ls,mn_playerhome,Info^.url);
+
+ result:=ls;
+end;
diff --git a/plugins/Watrack/templates/i_tmpl_dlg.inc b/plugins/Watrack/templates/i_tmpl_dlg.inc
new file mode 100644
index 0000000000..185f91d608
--- /dev/null
+++ b/plugins/Watrack/templates/i_tmpl_dlg.inc
@@ -0,0 +1,117 @@
+{}
+function DlgProcOptions(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):integer; stdcall;
+begin
+ result:=0;
+ case hMessage of
+ WM_INITDIALOG: begin
+ TranslateDialogDefault(Dialog);
+
+ if not isVarsInstalled then
+ ShowWindow(GetDlgItem(Dialog,IDC_VAR_HELP),SW_HIDE)
+ else
+ SendDlgItemMessage(Dialog,IDC_VAR_HELP,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_VARS_GETSKINITEM,0,VSI_HELPICON));
+
+ SendDlgItemMessage(Dialog,IDC_MACRO_HELP,BM_SETIMAGE,IMAGE_ICON,
+ CallService(MS_SKIN_LOADICON,SKINICON_OTHER_HELP,0));
+
+ MakeHint(Dialog,IDC_REPLACESPC,
+ 'Replaces "_" (underscores) globally in pasted os status text,'+
+ ' sometimes may be useful');
+ CheckDlgButton(Dialog,IDC_REPLACESPC,ReplaceSpc);
+
+ CheckDlgButton(Dialog,IDC_LOCASE,LoCaseType);
+
+ CheckDlgButton(Dialog,IDC_FSIZEBYTE,ord(FSizeMode=1));
+ CheckDlgButton(Dialog,IDC_FSIZEKILO,ord(FSizeMode=1024));
+ CheckDlgButton(Dialog,IDC_FSIZEMEGA,ord(FSizeMode=1024*1024));
+
+ SetDlgItemInt (Dialog,IDC_PRECISION,FSPrecision,false);
+ CheckDlgButton(Dialog,IDC_POSTNONE ,ord(FSizePost=0));
+ CheckDlgButton(Dialog,IDC_POSTSMALL,ord(FSizePost=1));
+ CheckDlgButton(Dialog,IDC_POSTMIX ,ord(FSizePost=2));
+ CheckDlgButton(Dialog,IDC_POSTLARGE,ord(FSizePost=3));
+
+ CheckDlgButton(Dialog,IDC_ALLCAP ,ord(PlayerCaps=2));
+ CheckDlgButton(Dialog,IDC_SMALLCAP,ord(PlayerCaps=1));
+ CheckDlgButton(Dialog,IDC_MIXCAP ,ord(PlayerCaps=0));
+
+ CheckDlgButton(Dialog,IDC_WRITECBR1,ord(WriteCBR=0));
+ CheckDlgButton(Dialog,IDC_WRITECBR2,ord(WriteCBR<>0));
+
+ SetDlgItemTextW(Dialog,IDC_EXPORT_TEXT,ExportText);
+ end;
+
+ WM_COMMAND: begin
+ if (wParam shr 16)=BN_CLICKED then
+ begin
+ case loword(wParam) of
+ IDC_VAR_HELP : ShowVarHelp (Dialog);
+ IDC_MACRO_HELP: CallService(MS_WAT_MACROHELP,Dialog,0);
+ IDC_ALLCAP: begin
+ CheckDlgButton(Dialog,IDC_ALLCAP ,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_SMALLCAP,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MIXCAP ,BST_UNCHECKED);
+ end;
+ IDC_SMALLCAP: begin
+ CheckDlgButton(Dialog,IDC_ALLCAP ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_SMALLCAP,BST_CHECKED);
+ CheckDlgButton(Dialog,IDC_MIXCAP ,BST_UNCHECKED);
+ end;
+ IDC_MIXCAP: begin
+ CheckDlgButton(Dialog,IDC_ALLCAP ,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_SMALLCAP,BST_UNCHECKED);
+ CheckDlgButton(Dialog,IDC_MIXCAP ,BST_CHECKED);
+ end;
+ end;
+ end;
+ if ((wParam shr 16)=EN_CHANGE) or ((wParam shr 16)=BN_CLICKED) then
+ SendMessage(GetParent(Dialog),PSM_CHANGED,0,0);
+ result:=1;
+ end;
+
+ WM_NOTIFY: begin
+ if integer(PNMHdr(lParam)^.code)=PSN_APPLY then
+ begin
+ ReplaceSpc:=IsDlgButtonChecked(Dialog,IDC_REPLACESPC);
+ LoCaseType:=IsDlgButtonChecked(Dialog,IDC_LOCASE);
+ if IsDlgButtonChecked(Dialog,IDC_WRITECBR1)=BST_CHECKED then
+ WriteCBR:=0
+ else //if IsDlgButtonChecked(Dialog,IDC_WRITECBR2)=BST_CHECKED then
+ WriteCBR:=1;
+ if IsDlgButtonChecked(Dialog,IDC_FSIZEBYTE)=BST_CHECKED then
+ FSizeMode:=1
+ else if IsDlgButtonChecked(Dialog,IDC_FSIZEKILO)=BST_CHECKED then
+ FSizeMode:=1024
+ else// if IsDlgButtonChecked(Dialog,IDC_FSIZEMEGA)=BST_CHECKED then
+ FSizeMode:=1024*1024;
+
+ if IsDlgButtonChecked(Dialog,IDC_MIXCAP)=BST_CHECKED then
+ PlayerCaps:=0
+ else if IsDlgButtonChecked(Dialog,IDC_SMALLCAP)=BST_CHECKED then
+ PlayerCaps:=1
+ else// if IsDlgButtonChecked(Dialog,IDC_ALLCAP)=BST_CHECKED then
+ PlayerCaps:=2;
+
+ if IsDlgButtonChecked(Dialog,IDC_POSTNONE)=BST_CHECKED then
+ FSizePost:=0
+ else if IsDlgButtonChecked(Dialog,IDC_POSTSMALL)=BST_CHECKED then
+ FSizePost:=1
+ else if IsDlgButtonChecked(Dialog,IDC_POSTMIX)=BST_CHECKED then
+ FSizePost:=2
+ else// if IsDlgButtonChecked(Dialog,IDC_POSTLARGE)=BST_CHECKED then
+ FSizePost:=3;
+ FSPrecision:=GetDlgItemInt(Dialog,IDC_PRECISION,pbool(nil)^,false);
+ if FSPrecision>3 then
+ FSPrecision:=3;
+
+ mFreeMem(ExportText);
+ ExportText:=GetDlgText(Dialog,IDC_EXPORT_TEXT);
+
+ SaveOpt;
+ end;
+ end;
+ else
+ {result:=}DefWindowProc(Dialog,hMessage,wParam,lParam);
+ end;
+end;
diff --git a/plugins/Watrack/templates/i_tmpl_rc.inc b/plugins/Watrack/templates/i_tmpl_rc.inc
new file mode 100644
index 0000000000..5b444a45be
--- /dev/null
+++ b/plugins/Watrack/templates/i_tmpl_rc.inc
@@ -0,0 +1,21 @@
+const
+ IDC_PRECISION = 1025;
+ IDC_FSIZEBYTE = 1026;
+ IDC_FSIZEKILO = 1027;
+ IDC_FSIZEMEGA = 1028;
+ IDC_POSTNONE = 1029;
+ IDC_POSTSMALL = 1030;
+ IDC_POSTMIX = 1031;
+ IDC_POSTLARGE = 1032;
+ IDC_LOCASE = 1033;
+ IDC_WRITECBR1 = 1034;
+ IDC_WRITECBR2 = 1035;
+ IDC_ALLCAP = 1036;
+ IDC_MIXCAP = 1037;
+ IDC_SMALLCAP = 1038;
+ IDC_EXPORT_TEXT = 1039;
+ IDC_REPLACESPC = 1040;
+ IDC_MACRO_HELP = IDHELP;//1041;
+ IDC_VAR_HELP = 1042;
+
+ IDC_MACROHELP = 1025;
diff --git a/plugins/Watrack/templates/i_variables.inc b/plugins/Watrack/templates/i_variables.inc
new file mode 100644
index 0000000000..a43c77b8c2
--- /dev/null
+++ b/plugins/Watrack/templates/i_variables.inc
@@ -0,0 +1,185 @@
+{Variables support}
+function GetField(ai:PARGUMENTSINFO):int_ptr; cdecl;
+var
+ i,j:integer;
+ res,ws:pWideChar;
+ s:array [0..31] of WideChar;
+ rs:boolean;
+ si:pSongInfo;
+begin
+ i:=0;
+ repeat
+ ws:=vars[i].alias;
+ if ws=nil then
+ ws:=vars[i].name;
+ if lstrcmpiw(PWideChar(ai^.argv^),ws)=0 then
+ break;
+ inc(i);
+ until i=numvars;
+ ws:=nil;
+ j:=-1;
+ rs:=true;
+ si:=pointer(CallService(MS_WAT_RETURNGLOBAL,0,0));
+ case i of
+ mn_wndtext: ws:=si^.wndtext;
+ mn_artist : ws:=si^.artist;
+ mn_title : ws:=si^.title;
+ mn_album : ws:=si^.album;
+ mn_genre : ws:=si^.genre;
+ mn_file : begin ws:=si^.mfile; rs:=false; end;
+ mn_year : ws:=si^.year;
+ mn_comment: ws:=si^.comment;
+ mn_player : begin
+ StrCopyW(s,si^.player);
+ case PlayerCaps of
+ 1: LowerCase(s);
+ 2: UpperCase(s);
+ end;
+ ws:=@s;
+ end;
+ mn_lyric : ws:=si^.lyric;
+ mn_cover : ws:=si^.cover;
+ mn_txtver : ws:=si^.txtver;
+ mn_type: begin
+ GetExt(si^.mfile,s);
+ if LoCaseType=BST_CHECKED then
+ LowerCase(s);
+// else
+// UpperCase(s);
+ ws:=@s;
+ end;
+ mn_size: begin
+ IntToK(s,si^.fsize,FSizeMode,FSPrecision,FSizePost);
+ ws:=@s;
+ end;
+ mn_fps: begin
+ IntToStr(s,si^.fps div 100);
+ ws:=@s;
+ while ws^<>#0 do inc(ws);
+ ws^:='.';
+ IntToStr(ws+1,si^.fps mod 100);
+ ws:=@s;
+ end;
+ mn_codec: begin
+ s[0]:=WideChar( si^.codec and $FF);
+ s[1]:=WideChar((si^.codec shr 8) and $FF);
+ s[2]:=WideChar((si^.codec shr 16) and $FF);
+ s[3]:=WideChar((si^.codec shr 24) and $FF);
+ s[4]:=#0;
+ ws:=@s;
+ end;
+ mn_vbr: if si^.vbr<>0 then
+ ws:=chVBR
+ else if WriteCBR<>0 then
+ ws:=chCBR;
+ mn_status: case si^.status of
+ WAT_MES_STOPPED: ws:=TranslateW(splStopped);
+ WAT_MES_PLAYING: ws:=TranslateW(splPlaying);
+ WAT_MES_PAUSED : ws:=TranslateW(splPaused);
+ end;
+ mn_nstatus: case si^.status of
+ WAT_MES_STOPPED: ws:=splStopped;
+ WAT_MES_PLAYING: ws:=splPlaying;
+ WAT_MES_PAUSED : ws:=splPaused;
+ end;
+ mn_mono: begin
+ case si^.channels of
+ 1: ws:=chMono;
+ 2: ws:=chStereo;
+ 5,6: ws:=ch51;
+ end;
+ end;
+ mn_playerhome: ws:=si^.url;
+ else
+ begin
+ case i of
+ mn_volume : j:=loword(si^.volume);
+ mn_width : j:=si^.width;
+ mn_height : j:=si^.height;
+ mn_kbps,
+ mn_bitrate : j:=si^.kbps;
+ mn_khz,
+ mn_samplerate: j:=si^.khz;
+ mn_channels : j:=si^.channels;
+ mn_track : j:=si^.track;
+ mn_percent: begin
+ if si^.total>0 then
+ j:=(si^.time*100) div si^.total
+ else
+ j:=0;
+ end;
+ else
+ begin
+ case i of
+ mn_total,
+ mn_length : IntToTime(s,si^.total);
+ mn_time : IntToTime(s,si^.time);
+ mn_version: IntToHex (s,si^.plyver);
+ else
+ result:=0;
+ exit;
+ end;
+ ws:=@s;
+ end;
+ end;
+ end;
+ end;
+ if (ws=nil) and (j>=0) then
+ begin
+ IntToStr(s,j);
+ ws:=@s;
+ end;
+
+ StrDupW(ws,ws);
+ If rs and (ReplaceSpc=BST_CHECKED) then
+ CharReplaceW(ws,'_',' ');
+ i:=StrLenW(ws);
+ mGetMem(res,(i+1)*SizeOf(WideChar));
+ if ws<>nil then
+ begin
+ StrCopyW(res,ws);
+ mFreeMem(ws);
+ end
+ else
+ res[0]:=#0;
+ result:=int_ptr(res);
+end;
+
+function FreeField(szReturn:PAnsiChar):int; cdecl;
+begin
+ mFreeMem(szReturn);
+ result:=1;
+end;
+
+procedure RegisterVariables;
+const
+ Prefix:PAnsiChar = 'WATrack'#9;
+var
+ rt:TTOKENREGISTER;
+ i,j:integer;
+ s:array [0..127] of AnsiChar;
+ p:pvar;
+begin
+ if not isVarsInstalled then
+ exit;
+
+ rt.cbSize :=SizeOf(rt);
+ rt.memType :=TR_MEM_OWNER;
+ rt.flags :=TRF_FIELD or TRF_CLEANUP or
+ TRF_UNICODE or TRF_PARSEFUNC or TRF_CLEANUPFUNC;
+ rt.szService :=@GetField;
+ rt.szCleanupService:=@FreeField;
+ j:=StrLen(Prefix);
+ move(Prefix^,s,j);
+ rt.szHelpText:=@s;
+ for i:=0 to numvars-1 do
+ begin
+ p:=@vars[i];
+ rt.szTokenString.w:=p.alias;
+ if rt.szTokenString.w=nil then
+ rt.szTokenString.w:=p.name;
+ if p.help<>nil then
+ StrCopy(s+j,p.help);
+ CallService(MS_VARS_REGISTERTOKEN,0,lparam(@rt));
+ end;
+end;
diff --git a/plugins/Watrack/templates/templates.pas b/plugins/Watrack/templates/templates.pas
new file mode 100644
index 0000000000..ec56580852
--- /dev/null
+++ b/plugins/Watrack/templates/templates.pas
@@ -0,0 +1,113 @@
+unit templates;
+{$include compilers.inc}
+interface
+{$Resource templates.res}
+implementation
+
+uses
+ messages,windows,commctrl,
+ common,syswin,wrapper,
+ m_api,dbsettings,mirutils,
+ wat_api,global,macros;
+
+const
+ splStopped:PWideChar = 'stopped';
+ splPlaying:PWideChar = 'playing';
+ splPaused :PWideChar = 'paused';
+ chMono :PWideChar = 'mono';
+ chStereo :PWideChar = 'stereo';
+ ch51 :PWideChar = '5.1';
+ chVBR :PWideChar = 'VBR';
+ chCBR :PWideChar = 'CBR';
+
+const
+ LoCaseType :integer=0;
+ WriteCBR :integer=0;
+ ReplaceSpc :integer=0;
+ FSizeMode :integer=1024*1024;
+ FSizePost :integer=2;
+ FSPrecision :integer=2;
+ PlayerCaps :integer=0;
+ ExportText:pWideChar=nil;
+
+{$include i_tmpl_rc.inc}
+{$include i_variables.inc}
+{$include i_macro.inc}
+{$include i_text.inc}
+{$include i_opt_it.inc}
+{$include i_tmpl_dlg.inc}
+{$include i_expkey.inc}
+
+function WATReplaceText(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ p:pWideChar;
+begin
+ if (lParam<>0) and (pWideChar(lParam)^<>#0) then
+ begin
+ if isVarsInstalled then
+ result:=int_ptr(ParseVarString(pWideChar(lParam)))
+ else
+ result:=int_ptr(ReplaceAll(pWideChar(lParam)));
+ if (result<>0) and (pWideChar(result)^=#0) then
+ begin
+ p:=PWideChar(result);
+ mFreeMem(p);
+ result:=0;
+ end;
+ end
+ else
+ result:=0;
+end;
+
+// ------------ base interface functions -------------
+
+function AddOptionsPage(var tmpl:pAnsiChar;var proc:pointer;var name:PAnsiChar):integer;
+begin
+ tmpl:='FORMAT';
+ proc:=@DlgProcOptions;
+ name:='Templates';
+ result:=0;
+end;
+
+var
+ hEXP,
+ hMacro,
+ hReplace:THANDLE;
+
+function InitProc(aGetStatus:boolean=false):integer;
+begin
+ result:=1;
+ hEXP :=CreateServiceFunction(MS_WAT_EXPORT ,@ExportProc);
+ hReplace:=CreateServiceFunction(MS_WAT_REPLACETEXT,@WATReplaceText);
+ hMacro :=CreateServiceFunction(MS_WAT_MACROHELP ,@WATMacroHelp);
+ LoadOpt;
+ LoadAliases;
+ RegisterVariables;
+ reginshotkey;
+end;
+
+procedure DeInitProc(aSetDisable:boolean);
+begin
+ DestroyServiceFunction(hReplace);
+ DestroyServiceFunction(hEXP);
+ DestroyServiceFunction(hMacro);
+ FreeAliases;
+ FreeOpt;
+end;
+
+var
+ Tmpl:twModule;
+
+procedure Init;
+begin
+ Tmpl.Next :=ModuleLink;
+ Tmpl.Init :=@InitProc;
+ Tmpl.DeInit :=@DeInitProc;
+ Tmpl.AddOption :=@AddOptionsPage;
+ Tmpl.ModuleName:=nil;
+ ModuleLink :=@Tmpl;
+end;
+
+begin
+ Init;
+end.
diff --git a/plugins/Watrack/templates/templates.rc b/plugins/Watrack/templates/templates.rc
new file mode 100644
index 0000000000..f7e8ff1f20
--- /dev/null
+++ b/plugins/Watrack/templates/templates.rc
@@ -0,0 +1,51 @@
+#include "i_tmpl_rc.inc"
+
+LANGUAGE 0,0
+
+FORMAT 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
+{
+ GROUPBOX "Options", -1, 2, 2, 188, 161, WS_TABSTOP
+ AUTOCHECKBOX "Replace underlines with spaces", IDC_REPLACESPC, 6, 12, 182, 14, BS_VCENTER | BS_MULTILINE | BS_NOTIFY
+
+ EDITTEXT IDC_PRECISION, 192, 60, 20, 12, ES_RIGHT | ES_NUMBER
+ GROUPBOX "File size", -1, 192, 2, 64, 54
+ AUTORADIOBUTTON "Bytes" , IDC_FSIZEBYTE, 196, 14, 50, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Kilobytes", IDC_FSIZEKILO, 196, 28, 50, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Megabytes", IDC_FSIZEMEGA, 196, 42, 50, 10, NOT WS_TABSTOP
+ LTEXT "Precision", -1, 216, 62, 84, 12
+ GROUPBOX "Postfix", -1, 258, 2, 42, 54
+ AUTORADIOBUTTON "none", IDC_POSTNONE , 262, 12, 30, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "kb" , IDC_POSTSMALL, 262, 23, 30, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "Kb" , IDC_POSTMIX , 262, 34, 30, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "KB" , IDC_POSTLARGE, 262, 45, 30, 10, NOT WS_TABSTOP
+// CONTROL "", -1, "STATIC", SS_ETCHEDHORZ, 192, 77, 108, 2
+ GROUPBOX "VBR macro", -1, 192, 77, 108, 34
+ AUTORADIOBUTTON "VBR or empty", IDC_WRITECBR1, 198, 87, 96, 10, NOT WS_TABSTOP
+ AUTORADIOBUTTON "VBR or CBR" , IDC_WRITECBR2, 198, 99, 96, 10, NOT WS_TABSTOP
+ GROUPBOX "Player name letters", -1, 192, 115, 108, 48
+ RADIOBUTTON "All uppercase", IDC_ALLCAP , 198, 127, 96, 10, NOT WS_TABSTOP
+ RADIOBUTTON "Do not change", IDC_MIXCAP , 198, 139, 96, 10, NOT WS_TABSTOP
+ RADIOBUTTON "All lowercase", IDC_SMALLCAP, 198, 151, 96, 10, NOT WS_TABSTOP
+
+ AUTOCHECKBOX "lowercase %type%", IDC_LOCASE, 193,164, 108, 14
+
+ LTEXT "Export text template",-1, 6, 164 ,142, 14, SS_CENTERIMAGE
+ EDITTEXT IDC_EXPORT_TEXT, 4, 180, 296, 42,
+ ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+// PUSHBUTTON "V", IDC_VAR_HELP ,154,163,16,16
+// PUSHBUTTON "M", IDC_MACRO_HELP,172,163,16,16
+ CONTROL "V" ,IDC_VAR_HELP ,"MButtonClass",WS_TABSTOP,154,163,16,16,$18000000
+ CONTROL "M" ,IDC_MACRO_HELP ,"MButtonClass",WS_TABSTOP,172,163,16,16,$18000000
+}
+
+MACRO DIALOGEX 0, 0, 240, 176, 0
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_SIZEBOX
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "WATrack Macro Info"
+FONT 8, "MS Shell Dlg", 0, 0
+{
+ CONTROL "", IDC_MACROHELP, "SysListView32", WS_BORDER | WS_TABSTOP | LVS_NOCOLUMNHEADER | LVS_EDITLABELS | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT, 6, 6, 228, 164, WS_EX_CONTROLPARENT
+}
diff --git a/plugins/Watrack/templates/templates.res b/plugins/Watrack/templates/templates.res
new file mode 100644
index 0000000000..d23e804915
--- /dev/null
+++ b/plugins/Watrack/templates/templates.res
Binary files differ
diff --git a/plugins/Watrack/wat_api.pas b/plugins/Watrack/wat_api.pas
new file mode 100644
index 0000000000..52fd0f2650
--- /dev/null
+++ b/plugins/Watrack/wat_api.pas
@@ -0,0 +1,183 @@
+unit wat_api;
+
+interface
+
+uses windows;
+
+{$Include m_music.inc}
+
+function GenreName(idx:cardinal):pWideChar;
+
+implementation
+
+uses common;
+
+const
+ MAX_MUSIC_GENRES = 148;
+
+Genres:array [0..MAX_MUSIC_GENRES-1] of PWideChar = (
+{0} 'Blues',
+{1} 'Classic Rock',
+{2} 'Country',
+{3} 'Dance',
+{4} 'Disco',
+{5} 'Funk',
+{6} 'Grunge',
+{7} 'Hip-Hop',
+{8} 'Jazz',
+{9} 'Metal',
+{10} 'New Age',
+{11} 'Oldies',
+{12} 'Other',
+{13} 'Pop',
+{14} 'R&B',
+{15} 'Rap',
+{16} 'Reggae',
+{17} 'Rock',
+{18} 'Techno',
+{19} 'Industrial',
+{20} 'Alternative',
+{21} 'Ska',
+{22} 'Death Metal',
+{23} 'Pranks',
+{24} 'Soundtrack',
+{25} 'Euro-Techno',
+{26} 'Ambient',
+{27} 'Trip-Hop',
+{28} 'Vocal',
+{29} 'Jazz+Funk',
+{30} 'Fusion',
+{31} 'Trance',
+{32} 'Classical',
+{33} 'Instrumental',
+{34} 'Acid',
+{35} 'House',
+{36} 'Game',
+{37} 'Sound Clip',
+{38} 'Gospel',
+{39} 'Noise',
+{40} 'AlternRock',
+{41} 'Bass',
+{42} 'Soul',
+{43} 'Punk',
+{44} 'Space',
+{45} 'Meditative',
+{46} 'Instrumental Pop',
+{47} 'Instrumental Rock',
+{48} 'Ethnic',
+{49} 'Gothic',
+{50} 'Darkwave',
+{51} 'Techno-Industrial',
+{52} 'Electronic',
+{53} 'Pop-Folk',
+{54} 'Eurodance',
+{55} 'Dream',
+{56} 'Southern Rock',
+{57} 'Comedy',
+{58} 'Cult',
+{59} 'Gangsta',
+{60} 'Top 40',
+{61} 'Christian Rap',
+{62} 'Pop/Funk',
+{63} 'Jungle',
+{64} 'Native American',
+{65} 'Cabaret',
+{66} 'New Wave',
+{67} 'Psychadelic',
+{68} 'Rave',
+{69} 'Showtunes',
+{70} 'Trailer',
+{71} 'Lo-Fi',
+{72} 'Tribal',
+{73} 'Acid Punk',
+{74} 'Acid Jazz',
+{75} 'Polka',
+{76} 'Retro',
+{77} 'Musical',
+{78} 'Rock & Roll',
+{79} 'Hard Rock',
+{80} 'Folk',
+{81} 'Folk-Rock',
+{82} 'National Folk',
+{83} 'Swing',
+{84} 'Fast Fusion',
+{85} 'Bebob',
+{86} 'Latin',
+{87} 'Revival',
+{88} 'Celtic',
+{89} 'Bluegrass',
+{90} 'Avantgarde',
+{91} 'Gothic Rock',
+{92} 'Progressive Rock',
+{93} 'Psychedelic Rock',
+{94} 'Symphonic Rock',
+{95} 'Slow Rock',
+{96} 'Big Band',
+{97} 'Chorus',
+{98} 'Easy Listening',
+{99} 'Acoustic',
+{100} 'Humour',
+{101} 'Speech',
+{102} 'Chanson',
+{103} 'Opera',
+{104} 'Chamber Music',
+{105} 'Sonata',
+{106} 'Symphony',
+{107} 'Booty Brass',
+{108} 'Primus',
+{109} 'Porn Groove',
+{110} 'Satire',
+{111} 'Slow Jam',
+{112} 'Club',
+{113} 'Tango',
+{114} 'Samba',
+{115} 'Folklore',
+{116} 'Ballad',
+{117} 'Poweer Ballad',
+{118} 'Rhytmic Soul',
+{119} 'Freestyle',
+{120} 'Duet',
+{121} 'Punk Rock',
+{122} 'Drum Solo',
+{123} 'A Capela',
+{124} 'Euro-House',
+{125} 'Dance Hall',
+{126} 'Goa',
+{127} 'Drum & Bass',
+{128} 'Club-House',
+{129} 'Hardcore',
+{130} 'Terror',
+{131} 'Indie',
+{132} 'BritPop',
+{133} 'Negerpunk',
+{134} 'Polsk Punk',
+{135} 'Beat',
+{136} 'Christian Gangsta Rap',
+{137} 'Heavy Metal',
+{138} 'Black Metal',
+{139} 'Crossover',
+{140} 'Contemporary Christian',
+{141} 'Christian Rock',
+{142} 'Merengue',
+{143} 'Salsa',
+{144} 'Trash Metal',
+{145} 'Anime',
+{146} 'JPop',
+{147} 'Synthpop');
+
+function GenreName(idx:cardinal):pWideChar;
+begin
+ if idx<MAX_MUSIC_GENRES then
+ begin
+ StrDupW(result,Genres[idx]);
+{
+ mGetMem(result,64*SizeOf(WideChar));
+ LoadStringW(hInstance,idx,result,64);
+}
+// result:=Genres[idx];
+ end
+ else
+ result:=nil;
+end;
+
+end.
diff --git a/plugins/Watrack/waticons.inc b/plugins/Watrack/waticons.inc
new file mode 100644
index 0000000000..0c3c423f0e
--- /dev/null
+++ b/plugins/Watrack/waticons.inc
@@ -0,0 +1,35 @@
+const
+ IDI_PREV_NORMAL = 1;
+ IDI_PREV_HOVERED = 2;
+ IDI_PREV_PRESSED = 3;
+
+ IDI_PLAY_NORMAL = 4;
+ IDI_PLAY_HOVERED = 5;
+ IDI_PLAY_PRESSED = 6;
+
+ IDI_PAUSE_NORMAL = 7;
+ IDI_PAUSE_HOVERED = 8;
+ IDI_PAUSE_PRESSED = 9;
+
+ IDI_STOP_NORMAL = 10;
+ IDI_STOP_HOVERED = 11;
+ IDI_STOP_PRESSED = 12;
+
+ IDI_NEXT_NORMAL = 13;
+ IDI_NEXT_HOVERED = 14;
+ IDI_NEXT_PRESSED = 15;
+
+ IDI_VOLDN_NORMAL = 16;
+ IDI_VOLDN_HOVERED = 17;
+ IDI_VOLDN_PRESSED = 18;
+
+ IDI_VOLUP_NORMAL = 19;
+ IDI_VOLUP_HOVERED = 20;
+ IDI_VOLUP_PRESSED = 21;
+
+ IDI_SLIDER_NORMAL = 22;
+ IDI_SLIDER_HOVERED = 23;
+ IDI_SLIDER_PRESSED = 24;
+
+ IDI_PLUGIN_ENABLE = 100;
+ IDI_PLUGIN_DISABLE = 101;
diff --git a/plugins/Watrack/waticons.pas b/plugins/Watrack/waticons.pas
new file mode 100644
index 0000000000..5b61af18dd
--- /dev/null
+++ b/plugins/Watrack/waticons.pas
@@ -0,0 +1,202 @@
+unit WATIcons;
+interface
+
+uses wat_api;
+
+const // to not load icobuttons module
+ AST_NORMAL = 0;
+ AST_HOVERED = 1;
+ AST_PRESSED = 2;
+
+// main Enable/Disable icons
+const // name in icolib
+ IcoBtnEnable :PAnsiChar='WATrack_Enabled';
+ IcoBtnDisable:PAnsiChar='WATrack_Disabled';
+
+function RegisterIcons:boolean;
+
+// frame button icons
+function RegisterButtonIcons:boolean;
+function GetIcon(action:integer;stat:integer=AST_NORMAL):cardinal;
+function DoAction(action:integer):integer;
+function GetIconDescr(action:integer):pAnsiChar;
+{
+const
+ AST_NORMAL = 0;
+ AST_HOVERED = 1;
+ AST_PRESSED = 2;
+}
+implementation
+
+uses m_api,windows;
+
+{$include waticons.inc}
+
+const
+ ICOCtrlName = 'watrack_buttons.dll';
+
+const
+ IconsLoaded:bool = false;
+
+function DoAction(action:integer):integer;
+begin
+ result:=CallService(MS_WAT_PRESSBUTTON,action,0);
+end;
+
+function RegisterIcons:boolean;
+var
+ sid:TSKINICONDESC;
+ buf:array [0..511] of AnsiChar;
+ hIconDLL:THANDLE;
+begin
+ result:=true;
+ sid.szDefaultFile.a:='icons\'+ICOCtrlName;
+// ConvertFileName(sid.szDefaultFile.a,buf);
+ CallService(MS_UTILS_PATHTOABSOLUTE,wparam(sid.szDefaultFile),lparam(@buf));
+
+ hIconDLL:=LoadLibraryA(buf);
+ if hIconDLL=0 then // not found
+ begin
+ sid.szDefaultFile.a:='plugins\'+ICOCtrlName;
+// ConvertFileName(sid.szDefaultFile.a,buf);
+ CallService(MS_UTILS_PATHTOABSOLUTE,wparam(sid.szDefaultFile),lparam(@buf));
+ hIconDLL:=LoadLibraryA(buf);
+ end;
+
+ if hIconDLL=0 then
+ hIconDLL:=hInstance;
+
+ FillChar(sid,SizeOf(TSKINICONDESC),0);
+ sid.cbSize:=SizeOf(TSKINICONDESC);
+ sid.cx:=16;
+ sid.cy:=16;
+ sid.szSection.a:='WATrack';
+
+ sid.hDefaultIcon :=LoadImage(hIconDLL,
+ MAKEINTRESOURCE(IDI_PLUGIN_ENABLE),IMAGE_ICON,16,16,0);
+ sid.pszName :=IcoBtnEnable;
+ sid.szDescription.a:='Plugin Enabled';
+ Skin_AddIcon(@sid);
+ DestroyIcon(sid.hDefaultIcon);
+
+ sid.hDefaultIcon :=LoadImage(hIconDLL,
+ MAKEINTRESOURCE(IDI_PLUGIN_DISABLE),IMAGE_ICON,16,16,0);
+ sid.pszName :=IcoBtnDisable;
+ sid.szDescription.a:='Plugin Disabled';
+ Skin_AddIcon(@sid);
+ DestroyIcon(sid.hDefaultIcon);
+
+ if hIconDLL<>hInstance then
+ FreeLibrary(hIconDLL);
+end;
+
+type
+ PAWKIconButton = ^TAWKIconButton;
+ TAWKIconButton = record
+ descr:PAnsiChar;
+ name :PAnsiChar;
+ id :int_ptr;
+ end;
+const
+ CtrlIcoLib:array [WAT_CTRL_FIRST..WAT_CTRL_LAST,AST_NORMAL..AST_PRESSED] of
+ TAWKIconButton = (
+ ((descr:'Prev' ;name:'WATrack_Prev' ; id:IDI_PREV_NORMAL),
+ (descr:'Prev Hovered' ;name:'WATrack_PrevH' ; id:IDI_PREV_HOVERED),
+ (descr:'Prev Pushed' ;name:'WATrack_PrevP' ; id:IDI_PREV_PRESSED)),
+
+ ((descr:'Play' ;name:'WATrack_Play' ; id:IDI_PLAY_NORMAL),
+ (descr:'Play Hovered' ;name:'WATrack_PlayH' ; id:IDI_PLAY_HOVERED),
+ (descr:'Play Pushed' ;name:'WATrack_PlayP' ; id:IDI_PLAY_PRESSED)),
+
+ ((descr:'Pause' ;name:'WATrack_Pause' ; id:IDI_PAUSE_NORMAL),
+ (descr:'Pause Hovered' ;name:'WATrack_PauseH' ; id:IDI_PAUSE_HOVERED),
+ (descr:'Pause Pushed' ;name:'WATrack_PauseP' ; id:IDI_PAUSE_PRESSED)),
+
+ ((descr:'Stop' ;name:'WATrack_Stop' ; id:IDI_STOP_NORMAL),
+ (descr:'Stop Hovered' ;name:'WATrack_StopH' ; id:IDI_STOP_HOVERED),
+ (descr:'Stop Pushed' ;name:'WATrack_StopP' ; id:IDI_STOP_PRESSED)),
+
+ ((descr:'Next' ;name:'WATrack_Next' ; id:IDI_NEXT_NORMAL),
+ (descr:'Next Hovered' ;name:'WATrack_NextH' ; id:IDI_NEXT_HOVERED),
+ (descr:'Next Pushed' ;name:'WATrack_NextP' ; id:IDI_NEXT_PRESSED)),
+
+ ((descr:'Volume Down' ;name:'WATrack_VolDn' ; id:IDI_VOLDN_NORMAL),
+ (descr:'Volume Down Hovered';name:'WATrack_VolDnH' ; id:IDI_VOLDN_HOVERED),
+ (descr:'Volume Down Pushed' ;name:'WATrack_VolDnP' ; id:IDI_VOLDN_PRESSED)),
+
+ ((descr:'Volume Up' ;name:'WATrack_VolUp' ; id:IDI_VOLUP_NORMAL),
+ (descr:'Volume Up Hovered' ;name:'WATrack_VolUpH' ; id:IDI_VOLUP_HOVERED),
+ (descr:'Volume Up Pushed' ;name:'WATrack_VolUpP' ; id:IDI_VOLUP_PRESSED)),
+
+ ((descr:'Slider' ;name:'WATrack_Slider' ; id:IDI_SLIDER_NORMAL),
+ (descr:'Slider Hovered' ;name:'WATrack_SliderH'; id:IDI_SLIDER_HOVERED),
+ (descr:'Slider Pushed' ;name:'WATrack_SliderP'; id:IDI_SLIDER_PRESSED))
+ );
+
+function RegisterButtonIcons:boolean;
+var
+ sid:TSKINICONDESC;
+ buf:array [0..511] of AnsiChar;
+ hIconDLL:THANDLE;
+ i,j:integer;
+ path:pAnsiChar;
+begin
+ if not IconsLoaded then
+ begin
+ path:='icons\'+ICOCtrlName;
+// ConvertFileName(sid.szDefaultFile.a,buf);
+ CallService(MS_UTILS_PATHTOABSOLUTE,wparam(path),lparam(@buf));
+
+ hIconDLL:=LoadLibraryA(buf);
+ if hIconDLL=0 then // not found
+ begin
+ sid.szDefaultFile.a:='plugins\'+ICOCtrlName;
+// ConvertFileName(sid.szDefaultFile.a,buf);
+ CallService(MS_UTILS_PATHTOABSOLUTE,wparam(path),lparam(@buf));
+ hIconDLL:=LoadLibraryA(buf);
+ end;
+
+ if hIconDLL<>0 then
+ begin
+ FreeLibrary(hIconDLL);
+ FillChar(sid,SizeOf(sid),0);
+ sid.flags:=0;
+ sid.cbSize:=SizeOf(TSKINICONDESC);
+ sid.cx:=16;
+ sid.cy:=16;
+
+ sid.szSection.a :='WATrack/Frame Controls';
+ sid.szDefaultFile.a:=path;
+ i:=WAT_CTRL_FIRST;
+ repeat
+ j:=AST_NORMAL;
+ repeat
+ // increment from 1 by order, so - just decrease number (for iconpack import)
+ sid.iDefaultIndex :=CtrlIcoLib[i][j].id-1;
+ sid.pszName :=CtrlIcoLib[i][j].name;
+ sid.szDescription.a:=CtrlIcoLib[i][j].descr;
+
+ Skin_AddIcon(@sid);
+ Inc(j);
+ until j>AST_PRESSED;
+ Inc(i);
+ until i>WAT_CTRL_LAST;
+ IconsLoaded:=true;
+ end;
+ end;
+
+ result:=IconsLoaded;
+end;
+
+function GetIcon(action:integer;stat:integer):cardinal;
+begin
+ result:=CallService(MS_SKIN2_GETICON,0,
+ lparam(CtrlIcoLib[action][stat].name));
+end;
+
+function GetIconDescr(action:integer):pAnsiChar;
+begin
+ result:=CtrlIcoLib[action][AST_NORMAL].descr;
+end;
+
+end.
diff --git a/plugins/Watrack/watrack.dpr b/plugins/Watrack/watrack.dpr
new file mode 100644
index 0000000000..2702c4852f
--- /dev/null
+++ b/plugins/Watrack/watrack.dpr
@@ -0,0 +1,675 @@
+{$include compilers.inc}
+{$IFDEF COMPILER_16_UP}
+ {$WEAKLINKRTTI ON}
+ {.$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
+{$ENDIF}
+{$IMAGEBASE $13000000}
+library WATrack;
+uses
+ // FastMM not compatible with FPC, internal for delphi xe
+// {$IFNDEF COMPILER_16_UP}{$IFNDEF FPC}fastmm4,{$ENDIF}{$ENDIF}
+ m_api,dbsettings,activex,winampapi,
+ Windows,messages,commctrl,//uxtheme,
+ srv_format,srv_player,wat_api,wrapper,
+ common,syswin,HlpDlg,mirutils
+ ,global,waticons,io,macros, msninfo
+ ,myshows in 'myshows\myshows.pas'
+ ,lastfm in 'lastfm\lastfm.pas'
+ ,statlog in 'stat\statlog.pas'
+ ,popups in 'popup\popups.pas'
+ ,proto in 'proto\proto.pas'
+ ,status in 'status\status.pas'
+ ,tmpl in 'status\tmpl.pas'
+ ,templates in 'templates\templates.pas'
+{$IFDEF KOL_MCK}
+ ,kolframe in 'kolframe\kolframe.pas'
+{$ENDIF}
+ {$include lst_players.inc}
+ {$include lst_formats.inc}
+;
+
+{$include res\i_const.inc}
+
+{$Resource res\watrack.res}
+
+{$include i_vars.inc}
+
+const
+ MenuDisablePos = 500050000;
+
+function MirandaPluginInfoEx(mirandaVersion:DWORD):PPLUGININFOEX; cdecl;
+begin
+ result:=@PluginInfo;
+ PluginInfo.cbSize :=SizeOf(TPLUGININFOEX);
+ PluginInfo.shortName :=PluginName;
+ PluginInfo.version :=$0000060C;
+ PluginInfo.description:='Paste played music info into message window or status text';
+ PluginInfo.author :='Awkward';
+ PluginInfo.authorEmail:='panda75@bk.ru; awk1975@ya.ru';
+ PluginInfo.copyright :='(c) 2005-2012 Awkward';
+ PluginInfo.homepage :='http://code.google.com/p/delphi-miranda-plugins/';
+ PluginInfo.flags :=UNICODE_AWARE;
+ PluginInfo.uuid :=MIID_WATRACK;
+end;
+
+{$include i_options.inc}
+{$include i_timer.inc}
+{$include i_gui.inc}
+{$include i_opt_dlg.inc}
+{$include i_cover.inc}
+
+function ReturnInfo(enc:WPARAM;cp:LPARAM=CP_ACP):pointer;
+begin
+ if enc<>WAT_INF_UNICODE then
+ begin
+ ClearSongInfoData(tSongInfo(SongInfoA),true);
+ move(SongInfo,SongInfoA,SizeOf(tSongInfo));
+ with SongInfoA do
+ begin
+ FastWideToAnsi(SongInfo.url,url);
+ if enc=WAT_INF_ANSI then
+ begin
+ WideToAnsi(SongInfo.artist ,artist ,cp);
+ WideToAnsi(SongInfo.title ,title ,cp);
+ WideToAnsi(SongInfo.album ,album ,cp);
+ WideToAnsi(SongInfo.genre ,genre ,cp);
+ WideToAnsi(SongInfo.comment,comment,cp);
+ WideToAnsi(SongInfo.year ,year ,cp);
+ WideToAnsi(SongInfo.mfile ,mfile ,cp);
+ WideToAnsi(SongInfo.wndtext,wndtext,cp);
+ WideToAnsi(SongInfo.player ,player ,cp);
+ WideToAnsi(SongInfo.txtver ,txtver ,cp);
+ WideToAnsi(SongInfo.lyric ,lyric ,cp);
+ WideToAnsi(SongInfo.cover ,cover ,cp);
+ WideToAnsi(SongInfo.url ,url ,cp);
+ end
+ else
+ begin
+ WideToUTF8(SongInfo.artist ,artist);
+ WideToUTF8(SongInfo.title ,title);
+ WideToUTF8(SongInfo.album ,album);
+ WideToUTF8(SongInfo.genre ,genre);
+ WideToUTF8(SongInfo.comment,comment);
+ WideToUTF8(SongInfo.year ,year);
+ WideToUTF8(SongInfo.mfile ,mfile);
+ WideToUTF8(SongInfo.wndtext,wndtext);
+ WideToUTF8(SongInfo.player ,player);
+ WideToUTF8(SongInfo.txtver ,txtver);
+ WideToUTF8(SongInfo.lyric ,lyric);
+ WideToUTF8(SongInfo.cover ,cover);
+ WideToUTF8(SongInfo.url ,url);
+ end;
+ end;
+ result:=@SongInfoA;
+ end
+ else
+ result:=@SongInfo;
+end;
+
+function WATReturnGlobal(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+begin
+ if wParam=0 then wParam:=WAT_INF_UNICODE;
+ if lParam=0 then lParam:=MirandaCP;
+
+ result:=int_ptr(ReturnInfo(wParam,lParam));
+end;
+
+function WATGetFileInfo(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+// si:TSongInfo;
+ dst:pSongInfo;
+ extw:array [0..7] of WideChar;
+ f:THANDLE;
+ p:PWideChar;
+begin
+ result:=1;
+ if (lParam=0) or (pSongInfo(lParam).mfile=nil) then exit;
+ dst:=pointer(lParam);
+ StrDupW(p,dst^.mfile);
+ ClearTrackInfo(dst^,false); //!!!!
+ dst^.mfile:=p;
+// FillChar(dst,SizeOf(dst),0);
+// FillChar(si,SizeOf(si),0);
+{
+ if flags and WAT_INF_ANSI<>0 then
+ AnsiToWide(dst^.mfile,si.mfile)
+ else if flags and WAT_INF_UTF<>0 then
+ UTFToWide(dst^.mfile,si.mfile)
+ else
+ si.mfile:=dst^.mfile;
+}
+ f:=Reset(dst^.mfile);
+ if dword(f)<>INVALID_HANDLE_VALUE then
+ GetFileTime(f,nil,nil,@dst^.date);
+ CloseHandle(f);
+ dst^.fsize:=GetFSize(dst^.mfile);
+ GetExt(dst^.mfile,extw);
+ if GetFileFormatInfo(dst^)<>WAT_RES_NOTFOUND then
+ begin
+ with dst^ do
+ begin
+ if (cover=nil) or (cover^=#0) then
+ GetCover(cover,mfile);
+ if (lyric=nil) or (lyric^=#0) then
+ GetLyric(lyric,mfile);
+ end;
+ result:=0;
+// ReturnInfo(si,dst,wParam and $FF);
+ end;
+end;
+
+function WATGetMusicInfo(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+type
+ ppointer = ^pointer;
+const
+ giused:cardinal=0;
+var
+ flags:cardinal;
+ buf:PWideChar;
+ OldPlayerStatus:integer;
+ stat:integer;
+ newplayer:bool;
+begin
+ result:=WAT_RES_NOTFOUND;
+ if DisablePlugin=dsPermanent then
+ exit;
+
+ //----- Return old info if main timer -----
+ if giused<>0 then
+ begin
+ result:=WAT_RES_OK;
+ if lParam<>0 then
+ ppointer(lParam)^:=ReturnInfo(wParam and $FF);
+ exit;
+ end;
+
+ giused:=1;
+
+ OldPlayerStatus:=WorkSI.status;
+
+ //----- Checking player -----
+ // get player status too
+ flags:=0;
+ if CheckAll<>BST_UNCHECKED then flags:=flags or WAT_OPT_CHECKALL;
+ // no need old data, clear
+// ClearPlayerInfo(WorkSI,false);
+ result:=CheckPlayers(WorkSI,flags);
+ if result=WAT_RES_NEWPLAYER then
+ begin
+ newplayer:=true;
+ NotifyEventHooks(hHookWATStatus,WAT_EVENT_NEWPLAYER,tlparam(@WorkSI));
+ result:=WAT_RES_OK;
+ end
+ else // !!!! (need to add) must remember about same player, another instance
+ newplayer:=false;
+
+ // Checking player status
+ if result=WAT_RES_OK then
+ begin
+ if not newplayer then //!!cheat
+ SongInfo.plwnd:=WorkSI.plwnd;
+
+ // player stopped - no need file info
+ if WorkSI.status=WAT_MES_STOPPED then
+ begin
+ ClearFileInfo (WorkSI,false);
+ ClearChangingInfo(WorkSI,false);
+ ClearTrackInfo (WorkSI,false);
+
+ if Hiword(OldPlayerStatus)<>WAT_MES_STOPPED then
+ begin
+ NotifyEventHooks(hHookWATStatus,WAT_EVENT_PLAYERSTATUS,WAT_MES_STOPPED);
+ end;
+
+ ClearFileInfo (SongInfo,true);
+ ClearChangingInfo(SongInfo,true);
+ ClearTrackInfo (SongInfo,true);
+ if newplayer then
+ begin
+ ClearPlayerInfo(SongInfo,true);
+ CopyPlayerInfo (WorkSI,SongInfo);
+ end;
+ WorkSI.status:=(WAT_MES_STOPPED shl 16) or (WAT_PLS_NOMUSIC and $FFFF);
+ SongInfo.status:=WorkSI.status;
+ end
+ else
+ begin
+ //----- Get file (no file, new file, maybe new) -----
+ // file info will be replaced (name most important only)
+ flags:=0;
+ if CheckTime <>BST_UNCHECKED then flags:=flags or WAT_OPT_CHECKTIME;
+ if UseImplant<>BST_UNCHECKED then flags:=flags or WAT_OPT_IMPLANTANT;
+ if MTHCheck <>BST_UNCHECKED then flags:=flags or WAT_OPT_MULTITHREAD;
+ if KeepOld <>BST_UNCHECKED then flags:=flags or WAT_OPT_KEEPOLD;
+
+ // requirement - old file name
+ result:=CheckFile(WorkSI,flags,TimeoutForThread);
+
+ // here - place for Playerstatus event
+ // high word - song status (play, pause,stop, nothing)
+ // low word - player status (normal,no music, nothing)
+ case WorkSI.status of
+ WAT_MES_PLAYING,
+ WAT_MES_PAUSED: stat:=WAT_PLS_NORMAL;
+ WAT_MES_UNKNOWN: // depends of file search
+ begin
+ if result=WAT_RES_NOTFOUND then
+ stat:=WAT_PLS_NOMUSIC
+ else
+ stat:=WAT_PLS_NORMAL;
+ end;
+ else // really, this way blocked already
+ {WAT_MES_STOPPED:} stat:=WAT_PLS_NOMUSIC;
+ end;
+ WorkSI.status:=(WorkSI.status shl 16) or (stat and $FFFF);
+
+ if OldPlayerStatus<>WorkSI.status then
+ begin
+ NotifyEventHooks(hHookWATStatus,WAT_EVENT_PLAYERSTATUS,WorkSI.status);
+ end;
+
+ // no playing file - clear all file info
+ if stat=WAT_PLS_NOMUSIC then
+ begin
+ ClearFileInfo (WorkSI,false);
+ ClearChangingInfo(WorkSI,false);
+ ClearTrackInfo (WorkSI,false);
+
+ ClearFileInfo (SongInfo,true);
+ ClearChangingInfo(SongInfo,true);
+ ClearTrackInfo (SongInfo,true);
+
+ if newplayer then
+ begin
+ ClearPlayerInfo(SongInfo,true);
+ CopyPlayerInfo (WorkSI,SongInfo);
+ end;
+ SongInfo.status:=WorkSI.status;
+ end;
+ // now time for changes (window text, volume)
+ // just when music presents
+ if stat=WAT_PLS_NORMAL then
+ begin
+ GetChangingInfo(WorkSI,flags);
+ // full info requires
+ // "no music" case blocked
+ if (result=WAT_RES_NEWFILE) or // new file
+ ((result=WAT_RES_OK) and // if not new but...
+ (((wParam and WAT_INF_CHANGES)=0) or // ... ask for full info
+ (StrPosW(WorkSI.mfile,'://')<>nil) or // ... or remote file
+ isContainer(WorkSI.mfile))) then // ... or container like CUE
+ begin
+ // requirement: old artist/title for remote files
+ stat:=GetInfo(WorkSI,flags);
+
+ // covers
+ if (WorkSI.cover=nil) or (WorkSI.cover^=#0) then
+ GetCover(WorkSI.cover,WorkSI.mfile)
+ else
+ begin
+ mGetMem(buf,MAX_PATH*SizeOf(WideChar));
+ GetTempPathW(MAX_PATH,buf);
+ if StrCmpW(buf,WorkSI.cover,StrLenW(buf))=0 then
+ begin
+ GetExt(WorkSI.cover,StrCatEW(buf,'\wat_cover.'));
+ DeleteFileW(buf);
+ MoveFileW(WorkSI.cover,buf);
+ mFreeMem(WorkSI.cover);
+ WorkSI.cover:=buf;
+ end
+ else
+ mFreeMem(buf);
+ end;
+ // lyric
+ if (WorkSI.lyric=nil) or (WorkSI.lyric^=#0) then
+ GetLyric(WorkSI.lyric,WorkSI.mfile);
+
+// file info will be updated anyway, so - just update it
+ if result=WAT_RES_NEWFILE then
+ begin
+ ClearFileInfo(SongInfo,true);
+ CopyFileInfo (WorkSI,SongInfo);
+ end;
+ ClearTrackInfo(SongInfo,true);
+ CopyTrackInfo (WorkSI,SongInfo);
+
+ if newplayer then
+ begin
+ ClearPlayerInfo(SongInfo,true);
+ CopyPlayerInfo (WorkSI,SongInfo);
+ end;
+ ClearChangingInfo(SongInfo,true);
+ CopyChangingInfo (WorkSI,SongInfo);
+ SongInfo.status:=WorkSI.status;
+
+ if stat=WAT_RES_NEWFILE then
+ result:=WAT_RES_NEWFILE;
+
+ if result=WAT_RES_NEWFILE then
+ NotifyEventHooks(hHookWATStatus,WAT_EVENT_NEWTRACK,tlparam(@SongInfo));
+ end
+ else // just changing infos
+ begin
+ if newplayer then
+ begin
+ ClearPlayerInfo(SongInfo,true);
+ CopyPlayerInfo (WorkSI,SongInfo);
+ end;
+ ClearChangingInfo(SongInfo,true);
+ CopyChangingInfo (WorkSI,SongInfo);
+ SongInfo.status:=WorkSI.status;
+ end;
+ end;
+ end;
+
+ if lParam<>0 then
+ ppointer(lParam)^:=ReturnInfo(wParam and $FF);
+ end
+ //----- Player not found -----
+ else
+ begin
+ if OldPlayerStatus<>WorkSI.status then
+ begin
+ ClearSongInfoData(WorkSI,false); // player info must be empty anyway
+ ClearSongInfoData(SongInfo,true);
+ SongInfo.status:=WAT_PLS_NOTFOUND+WAT_MES_UNKNOWN shl 16;
+
+ NotifyEventHooks(hHookWATStatus,WAT_EVENT_PLAYERSTATUS,
+ WAT_PLS_NOTFOUND+WAT_MES_UNKNOWN shl 16);
+ end;
+
+{
+ if OldPlayerStatus<>WorkSI.status then
+ begin
+ NotifyEventHooks(hHookWATStatus,WAT_EVENT_PLAYERSTATUS,
+ WAT_PLS_NOTFOUND+WAT_MES_UNKNOWN shl 16);
+ end;
+
+ ClearSongInfoData(WorkSI,false); // player info must be empty anyway
+ WorkSI.status:=WAT_PLS_NOTFOUND+WAT_MES_UNKNOWN shl 16;
+
+ ClearSongInfoData(SongInfo,true);
+ SongInfo.status:=WAT_PLS_NOTFOUND+WAT_MES_UNKNOWN shl 16;
+}
+
+ if lParam<>0 then
+ ppointer(lParam)^:=nil;
+ end;
+
+ giused:=0;
+end;
+
+function PressButton(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ flags:integer;
+begin
+ if DisablePlugin=dsPermanent then
+ result:=0
+ else
+ begin
+ flags:=0;
+ if UseImplant<>BST_UNCHECKED then flags:=flags or WAT_OPT_IMPLANTANT;
+ if mmkeyemu <>BST_UNCHECKED then flags:=flags or WAT_OPT_APPCOMMAND;
+ if CheckAll <>BST_UNCHECKED then flags:=flags or WAT_OPT_CHECKALL;
+ result:=SendCommand(wParam,lParam,flags);
+ end;
+end;
+
+function WATPluginStatus(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ f1:integer;
+begin
+ if wParam=2 then
+ begin
+ result:=PluginInfo.version;
+ exit;
+ end;
+ if DisablePlugin=dsPermanent then
+ result:=1
+ else
+ result:=0;
+ if (integer(wParam)<0) or (wParam=MenuDisablePos) then
+ begin
+ if result=0 then
+ wParam:=1
+ else
+ wParam:=0;
+ end;
+ case wParam of
+ 0: begin
+ if DisablePlugin=dsPermanent then //??
+ begin
+ StartTimer;
+ DisablePlugin:=dsEnabled;
+ end;
+ f1:=0;
+ end;
+ 1: begin
+ StopTimer;
+ DisablePlugin:=dsPermanent;
+ f1:=CMIF_CHECKED;
+ end;
+ else
+ exit;
+ end;
+ DBWriteByte(0,PluginShort,opt_disable,DisablePlugin);
+
+ ChangeMenuIcons(f1);
+
+ NotifyEventHooks(hHookWATStatus,WAT_EVENT_PLUGINSTATUS,DisablePlugin);
+end;
+
+function WaitAllModules(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ ptr:pwModule;
+begin
+ result:=0;
+
+ CallService(MS_SYSTEM_REMOVEWAIT,wParam,0);
+
+ ptr:=ModuleLink;
+ while ptr<>nil do
+ begin
+ if @ptr^.Init<>nil then
+ ptr^.ModuleStat:=ptr^.Init(true);
+ ptr:=ptr^.Next;
+ end;
+
+ if mTimer<>0 then
+ TimerProc(0,0,0,0);
+
+ StartTimer;
+
+ NotifyEventHooks(hHookWATLoaded,0,0);
+ CloseHandle(hEvent);
+end;
+
+function OnModulesLoaded(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ p:PAnsiChar;
+begin
+ UnhookEvent(onloadhook);
+
+ CallService(MS_DBEDIT_REGISTERSINGLEMODULE,twparam(PluginShort),0);
+
+ hTimer:=0;
+
+ OleInitialize(nil);
+
+ if RegisterIcons then
+ wsic:=HookEvent(ME_SKIN2_ICONSCHANGED,@IconChanged)
+ else
+ wsic:=0;
+
+ CreateMenus;
+
+ if ServiceExists(MS_TTB_ADDBUTTON)<>0 then
+ onloadhook:=HookEvent(ME_TTB_MODULELOADED,@OnTTBLoaded)
+ else
+ ttbState:=0;
+
+ ProcessFormatLink;
+ ProcessPlayerLink;
+ p:=GetAddonFileName(nil,'player','plugins','ini');
+ if p<>nil then
+ begin
+ LoadFromFile(p);
+ mFreeMem(p);
+ end;
+
+ p:=GetAddonFileName(nil,'watrack_icons','icons','dll');
+ if p<>nil then
+ begin
+ SetPlayerIcons(p);
+ mFreeMem(p);
+ end;
+
+ IsMultiThread:=true;
+
+ hEvent:=CreateEvent(nil,true,true,nil);
+ if hEvent<>0 then
+ begin
+ p:='WAT_INIT';
+ hWATI:=CreateServiceFunction(p,@WaitAllModules);
+ CallService(MS_SYSTEM_WAITONHANDLE,hEvent,tlparam(p));
+ end;
+
+ loadopt;
+ if DisablePlugin=dsPermanent then
+ CallService(MS_WAT_PLUGINSTATUS,1,0);
+
+ StartMSNHook;
+
+ result:=0;
+end;
+
+procedure FreeVariables;
+begin
+ ClearSongInfoData(SongInfo ,true);
+ ClearSongInfoData(tSongInfo(SongInfoA),true);
+ ClearSongInfoData(WorkSI ,false); // not necessary really
+ mFreeMem(CoverPaths);
+ ClearFormats;
+ ClearPlayers;
+end;
+
+procedure FreeServices;
+begin
+ DestroyServiceFunction(hGFI);
+ DestroyServiceFunction(hRGS);
+
+ DestroyServiceFunction(hWI);
+ DestroyServiceFunction(hGMI);
+ DestroyServiceFunction(hPS);
+ DestroyServiceFunction(hPB);
+ DestroyServiceFunction(hWATI);
+ DestroyServiceFunction(hWC);
+
+ DestroyServiceFunction(hFMT);
+ DestroyServiceFunction(hPLR);
+end;
+
+function PreShutdown(wParam:WPARAM;lParam:LPARAM):int;cdecl;
+var
+ buf:array [0..511] of WideChar;
+ fdata:WIN32_FIND_DATAW;
+ fi:THANDLE;
+ p:PWideChar;
+ ptr:pwModule;
+begin
+ StopMSNHook;
+
+ NotifyEventHooks(hHookWATStatus,WAT_EVENT_PLAYERSTATUS,WAT_PLS_NOTFOUND);
+
+ if hwndTooltip<>0 then
+ DestroyWindow(hwndTooltip);
+
+ if ttbState<>0 then
+ begin
+ if ServiceExists(MS_TTB_REMOVEBUTTON)>0 then
+ CallService(MS_TTB_REMOVEBUTTON,TWPARAM(ttbState),0);
+ ttbState:=0;
+ end;
+
+ StopTimer;
+ ptr:=ModuleLink;
+ while ptr<>nil do
+ begin
+ if @ptr^.DeInit<>nil then
+ ptr^.DeInit(false);
+ ptr:=ptr^.Next;
+ end;
+
+// UnhookEvent(plStatusHook);
+ UnhookEvent(hHookShutdown);
+ UnhookEvent(opthook);
+ if wsic<>0 then UnhookEvent(wsic);
+
+ FreeServices;
+ FreeVariables;
+
+ DestroyHookableEvent(hHookWATLoaded);
+ DestroyHookableEvent(hHookWATStatus);
+
+ OleUnInitialize;
+
+ //delete cover files
+ buf[0]:=#0;
+ GetTempPathW(511,buf);
+ p:=StrEndW(buf);
+ StrCopyW(p,'wat_cover.*');
+
+ fi:=FindFirstFileW(buf,fdata);
+ if fi<>THANDLE(INVALID_HANDLE_VALUE) then
+ begin
+ repeat
+ StrCopyW(p,fdata.cFileName);
+ DeleteFileW(buf);
+ until not FindNextFileW(fi,fdata);
+ FindClose(fi);
+ end;
+
+ result:=0;
+end;
+
+function Load():int; cdecl;
+begin
+ result:=0;
+ Langpack_register;
+
+ DisablePlugin:=dsPermanent;
+
+ hHookWATLoaded:=CreateHookableEvent(ME_WAT_MODULELOADED);
+ hHookWATStatus:=CreateHookableEvent(ME_WAT_NEWSTATUS);
+ hHookShutdown :=HookEvent(ME_SYSTEM_OKTOEXIT,@PreShutdown);
+ opthook :=HookEvent(ME_OPT_INITIALISE ,@OnOptInitialise);
+
+ hGFI:=CreateServiceFunction(MS_WAT_GETFILEINFO ,@WATGetFileInfo);
+ hRGS:=CreateServiceFunction(MS_WAT_RETURNGLOBAL ,@WATReturnGlobal);
+
+ hGMI:=CreateServiceFunction(MS_WAT_GETMUSICINFO ,@WATGetMusicInfo);
+ hPS :=CreateServiceFunction(MS_WAT_PLUGINSTATUS ,@WATPluginStatus);
+ hPB :=CreateServiceFunction(MS_WAT_PRESSBUTTON ,@PressButton);
+ hWI :=CreateServiceFunction(MS_WAT_WINAMPINFO ,@WinampGetInfo);
+ hWC :=CreateServiceFunction(MS_WAT_WINAMPCOMMAND,@WinampCommand);
+
+ hFMT:=CreateServiceFunction(MS_WAT_FORMAT,@ServiceFormat);
+ hPLR:=CreateServiceFunction(MS_WAT_PLAYER,@ServicePlayer);
+
+ FillChar(SongInfoA,SizeOf(SongInfoA),0);
+ FillChar(SongInfo ,SizeOf(SongInfo ),0);
+ FillChar(WorkSI ,SizeOf(SongInfo ),0);
+ onloadhook:=HookEvent(ME_SYSTEM_MODULESLOADED,@OnModulesLoaded);
+end;
+
+function Unload:int; cdecl;
+begin
+ result:=0;
+end;
+
+exports
+ Load, Unload,
+ MirandaPluginInfoEx;
+
+begin
+end.
diff --git a/plugins/Watrack/winampapi.pas b/plugins/Watrack/winampapi.pas
new file mode 100644
index 0000000000..e53e88a247
--- /dev/null
+++ b/plugins/Watrack/winampapi.pas
@@ -0,0 +1,277 @@
+{Winamp-like - base class}
+unit winampapi;
+{$include compilers.inc}
+
+interface
+
+uses windows,messages;
+
+const
+ WinampClass = 'Winamp v1.x';
+ WinampTail = ' - Winamp';
+
+function WinampGetStatus(wnd:HWND):integer;
+function WinampGetWindowText(wnd:HWND):pWideChar;
+function WinampFindWindow(wnd:HWND):HWND;
+function WinampCommand(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+function WinampGetInfo(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+
+const
+ WM_WA_IPC = WM_USER;
+ IPC_GETVERSION = 0;
+ IPC_ISPLAYING = 104;
+ IPC_GETINFO = 126;
+ IPC_GETOUTPUTTIME = 105;
+ IPC_WRITEPLAYLIST = 120;
+ IPC_GETLISTLENGTH = 124;
+ IPC_GETLISTPOS = 125;
+ IPC_ISFULLSTOP = 400; //!!
+ IPC_INETAVAILABLE = 242; //!!
+ IPC_GETPLAYLISTFILE = 211;
+
+ IPC_IS_PLAYING_VIDEO = 501;
+
+ IPC_PLAYFILE = 100;
+ IPC_STARTPLAY = 102;
+ IPC_SETVOLUME = 122; // -666 returns the current volume.
+ IPC_GET_SHUFFLE = 250;
+ IPC_SET_SHUFFLE = 252;
+ IPC_JUMPTOTIME = 106;
+
+const
+ WINAMP_PREV = 40044;
+ WINAMP_PLAY = 40045;
+ WINAMP_PAUSE = 40046;
+ WINAMP_STOP = 40047;
+ WINAMP_NEXT = 40048;
+ WINAMP_VOLUMEUP = 40058; // turns the volume up a little
+ WINAMP_VOLUMEDOWN = 40059; // turns the volume down a little
+
+implementation
+
+uses common,wat_api;
+
+function WinampFindWindow(wnd:HWND):HWND;
+var
+ pr,pr1:dword;
+begin
+ GetWindowThreadProcessId(wnd,@pr);
+ result:=0;
+ repeat
+ result:=FindWindowEx(0,result,WinampClass,nil);
+ if result<>0 then
+ begin
+ GetWindowThreadProcessId(result,@pr1);
+ if pr=pr1 then
+ break;
+ end
+ else
+ break;
+ until false;
+end;
+
+// ----------- Get player info ------------
+
+function GetVersion(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETVERSION);
+end;
+
+function GetVersionText(wnd:HWND):pWideChar;
+var
+ ver:integer;
+ s:array [0..31] of WideChar;
+ p:pWideChar;
+begin
+ ver:=GetVersion(wnd);
+ p:=@s;
+ IntToStr(p,ver shr 12);
+ while p^<>#0 do inc(p);
+ p^:='.';
+ IntToStr(p+1,(ver shr 4) and $F);
+ while p^<>#0 do inc(p);
+ p^:='.';
+ IntToStr(p+1,ver and $F);
+ StrDupW(result,PWideChar(@s));
+end;
+
+function WinampGetStatus(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,0,IPC_ISPLAYING);
+ // 0 - stopped, 1 - playing
+ if result>1 then
+ result:=WAT_MES_PAUSED;
+{
+ if result=0 then // !! only for remote media!
+ begin
+ result:=SendMessage(wnd,WM_WA_IPC,0,IPC_ISFULLSTOP);
+ if result<>0 then
+ result:=WAT_MES_STOPPED
+ else
+ result:=WAT_MES_PLAYING;
+ end;
+}
+end;
+
+function WinampGetWindowText(wnd:HWND):pWideChar;
+var
+ a:cardinal;
+ pc:pWideChar;
+begin
+ a:=GetWindowTextLengthW(wnd);
+ mGetMem(result,(a+1)*SizeOf(WideChar));
+ if GetWindowTextW(wnd,result,a+1)>0 then
+ begin
+ pc:=StrPosW(result,WinampTail);
+ if pc<>nil then
+ begin
+ pc^:=#0;
+ pc:=StrPosW(result,'. ');
+ if pc<>nil then
+ StrCopyW(result,pc+2);
+ end;
+ end;
+end;
+
+// --------- Get file info ----------
+
+function GetKbps(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,1,IPC_GETINFO);
+ if result>1000 then
+ result:=result div 1000;
+end;
+
+function GetKhz(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETINFO);
+ if result>1000 then
+ result:=result div 1000;
+end;
+
+function GetChannels(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,2,IPC_GETINFO);
+end;
+
+function GetTotalTime(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,1,IPC_GETOUTPUTTIME);
+end;
+
+function GetElapsedTime(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETOUTPUTTIME) div 1000;
+end;
+
+function GetVolume(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,-666,IPC_SETVOLUME);
+ result:=(result shl 16)+(result shr 4);
+end;
+
+function WinampGetInfo(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ wnd:HWND;
+begin
+ result:=0;
+ with pSongInfo(wParam)^ do
+ begin
+ if winampwnd<>0 then
+ wnd:=winampwnd
+ else
+ wnd:=plwnd;
+
+ if (lParam and WAT_OPT_PLAYERDATA)<>0 then
+ begin
+ if plyver=0 then
+ begin
+ plyver:=GetVersion(wnd);
+ txtver:=GetVersionText(wnd);
+ end;
+ end
+ else if (lParam and WAT_OPT_CHANGES)<>0 then
+ begin
+ volume:=GetVolume(wnd);
+ if status<>WAT_MES_STOPPED then
+ time:=GetElapsedTime(wnd);
+// wndtext:=WinampGetWindowText(wnd);
+ end
+ else
+ begin
+ if kbps =0 then kbps :=GetKbps(wnd);
+ if khz =0 then khz :=GetKhz(wnd);
+ if channels=0 then channels:=GetChannels(wnd);
+ if total =0 then total :=GetTotalTime(wnd);
+ end;
+ end;
+end;
+
+// ------- Commands ----------
+
+function Play(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_COMMAND,WINAMP_PLAY,0);
+end;
+
+function Pause(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_COMMAND,WINAMP_PAUSE,0);
+end;
+
+function Stop(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_COMMAND,WINAMP_STOP,0);
+end;
+
+function Next(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_COMMAND,WINAMP_NEXT,0);
+end;
+
+function Prev(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_COMMAND,WINAMP_PREV,0);
+end;
+
+function VolDn(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_COMMAND,WINAMP_VOLUMEDOWN,0);
+end;
+
+function VolUp(wnd:HWND):integer;
+begin
+ result:=SendMessage(wnd,WM_COMMAND,WINAMP_VOLUMEUP,0);
+end;
+
+procedure SetVolume(wnd:HWND;value:cardinal);
+begin
+ SendMessage(wnd,WM_WA_IPC,value shl 4,IPC_SETVOLUME);
+end;
+
+function Seek(wnd:HWND;value:integer):integer;
+begin
+ result:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETOUTPUTTIME) div 1000;
+ SendMessage(wnd,WM_WA_IPC,value*1000,IPC_JUMPTOTIME);
+end;
+
+function WinampCommand(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
+var
+ wnd:HWND;
+begin
+ wnd:=wParam;
+ case LoWord(lParam) of
+ WAT_CTRL_PREV : result:=Prev (wnd);
+ WAT_CTRL_PLAY : result:=Play (wnd);
+ WAT_CTRL_PAUSE: result:=Pause(wnd);
+ WAT_CTRL_STOP : result:=Stop (wnd);
+ WAT_CTRL_NEXT : result:=Next (wnd);
+ WAT_CTRL_VOLDN: result:=VolDn(wnd);
+ WAT_CTRL_VOLUP: result:=VolUp(wnd);
+ WAT_CTRL_SEEK : result:=Seek (wnd,lParam shr 16);
+ else
+ result:=0;
+ end;
+end;
+
+end.