mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
797 lines
21 KiB
C++
797 lines
21 KiB
C++
#include "main.h"
|
|
#include "device.h"
|
|
#include "XMLString.h"
|
|
#include "api.h"
|
|
#include "../xml/obj_xml.h"
|
|
#include "../xml/ifc_xmlreaderparams.h"
|
|
#include <api/service/waServiceFactory.h>
|
|
#include "SongListDownloader.h"
|
|
#include "SongDownloader.h"
|
|
#include "RenameDownloader.h"
|
|
#include "resource.h"
|
|
#include "PlaylistSync.h"
|
|
#include "nu/AutoWide.h"
|
|
#include "images.h"
|
|
#include <mmsystem.h> // for mmioFOURCC
|
|
#include <strsafe.h>
|
|
#include <shlwapi.h>
|
|
|
|
TemplateDevice::TemplateDevice(WifiDevice *device, const char *root_url, DeviceInfo *in_device_info, TrackList *track_list, PlaylistsList *playlists_list)
|
|
: url(strdup(root_url))
|
|
{
|
|
DeviceInfo_Copy(&device_info, in_device_info);
|
|
//tracks.own(*track_list);
|
|
for (auto track : tracks)
|
|
{
|
|
delete track;
|
|
}
|
|
tracks.clear();
|
|
tracks.assign(track_list->begin(), track_list->end());
|
|
track_list->clear();
|
|
|
|
|
|
//playlists.own(*playlists_list);
|
|
for (auto playlist : playlists)
|
|
{
|
|
delete playlist;
|
|
}
|
|
playlists.clear();
|
|
playlists.assign(playlists_list->begin(), playlists_list->end());
|
|
playlists_list->clear();
|
|
|
|
transcoder=0;
|
|
transferQueueLength=0;
|
|
|
|
transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
|
|
if(transcoder)
|
|
{
|
|
transcoder->AddAcceptableFormat(L"m4a");
|
|
transcoder->AddAcceptableFormat(L"mp3");
|
|
transcoder->AddAcceptableFormat(L"wav");
|
|
transcoder->AddAcceptableFormat(L"m4v");
|
|
transcoder->AddAcceptableFormat(L"mp4");
|
|
transcoder->AddAcceptableFormat(L"avi");
|
|
transcoder->AddAcceptableFormat(L"3gp");
|
|
transcoder->AddAcceptableFormat(L"mid");
|
|
transcoder->AddAcceptableFormat(L"ogg");
|
|
}
|
|
}
|
|
|
|
TemplateDevice::~TemplateDevice()
|
|
{
|
|
free(url);
|
|
|
|
//tracks.deleteAll();
|
|
for (auto track : tracks)
|
|
{
|
|
delete track;
|
|
}
|
|
tracks.clear();
|
|
|
|
//playlists.deleteAll();
|
|
for (auto playlist : playlists)
|
|
{
|
|
delete playlist;
|
|
}
|
|
playlists.clear();
|
|
|
|
if (transcoder)
|
|
SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
|
|
transcoder=0;
|
|
|
|
}
|
|
|
|
__int64 TemplateDevice::getDeviceCapacityAvailable() // in bytes
|
|
{
|
|
return device_info.total_space - device_info.used_space;
|
|
}
|
|
|
|
__int64 TemplateDevice::getDeviceCapacityTotal()
|
|
{
|
|
return device_info.total_space;
|
|
}
|
|
|
|
void TemplateDevice::Eject()
|
|
{
|
|
SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
|
|
}
|
|
|
|
void TemplateDevice::Close()
|
|
{
|
|
SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
|
|
}
|
|
|
|
void TemplateDevice::CloseAsync()
|
|
{
|
|
PostMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
|
|
}
|
|
|
|
int PostFile(const char *url, const wchar_t *filename, const itemRecordW *track, obj_xml *parser, int *killswitch,
|
|
void (*callback)(void *callbackContext, wchar_t *status), void *context, char *new_item_id, size_t new_item_id_len);
|
|
|
|
int PostAlbumArt(const char *url, const itemRecordW *track, obj_xml *parser, int *killswitch, void (*callback)(void *callbackContext, wchar_t *status), void *context);
|
|
|
|
|
|
static int64_t FileSize64(const wchar_t * filename)
|
|
{
|
|
WIN32_FIND_DATA f={0};
|
|
HANDLE h = FindFirstFileW(filename,&f);
|
|
if(h == INVALID_HANDLE_VALUE) return -1;
|
|
FindClose(h);
|
|
ULARGE_INTEGER i;
|
|
i.HighPart = f.nFileSizeHigh;
|
|
i.LowPart = f.nFileSizeLow;
|
|
return i.QuadPart;
|
|
}
|
|
|
|
// return 0 for success, -1 for failed or cancelled
|
|
int TemplateDevice::transferTrackToDevice(const itemRecordW *track, // the track to transfer
|
|
void * callbackContext, //pass this to the callback
|
|
void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
|
|
songid_t * songid, // fill in the songid when you are finished
|
|
int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
|
|
)
|
|
{
|
|
wchar_t newfile[MAX_PATH] = {0};
|
|
wchar_t *filename = track->filename;
|
|
bool delete_file = false;
|
|
if(transcoder && transcoder->ShouldTranscode(track->filename))
|
|
{
|
|
wchar_t ext[10] = {0};
|
|
int r = transcoder->CanTranscode(track->filename, ext, track->length);
|
|
if(r != 0 && r != -1)
|
|
{
|
|
transcoder->GetTempFilePath(ext,newfile);
|
|
if(transcoder->TranscodeFile(track->filename,newfile,killswitch,callback,callbackContext)) return -1;
|
|
filename = newfile;
|
|
delete_file=true;
|
|
}
|
|
}
|
|
|
|
char new_item_id[512] = {0};
|
|
char upload_url[555] = {0};
|
|
StringCbPrintfA(upload_url, sizeof(upload_url), "%s/upload", url);
|
|
if (PostFile(upload_url, filename, track, 0, killswitch, callback, callbackContext, new_item_id, 512) == 0 && new_item_id[0])
|
|
{
|
|
StringCbPrintfA(upload_url, sizeof(upload_url), "%s/albumart/%s", url, new_item_id);
|
|
PostAlbumArt(upload_url, track, 0, killswitch, callback, callbackContext);
|
|
callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_COMPLETED));
|
|
WifiTrack *new_track = new WifiTrack(new_item_id, track, filename);
|
|
*songid = (songid_t)new_track;
|
|
device_info.used_space += FileSize64(filename); // TODO: count album art also. or re-query for device info
|
|
if (delete_file)
|
|
DeleteFile(filename);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
callback(callbackContext, L"Failed");
|
|
if (delete_file)
|
|
DeleteFile(filename);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int TemplateDevice::trackAddedToTransferQueue(const itemRecordW *track)
|
|
{
|
|
// return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
|
|
__int64 l;
|
|
if(transcoder && transcoder->ShouldTranscode(track->filename))
|
|
{
|
|
int k = transcoder->CanTranscode(track->filename, 0, track->length);
|
|
if(k == -1) return -2;
|
|
if(k == 0) l = (__int64)FileSize64(track->filename);
|
|
else l = (__int64)k;
|
|
}
|
|
else
|
|
{
|
|
l = FileSize64(track->filename);
|
|
}
|
|
int64_t avail = getDeviceCapacityAvailable();
|
|
int64_t cmp = transferQueueLength;
|
|
cmp += l;
|
|
cmp += 3000000LL;
|
|
|
|
if(cmp > avail)
|
|
return -1;
|
|
else
|
|
{
|
|
transferQueueLength += l;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void TemplateDevice::trackRemovedFromTransferQueue(const itemRecordW *track)
|
|
{
|
|
int64_t l = FileSize64(track->filename);
|
|
if(transcoder && transcoder->ShouldTranscode(track->filename))
|
|
{
|
|
int k = transcoder->CanTranscode(track->filename, 0, track->length);
|
|
if(k != -1 && k != 0) l = (__int64)k;
|
|
}
|
|
transferQueueLength -= l;
|
|
|
|
}
|
|
|
|
// return the amount of space that will be taken up on the device by the track (once it has been tranferred)
|
|
// or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
|
|
__int64 TemplateDevice::getTrackSizeOnDevice(const itemRecordW *track)
|
|
{
|
|
if(transcoder && transcoder->ShouldTranscode(track->filename))
|
|
{
|
|
int k = transcoder->CanTranscode(track->filename, 0, track->length);
|
|
if(k != -1 && k != 0) return k;
|
|
}
|
|
return track->filesize;
|
|
}
|
|
|
|
int HTTP_Delete(const char *url);
|
|
void TemplateDevice::deleteTrack(songid_t songid)
|
|
{
|
|
// physically remove from device. Be sure to remove it from all the playlists!
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
char delete_url[1024] = {0};
|
|
StringCbPrintfA(delete_url, sizeof(delete_url), "%s/file/%S", url, track->id);
|
|
HTTP_Delete(delete_url);
|
|
again1:
|
|
for (WifiPlaylist::TrackList::iterator itr2=tracks.begin(); itr2 != tracks.end(); itr2++)
|
|
{
|
|
WifiTrack *trackitr = *itr2;
|
|
if (!wcscmp(trackitr->id, track->id))
|
|
{
|
|
tracks.erase(itr2);
|
|
if (trackitr != track)
|
|
delete trackitr;
|
|
goto again1; // iterator was invalidated
|
|
}
|
|
}
|
|
|
|
for (PlaylistsList::iterator itr=playlists.begin();itr!=playlists.end();itr++)
|
|
{
|
|
WifiPlaylist *playlist = *itr;
|
|
again2:
|
|
for (WifiPlaylist::TrackList::iterator itr2=playlist->tracks.begin(); itr2 != playlist->tracks.end(); itr2++)
|
|
{
|
|
WifiTrack *trackitr = *itr2;
|
|
if (!wcscmp(trackitr->id, track->id))
|
|
{
|
|
playlist->tracks.erase(itr2);
|
|
if (trackitr != track)
|
|
delete trackitr;
|
|
goto again2; // iterator was invalidated
|
|
}
|
|
}
|
|
}
|
|
delete track;
|
|
}
|
|
|
|
|
|
void TemplateDevice::commitChanges()
|
|
{
|
|
// optional. Will be called at a good time to save changes
|
|
}
|
|
|
|
int TemplateDevice::getPlaylistCount()
|
|
{
|
|
// always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
|
|
return 1 + (int)playlists.size();
|
|
}
|
|
|
|
// PlaylistName(0) should return the name of the device.
|
|
void TemplateDevice::getPlaylistName(int playlistnumber, wchar_t *buf, int len)
|
|
{
|
|
if (playlistnumber == 0)
|
|
{
|
|
StringCchCopy(buf, len, device_info.name);
|
|
}
|
|
else
|
|
{
|
|
WifiPlaylist *playlist = playlists[playlistnumber-1];
|
|
StringCchCopy(buf, len, playlist->name);
|
|
}
|
|
|
|
}
|
|
int TemplateDevice::getPlaylistLength(int playlistnumber)
|
|
{
|
|
if (playlistnumber == 0)
|
|
{
|
|
size_t size = tracks.size();
|
|
return (int)size;
|
|
}
|
|
else
|
|
{
|
|
WifiPlaylist *playlist = playlists[playlistnumber-1];
|
|
size_t size = playlist->tracks.size();
|
|
return (int)size;
|
|
}
|
|
}
|
|
|
|
songid_t TemplateDevice::getPlaylistTrack(int playlistnumber,int songnum)
|
|
{
|
|
if (playlistnumber == 0)
|
|
{
|
|
WifiTrack *track = tracks[songnum];
|
|
return (songid_t)track;
|
|
}
|
|
else
|
|
{
|
|
WifiPlaylist *playlist = playlists[playlistnumber-1];
|
|
WifiTrack *track = playlist->tracks[songnum];
|
|
return (songid_t)track;
|
|
}
|
|
|
|
}
|
|
|
|
void TemplateDevice::setPlaylistName(int playlistnumber, const wchar_t *buf)
|
|
{
|
|
if (playlistnumber == 0) // playlist 0 is the device itself
|
|
{
|
|
RenameDevice(url, buf);
|
|
StringCbCopy(device_info.name, sizeof(device_info.name), buf);
|
|
}
|
|
else
|
|
{
|
|
WifiPlaylist *playlist = playlists[playlistnumber-1];
|
|
playlist->SetName(buf);
|
|
Sync_RenamePlaylist(url, playlist->id, buf);
|
|
}
|
|
}
|
|
|
|
void TemplateDevice::playlistSwapItems(int playlistnumber, int posA, int posB)
|
|
{
|
|
// swap the songs at position posA and posB
|
|
// TODO: implement
|
|
}
|
|
|
|
void TemplateDevice::sortPlaylist(int playlistnumber, int sortBy)
|
|
{
|
|
// TODO: implement
|
|
}
|
|
|
|
void TemplateDevice::addTrackToPlaylist(int playlistnumber, songid_t songid)
|
|
{
|
|
// adds songid to the end of the playlist
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
if (playlistnumber == 0)
|
|
{
|
|
tracks.push_back(track);
|
|
}
|
|
else
|
|
{
|
|
playlists[playlistnumber - 1]->tracks.push_back(new WifiTrack(*track));
|
|
Sync_AddToPlaylist(url, playlists[playlistnumber-1]->id, track->id);
|
|
}
|
|
|
|
}
|
|
|
|
void TemplateDevice::removeTrackFromPlaylist(int playlistnumber, int songnum)
|
|
{
|
|
//where songnum is the position of the track in the playlist
|
|
if (playlistnumber == 0)
|
|
{
|
|
tracks.erase(tracks.begin() + songnum);
|
|
}
|
|
else
|
|
{
|
|
WifiPlaylist *playlist = playlists[playlistnumber-1];
|
|
WifiTrack *track = playlist->tracks[songnum];
|
|
Sync_RemoveFromPlaylist(url, playlist->id, track->id);
|
|
}
|
|
}
|
|
|
|
void TemplateDevice::deletePlaylist(int playlistnumber)
|
|
{
|
|
if (playlistnumber == 0)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
WifiPlaylist *playlist = playlists[playlistnumber-1];
|
|
Sync_DeletePlaylist(url, playlist->id);
|
|
playlists.erase(playlists.begin() + playlistnumber-1);
|
|
}
|
|
}
|
|
|
|
int TemplateDevice::newPlaylist(const wchar_t *name)
|
|
{
|
|
// create empty playlist, returns playlistnumber. -1 for failed.
|
|
WifiPlaylist *new_playlist = Sync_NewPlaylist(url, name);
|
|
if (new_playlist)
|
|
{
|
|
playlists.push_back(new_playlist);
|
|
return (int)playlists.size();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void TemplateDevice::getTrackArtist(songid_t songid, wchar_t *buf, int len)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
StringCchCopy(buf, len, track->artist);
|
|
}
|
|
|
|
void TemplateDevice::getTrackAlbum(songid_t songid, wchar_t *buf, int len)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
StringCchCopy(buf, len, track->album);
|
|
}
|
|
|
|
void TemplateDevice::getTrackTitle(songid_t songid, wchar_t *buf, int len)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
StringCchCopy(buf, len, track->title);
|
|
}
|
|
|
|
int TemplateDevice::getTrackTrackNum(songid_t songid)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
return track->track;
|
|
}
|
|
int TemplateDevice::getTrackDiscNum(songid_t songid)
|
|
{
|
|
// TODO: implement
|
|
return 0;
|
|
}
|
|
void TemplateDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len)
|
|
{
|
|
buf[0]=0;
|
|
}
|
|
|
|
int TemplateDevice::getTrackYear(songid_t songid)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
return track->year;
|
|
}
|
|
|
|
__int64 TemplateDevice::getTrackSize(songid_t songid)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
return track->size;
|
|
}
|
|
|
|
int TemplateDevice::getTrackLength(songid_t songid)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
return track->duration;
|
|
}
|
|
|
|
int TemplateDevice::getTrackBitrate(songid_t songid)
|
|
{
|
|
return 128;
|
|
}
|
|
|
|
int TemplateDevice::getTrackPlayCount(songid_t songid)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int TemplateDevice::getTrackRating(songid_t songid)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
__time64_t TemplateDevice::getTrackLastPlayed(songid_t songid)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
__time64_t TemplateDevice::getTrackLastUpdated(songid_t songid)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
return track->last_updated;
|
|
}
|
|
|
|
void TemplateDevice::getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len)
|
|
{
|
|
buf[0]=0;
|
|
}
|
|
|
|
void TemplateDevice::getTrackPublisher(songid_t songid, wchar_t *buf, int len)
|
|
{
|
|
buf[0]=0;
|
|
}
|
|
|
|
void TemplateDevice::getTrackComposer(songid_t songid, wchar_t *buf, int len)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)songid;
|
|
StringCchCopy(buf, len, track->composer);
|
|
}
|
|
|
|
int TemplateDevice::getTrackType(songid_t songid)
|
|
{
|
|
return 0;
|
|
}
|
|
void TemplateDevice::getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len)
|
|
{
|
|
// TODO: implement
|
|
//optional
|
|
}
|
|
|
|
// feel free to ignore any you don't support
|
|
void TemplateDevice::setTrackArtist(songid_t songid, const wchar_t *value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackAlbum(songid_t songid, const wchar_t *value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackTitle(songid_t songid, const wchar_t *value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackTrackNum(songid_t songid, int value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackDiscNum(songid_t songid, int value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackGenre(songid_t songid, const wchar_t *value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackYear(songid_t songid, int year)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackPlayCount(songid_t songid, int value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackRating(songid_t songid, int value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackLastPlayed(songid_t songid, __time64_t value)
|
|
{
|
|
// TODO: implement
|
|
|
|
} // in unix time format
|
|
void TemplateDevice::setTrackLastUpdated(songid_t songid, __time64_t value)
|
|
{
|
|
// TODO: implement
|
|
|
|
} // in unix time format
|
|
void TemplateDevice::setTrackAlbumArtist(songid_t songid, const wchar_t *value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackPublisher(songid_t songid, const wchar_t *value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackComposer(songid_t songid, const wchar_t *value)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value)
|
|
{
|
|
// TODO: implement
|
|
|
|
} //optional
|
|
|
|
bool TemplateDevice::playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue)
|
|
{
|
|
if(!enqueue) //clear playlist
|
|
{
|
|
SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
|
|
}
|
|
|
|
for(int i=0; i<listLength; i++)
|
|
{
|
|
WifiTrack*curSong = (WifiTrack *)songidList[i];
|
|
|
|
if (curSong)
|
|
{
|
|
wchar_t fn[1024] = {0};
|
|
|
|
if (curSong->mime_type && !_wcsicmp(curSong->mime_type, L"audio/mp4"))
|
|
StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.m4a", url, curSong->id);
|
|
else if (curSong->mime_type && !_wcsicmp(curSong->mime_type, L"audio/x-ms-wma"))
|
|
StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.wma", url, curSong->id);
|
|
else if (curSong->mime_type && (!_wcsicmp(curSong->mime_type, L"application/ogg") || !_wcsicmp(curSong->mime_type, L"audio/ogg")))
|
|
StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.ogg", url, curSong->id);
|
|
else
|
|
StringCbPrintf(fn, sizeof(fn), L"%S/file/%s", url, curSong->id);
|
|
enqueueFileWithMetaStructW s={0};
|
|
s.filename = fn;
|
|
s.title = _wcsdup(curSong->title);
|
|
s.ext = NULL;
|
|
s.length = curSong->duration/1000;
|
|
|
|
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
|
|
}
|
|
else
|
|
{
|
|
//char titleStr[32];
|
|
//MessageBoxA(plugin.hwndWinampParent,WASABI_API_LNGSTRING(IDS_CANNOT_OPEN_FILE),
|
|
// WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32),0);
|
|
}
|
|
}
|
|
|
|
if(!enqueue)
|
|
{
|
|
//play item startPlaybackAt
|
|
SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startPlaybackAt,IPC_SETPLAYLISTPOS);
|
|
SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
|
|
SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static const intptr_t encoder_blacklist[] =
|
|
{
|
|
mmioFOURCC('W','M','A',' '),
|
|
mmioFOURCC('A','A','C','H'),
|
|
mmioFOURCC('A','A','C','P'),
|
|
mmioFOURCC('A','A','C','r'),
|
|
mmioFOURCC('F','L','A','C'),
|
|
mmioFOURCC('M','P','2',' '),
|
|
mmioFOURCC('A','D','T','S'),
|
|
};
|
|
|
|
|
|
intptr_t TemplateDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4)
|
|
{
|
|
switch(param1)
|
|
{
|
|
case DEVICE_SET_ICON: // icons
|
|
{
|
|
MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
|
|
const ModelInfo *modelInfo;
|
|
i->hinst = plugin.hDllInstance;
|
|
|
|
modelInfo = device_info.modelInfo;
|
|
if (NULL == modelInfo || NULL == modelInfo->smallIcon)
|
|
{
|
|
modelInfo = GetDefaultModelInfo();
|
|
if (NULL == modelInfo)
|
|
break;
|
|
}
|
|
|
|
i->resourceId = (int)(intptr_t)modelInfo->smallIcon;
|
|
}
|
|
break;
|
|
case DEVICE_CAN_RENAME_DEVICE:
|
|
return 1;
|
|
case DEVICE_GET_ICON:
|
|
ModelInfo_GetIconPath(device_info.modelInfo, (int)param2, (int)param3, (wchar_t*)param4, 260, TRUE);
|
|
break;
|
|
case DEVICE_GET_CONNECTION_TYPE:
|
|
{
|
|
const char **type = (const char **)param2;
|
|
*type = "WiFi";
|
|
return 1;
|
|
}
|
|
case DEVICE_SUPPORTS_PODCASTS:
|
|
return 1; // we don't support podcasts
|
|
case DEVICE_GET_MODEL:
|
|
ModelInfo_CopyDisplayName(device_info.modelInfo, (wchar_t*)param2, param3);
|
|
return 1;
|
|
case DEVICE_SUPPORTED_METADATA:
|
|
{
|
|
intptr_t supported = SUPPORTS_ARTIST | SUPPORTS_ALBUM | SUPPORTS_TITLE | SUPPORTS_TRACKNUM /*| SUPPORTS_DISCNUM | SUPPORTS_GENRE */|
|
|
SUPPORTS_YEAR | SUPPORTS_SIZE | SUPPORTS_LENGTH /*| SUPPORTS_BITRATE */| SUPPORTS_LASTUPDATED /*| SUPPORTS_ALBUMARTIST */|
|
|
SUPPORTS_COMPOSER /*| SUPPORTS_PUBLISHER | SUPPORTS_ALBUMART*/;
|
|
return supported;
|
|
}
|
|
break;
|
|
case DEVICE_VETO_ENCODER:
|
|
{
|
|
for (size_t i=0;i<sizeof(encoder_blacklist)/sizeof(*encoder_blacklist);i++)
|
|
{
|
|
if (param2 == encoder_blacklist[i])
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// TODO: implement more
|
|
return 0;
|
|
}
|
|
|
|
bool TemplateDevice::copyToHardDriveSupported()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
__int64 TemplateDevice::songSizeOnHardDrive(songid_t song)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)song;
|
|
return track->size;
|
|
}
|
|
|
|
int TemplateDevice::copyToHardDrive(songid_t song, // the song to copy
|
|
wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
|
|
void * callbackContext, //pass this to the callback
|
|
void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
|
|
int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
|
|
)
|
|
{
|
|
WifiTrack *track = (WifiTrack *)song;
|
|
char download_url[1024] = {0};
|
|
StringCbPrintfA(download_url, sizeof(download_url), "%s/file/%S", url, track->id);
|
|
HANDLE event = CreateEvent(0, FALSE, FALSE, 0);
|
|
|
|
if (!_wcsicmp(track->mime_type, L"audio/mpeg"))
|
|
wcsncat(path, L".mp3", MAX_PATH);
|
|
else if (!_wcsicmp(track->mime_type, L"audio/mp4"))
|
|
wcsncat(path, L".m4a", MAX_PATH);
|
|
else if (!_wcsicmp(track->mime_type, L"audio/x-ms-wma"))
|
|
wcsncat(path, L".wma", MAX_PATH);
|
|
else if (!_wcsicmp(track->mime_type, L"application/ogg") || !_wcsicmp(track->mime_type, L"audio/ogg") )
|
|
wcsncat(path, L".ogg", MAX_PATH);
|
|
// TODO: more
|
|
|
|
SongDownloader *song_downloader = new SongDownloader(path, event, callback, callbackContext);
|
|
song_downloader->AddRef();
|
|
WAC_API_DOWNLOADMANAGER->DownloadEx(download_url, song_downloader, api_downloadManager::DOWNLOADEX_CALLBACK);
|
|
WaitForSingleObject(event, INFINITE);
|
|
song_downloader->Release();
|
|
return 0; // TODO: check error code
|
|
}
|
|
|
|
// art functions
|
|
void TemplateDevice::setArt(songid_t songid, void *buf, int w, int h)
|
|
{
|
|
//buf is in format ARGB32*
|
|
// TODO: implement
|
|
|
|
}
|
|
|
|
pmpart_t TemplateDevice::getArt(songid_t songid)
|
|
{
|
|
// TODO: implement
|
|
return 0;
|
|
}
|
|
|
|
void TemplateDevice::releaseArt(pmpart_t art)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
int TemplateDevice::drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h)
|
|
{
|
|
// TODO: implement
|
|
return 0;
|
|
}
|
|
|
|
void TemplateDevice::getArtNaturalSize(pmpart_t art, int *w, int *h)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::setArtNaturalSize(pmpart_t art, int w, int h)
|
|
{
|
|
// TODO: implement
|
|
|
|
}
|
|
void TemplateDevice::getArtData(pmpart_t art, void* data)
|
|
{
|
|
// data ARGB32* is at natural size
|
|
// TODO: implement
|
|
}
|
|
|
|
bool TemplateDevice::artIsEqual(pmpart_t a, pmpart_t b)
|
|
{
|
|
// TODO: implement
|
|
return false;
|
|
}
|
|
|