diff --git a/source/aimpremote/aimpremote.d b/source/aimpremote/aimpremote.d index f37116f..a119a4b 100644 --- a/source/aimpremote/aimpremote.d +++ b/source/aimpremote/aimpremote.d @@ -1,6 +1,7 @@ module aimpremote; import core.sys.windows.windows; +import std.typecons : Nullable; private const wstring AIMPRemoteAccessClass = "AIMP2_RemoteInfo"; private const int AIMPRemoteAccessMapFileSize = 2048; @@ -26,6 +27,21 @@ private struct AIMPRemoteFileInfo DWORD[6] deprecated2; }; +private const int WM_AIMP_COMMAND = WM_USER + 0x75; +private const int WM_AIMP_NOTIFY = WM_USER + 0x76; +private const int WM_AIMP_PROPERTY = WM_USER + 0x77; + +private const int AIMP_RA_PROPVALUE_GET = 0; +private const int AIMP_RA_PROPVALUE_SET = 1; +private const int AIMP_RA_PROPERTY_MASK = 0xFFFFFFF0; + +private const int AIMP_RA_PROPERTY_PLAYER_STATE = 0x40; +private const int AIMP_RA_PROPERTY_VOLUME = 0x50; + +private const int AIMP_RA_CMD_BASE = 10; +private const int AIMP_RA_CMD_NEXT = AIMP_RA_CMD_BASE + 7; +private const int AIMP_RA_CMD_PREV = AIMP_RA_CMD_BASE + 8; + private enum TagItem { Album, Artist, Date, FileName, Genre, Title } @@ -36,12 +52,55 @@ public struct TrackInfo { wstring genre; }; -public static TrackInfo getInfo() { +public enum PlayerState { + Off, Stopped, Paused, Playing +} + +public static PlayerState getPlayerState() { + auto hwnd = findPlayerWindow(); + if (hwnd == null) { + return PlayerState.Off; + } + + const auto state = SendMessage(hwnd, WM_AIMP_PROPERTY, + AIMP_RA_PROPERTY_PLAYER_STATE | AIMP_RA_PROPVALUE_GET, 0); + switch (state) { + default: return PlayerState.Stopped; + case 1: return PlayerState.Paused; + case 2: return PlayerState.Playing; + } +} + +public static void setVolume(ubyte volume) { + auto hwnd = findPlayerWindow(); + if (hwnd != null) { + SendMessage(hwnd, WM_AIMP_PROPERTY, + AIMP_RA_PROPERTY_VOLUME | AIMP_RA_PROPVALUE_SET, volume); + } +} + +public static void nextTrack() { + auto hwnd = findPlayerWindow(); + if (hwnd != null) { + SendMessage(hwnd, WM_AIMP_COMMAND, AIMP_RA_CMD_NEXT, 0); + } +} + +public static Nullable!TrackInfo getInfo() { import std.conv : to; import std.traits : EnumMembers; + Nullable!TrackInfo result = Nullable!TrackInfo.init; auto haimp = OpenFileMapping(FILE_MAP_READ, 0, AIMPRemoteAccessClass.ptr); + if (haimp == null) { + result.nullify(); + return result; + } const auto hfilemap = MapViewOfFile(haimp, FILE_MAP_READ, 0, 0, AIMPRemoteAccessMapFileSize); + if (hfilemap == null) { + result.nullify(); + return result; + } AIMPRemoteFileInfo* info = cast(AIMPRemoteFileInfo*) hfilemap; auto bytes = (cast(ubyte*) hfilemap)[0 .. AIMPRemoteAccessMapFileSize]; @@ -65,11 +124,12 @@ public static TrackInfo getInfo() { pbuff += length * wcharsize; } - TrackInfo result = { + TrackInfo r = { artist: trackInfo[TagItem.Artist], title: trackInfo[TagItem.Title], genre: trackInfo[TagItem.Genre] }; + result = Nullable!TrackInfo(r); return result; } @@ -86,7 +146,7 @@ private static HWND findPlayerWindow() { AIMPRemoteFileInfo* info = cast(AIMPRemoteFileInfo*) hfilemap; write("Bitrate: "); writeln(info.bitRate); - write("Samplerate: "); + write("Samlerate: "); writeln(info.sampleRate); write("fileSize: "); writeln(info.fileSize); diff --git a/source/app.d b/source/app.d index c2a7f31..611c6a4 100644 --- a/source/app.d +++ b/source/app.d @@ -10,6 +10,10 @@ void main() http.handle.set(CurlOption.ssl_verifypeer, 0); auto track = getInfo(); + if (track.isNull) { + writeln("No data"); + return; + } auto content = post("https://annimon.com/json/nowplay", [ "login" : "test",