139 lines
3.8 KiB
D
139 lines
3.8 KiB
D
module aimpremote;
|
|
|
|
import core.sys.windows.windows;
|
|
import std.typecons : Nullable;
|
|
|
|
private const wstring AIMPRemoteAccessClass = "AIMP2_RemoteInfo";
|
|
private const int AIMPRemoteAccessMapFileSize = 2048;
|
|
|
|
align(1)
|
|
private struct AIMPRemoteFileInfo
|
|
{
|
|
DWORD deprecated1;
|
|
BOOL active;
|
|
DWORD bitRate;
|
|
DWORD channels;
|
|
DWORD duration;
|
|
align(4) INT64 fileSize;
|
|
DWORD fileMark;
|
|
DWORD sampleRate;
|
|
DWORD trackNumber;
|
|
DWORD albumLength;
|
|
DWORD artistLength;
|
|
DWORD dateLength;
|
|
DWORD fileNameLength;
|
|
DWORD genreLength;
|
|
DWORD titleLength;
|
|
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
|
|
}
|
|
|
|
public struct TrackInfo {
|
|
wstring artist;
|
|
wstring title;
|
|
wstring genre;
|
|
};
|
|
|
|
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];
|
|
|
|
const wcharsize = wchar.sizeof;
|
|
auto pbuff = AIMPRemoteFileInfo.sizeof;
|
|
|
|
DWORD[TagItem] lengthInfo;
|
|
wstring[TagItem] trackInfo;
|
|
|
|
lengthInfo[TagItem.Album] = info.albumLength;
|
|
lengthInfo[TagItem.Artist] = info.artistLength;
|
|
lengthInfo[TagItem.Date] = info.dateLength;
|
|
lengthInfo[TagItem.FileName] = info.fileNameLength;
|
|
lengthInfo[TagItem.Genre] = info.genreLength;
|
|
lengthInfo[TagItem.Title] = info.titleLength;
|
|
foreach (index, immutable item; [EnumMembers!TagItem]) {
|
|
auto key = to!TagItem(index);
|
|
auto length = lengthInfo[key];
|
|
trackInfo[key] = cast(wstring)(bytes[pbuff .. (pbuff + length * wcharsize)]);
|
|
pbuff += length * wcharsize;
|
|
}
|
|
|
|
TrackInfo r = {
|
|
artist: trackInfo[TagItem.Artist],
|
|
title: trackInfo[TagItem.Title],
|
|
genre: trackInfo[TagItem.Genre]
|
|
};
|
|
result = Nullable!TrackInfo(r);
|
|
return result;
|
|
}
|
|
|
|
private static HWND findPlayerWindow() {
|
|
return FindWindow(AIMPRemoteAccessClass.ptr, null);
|
|
}
|