From aa323ee11bf075faaa16d7a0ad7baade71adfc25 Mon Sep 17 00:00:00 2001
From: _ <🐱>
Date: Wed, 2 Dec 2020 15:21:28 -0700
Subject: [PATCH] Add tagging support & warn on unsupported bitrate
---
README.md | 8 +-
SpotifyKeyDumper/Hooks.cpp | 68 +++++-
SpotifyKeyDumper/SpotifyKeyDumper.vcxproj | 3 +
SpotifyKeyDumper/Utils.cpp | 254 ++++++++++++++++------
SpotifyKeyDumper/Utils.h | 2 +-
SpotifyKeyDumper/pch.h | 7 +
6 files changed, 272 insertions(+), 70 deletions(-)
diff --git a/README.md b/README.md
index df9baeb..3577d75 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,13 @@ Spotify version:
* ~~1.1.25~~
## Building
-This project uses C++14 on Visual Studio 2019.
+This project uses C++14 on Visual Studio 2019 with vcpkg:
+1. [Install vcpkg](https://github.com/microsoft/vcpkg#quick-start-windows) if you haven't done so already
+2. Install TagLib dependency with vcpkg (`vcpkg install taglib:x86-windows-static-md`)
+3. Clone the repository (`git clone https://gitlab.com/fuck-capitalism/spotifykeydumper.git`)
+4. Open the solution 'SpotifyKeyDumper.sln' in Visual Studio 2019 and set the configuration to Release and the
+platform to x86 and then select Build -> Build Solution **or** run MSBuild (requires Visual Studio 2019 installation):
+`msbuild /p:Configuration="Release" /p:Platform="x86"`.
*If you want a specific version, create an issue.*
diff --git a/SpotifyKeyDumper/Hooks.cpp b/SpotifyKeyDumper/Hooks.cpp
index 91c2ae3..c156e72 100644
--- a/SpotifyKeyDumper/Hooks.cpp
+++ b/SpotifyKeyDumper/Hooks.cpp
@@ -37,10 +37,14 @@ uriHandler_v47 uriHandler_v47_hook = nullptr;
typedef bool (__cdecl* isValidUrl_v25)(int* urlThingArg, int a2);
isValidUrl_v25 isValidUrl_v25_hook = nullptr;
+typedef int (__cdecl* getBitrate_v25)(int quality);
+getBitrate_v25 getBitrate_v25_hook = nullptr;
+
std::string authToken = std::string();
std::string keyStr = std::string();
std::string uriStr = std::string();
std::string fileId = std::string();
+int quality = 4;
__int64 newPosition = 0;
bool signalled = false;
@@ -54,7 +58,7 @@ void TryDownload()
{
signalled = false;
lastUri = uriStr;
- std::thread t2(Utils::DownloadSong, std::string(fileId), uriStr, keyStr, authToken);
+ std::thread t2(Utils::DownloadSong, std::string(fileId), uriStr, keyStr, authToken, quality);
t2.detach();
}
}
@@ -63,7 +67,7 @@ int __cdecl keyToLE_hook_v25(unsigned int* dest, int* key, int bits)
{
if (bits == 128)
{
- BYTE keyBuffer[16];
+ BYTE keyBuffer[16] = {};
BYTE* keyBufPtr = keyBuffer;
memcpy(keyBufPtr, key, 16);
@@ -88,7 +92,7 @@ int __cdecl keyToLE_hook_v28(unsigned int* dest, int* key, int bits, bool isEnco
{
// key is encoded with some sort of algorithm; decode it here
- unsigned int keyDecoded[4];
+ unsigned int keyDecoded[4] = {};
unsigned int uVar1;
unsigned int keyPtr;
unsigned int uVar3;
@@ -118,7 +122,7 @@ int __cdecl keyToLE_hook_v28(unsigned int* dest, int* key, int bits, bool isEnco
}
// Copy key bytes to new buffer
- char keyBuffer[16];
+ char keyBuffer[16] = {};
char* keyBufPtr = keyBuffer;
memcpy(keyBufPtr, decodedKeyPtr, 16);
@@ -331,6 +335,57 @@ bool __cdecl isValidUrl_hook_v25(int* urlThingArg, int arg_4)
return isValidUrl_v25_hook(urlThingArg, arg_4);
}
+// TODO: Fix downloads on low quality and very high quality to get rid of this
+bool hasAlertedQuality = false;
+int __cdecl getBitrate_hook_v25(int quality)
+{
+ // Force quality to be normal or high quality (since other modes do not reliably work)
+ // (no, forcing it to very high on a free account does not work)
+
+ /*switch (quality)
+ {
+ case 0: // Automatic
+ quality = 3;
+ break;
+ case 1: // Low
+ quality = 2;
+ break;
+ case 4: // Very high
+ quality = 3;
+ break;
+ }*/
+
+ std::string qualityStr = "?";
+ switch (quality)
+ {
+ case 0:
+ qualityStr = "Automatic";
+ break;
+ case 1:
+ qualityStr = "Low";
+ break;
+ case 2:
+ qualityStr = "Normal";
+ break;
+ case 3:
+ qualityStr = "High";
+ break;
+ case 4:
+ qualityStr = "Very High";
+ break;
+ }
+
+ if (!hasAlertedQuality && quality != 2 && quality != 3)
+ {
+ std::cout << "Warning! You have selected an unsupported quality (" + qualityStr + "); select Normal or High"
+ " quality in the Spotify settings for proper compatibility." << std::endl;
+ hasAlertedQuality = true;
+ }
+
+ ::quality = quality;
+
+ return getBitrate_v25_hook(quality);
+}
char* GetKeyFuncAddrV26()
{
@@ -407,7 +462,8 @@ void Hooks::Init()
fileIdWriter_v45_hook = (fileIdWriter_v45)Utils::TrampHook32((char*)0x00CBB560, (char*)fileIdWriter_hook_v45,
5);
signalEmitter_v45_hook = (signalEmitter_v45)Utils::TrampHook32((char*)0x00B095A0, (char*)signalEmitter_hook_v45,
- 5);
+ 5); // 00E48410
+ getBitrate_v25_hook = (getBitrate_v25)Utils::TrampHook32((char*)0x00E48410, (char*)getBitrate_hook_v25, 6);
break;
case 46:
keyToLE_v28_hook = (keyToLE_v28)Utils::TrampHook32((char*)0x010C2FB0, (char*)keyToLE_hook_v28, 6);
@@ -417,6 +473,7 @@ void Hooks::Init()
5);
signalEmitter_v45_hook = (signalEmitter_v45)Utils::TrampHook32((char*)0x00B02270, (char*)signalEmitter_hook_v45,
5);
+ getBitrate_v25_hook = (getBitrate_v25)Utils::TrampHook32((char*)0x00E3C780, (char*)getBitrate_hook_v25, 6);
break;
case 47:
keyBuffer_v47 = new char[16]; // 128 bits = 16 bytes
@@ -428,6 +485,7 @@ void Hooks::Init()
5);
signalEmitter_v45_hook = (signalEmitter_v45)Utils::TrampHook32((char*)0x00AFBB50, (char*)signalEmitter_hook_v45,
5);
+ getBitrate_v25_hook = (getBitrate_v25)Utils::TrampHook32((char*)0x00E3E460, (char*)getBitrate_hook_v25, 6);
//startUpdate_v47_hook = (startUpdate_v47)Utils::TrampHook32((char*)0x009FB530, (char*)startUpdate_hook_v47, 5);
//uriHandler_v47_hook = (uriHandler_v47)Utils::TrampHook32((char*)0x010A39E0, (char*)uriHandler_hook_v47, 5);
//isValidUrl_v25_hook = (isValidUrl_v25)Utils::TrampHook32((char*)0x0105CD80, (char*)isValidUrl_hook_v25, 6);
diff --git a/SpotifyKeyDumper/SpotifyKeyDumper.vcxproj b/SpotifyKeyDumper/SpotifyKeyDumper.vcxproj
index dfe6e71..4eef5bc 100644
--- a/SpotifyKeyDumper/SpotifyKeyDumper.vcxproj
+++ b/SpotifyKeyDumper/SpotifyKeyDumper.vcxproj
@@ -16,6 +16,7 @@
{e6674e55-3cf4-45e4-a22f-7e257bcea583}
SpotifyKeyDumper
10.0
+ x86-windows-static-md
@@ -78,6 +79,7 @@
true
Speed
stdcpp14
+ MultiThreadedDLL
Windows
@@ -85,6 +87,7 @@
true
true
false
+ %(AdditionalDependencies)
diff --git a/SpotifyKeyDumper/Utils.cpp b/SpotifyKeyDumper/Utils.cpp
index a389bab..09706b7 100644
--- a/SpotifyKeyDumper/Utils.cpp
+++ b/SpotifyKeyDumper/Utils.cpp
@@ -3,6 +3,8 @@
#include "tiny-AES-c/aes.h"
const uint8_t IV[] = { 0x72, 0xE0, 0x67, 0xFB, 0xDD, 0xCB, 0xCF, 0x77, 0xEB, 0xE8, 0xBC, 0x64, 0x3F, 0x63, 0x0D, 0x93 };
+const std::string urlRegex = "https?:\\/\\/(?:www\.)?([-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6})"
+"\\b([-a-zA-Z0-9()@:%_\\+.~#?&\\/\\/=]*)";
bool Utils::Detour32(char* src, char* dst, const intptr_t len)
{
@@ -61,7 +63,7 @@ int Utils::GetSpotifyVersion()
LPBYTE lpVersionInfo = new BYTE[dwFVISize];
GetFileVersionInfo(lpszFilePath, 0, dwFVISize, lpVersionInfo);
UINT uLen;
- VS_FIXEDFILEINFO* lpFfi;
+ VS_FIXEDFILEINFO* lpFfi = {};
VerQueryValue(lpVersionInfo, _T("\\"), (LPVOID*)&lpFfi, &uLen);
DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
@@ -115,30 +117,158 @@ std::wstring Utils::Utf8ToUtf16(const std::string& str)
return convertedString;
}
+enum class FileType
+{
+ OGG,
+ MP3
+};
+
struct SongInfo
{
- std::string title, artist, album, cover;
-} songInfo;
+ FileType fileType{ FileType::OGG };
+ std::string title{ std::string() };
+ std::string artist{ std::string() };
+ std::string album{ std::string() };
+ std::string coverUrl{ std::string() };
+ std::string releaseType{ std::string() };
+ std::string releaseDate{ std::string() };
+ std::string isrc{ std::string() };
+ unsigned int year{ 0 };
+ unsigned int trackNum{ 1 };
+ unsigned int totalTracks{ 1 };
+ unsigned int discNum{ 0 };
+ bool isExplicit{ false };
+};
-void ClearSongInfo()
+void TagSong(std::wstring songPath, SongInfo* songInfo)
{
- songInfo.title = "";
- songInfo.artist = "";
- songInfo.album = "";
- songInfo.cover = "";
+ TagLib::String fileName = songPath.c_str();
+ TagLib::String tTitle(songInfo->title, TagLib::String::Type::UTF8);
+ TagLib::String tArtist(songInfo->artist, TagLib::String::Type::UTF8);
+ TagLib::String tAlbum(songInfo->album, TagLib::String::Type::UTF8);
+ TagLib::String tReleaseType(songInfo->releaseType, TagLib::String::Type::UTF8);
+ TagLib::String tReleaseDate(songInfo->releaseDate, TagLib::String::Type::UTF8);
+ TagLib::String tIsrc(songInfo->isrc, TagLib::String::Type::UTF8);
+ TagLib::String tTotalTracks(std::to_string(songInfo->totalTracks), TagLib::String::Type::UTF8);
+ TagLib::String tDiscNum(std::to_string(songInfo->discNum), TagLib::String::Type::UTF8);
+ //TagLib::String tIsExplicit(std::to_string(songInfo->isExplicit), TagLib::String::Type::UTF8);
+
+ // Parse episode URL to separate host and path
+ std::string coverUrlHost, coverUrlPath;
+ try
+ {
+ std::regex re(urlRegex);
+ std::smatch match;
+ if (std::regex_search(songInfo->coverUrl, match, re) && match.size() > 1)
+ {
+ coverUrlHost = match.str(1);
+ coverUrlPath = match.str(2);
+ }
+ else
+ {
+ std::cout << "Error: Cover art URL is not valid!" << std::endl;
+ return;
+ }
+ }
+ catch (std::regex_error& e)
+ {
+ // Syntax error in the regular expression
+ std::cout << "Error: Invalid regex!" << std::endl;
+ return;
+ }
+
+ std::string coverArtData = Utils::DownloadSpotifyUrl(coverUrlHost, coverUrlPath, "");
+ TagLib::ByteVector tCoverArtData(reinterpret_cast(&coverArtData[0]), coverArtData.length());
+
+ switch (songInfo->fileType)
+ {
+ case FileType::OGG:
+ {
+ TagLib::Ogg::Vorbis::File audioFile(songPath.c_str());
+ TagLib::Ogg::XiphComment* tag = audioFile.tag();
+
+ TagLib::FLAC::Picture* coverArt = new TagLib::FLAC::Picture();
+ coverArt->setType((TagLib::FLAC::Picture::Type)0x03); // Front Cover
+ coverArt->setMimeType("image/jpeg");
+ coverArt->setDescription("Front Cover");
+ coverArt->setData(tCoverArtData);
+
+ tag->addPicture(coverArt);
+ tag->setTitle(tTitle);
+ tag->setArtist(tArtist);
+ tag->setAlbum(tAlbum);
+ tag->setTrack(songInfo->trackNum);
+ tag->setYear(songInfo->year);
+
+ tag->addField("DATE", tReleaseDate);
+ tag->addField("DISCNUMBER", tDiscNum);
+ tag->addField("ISRC", tIsrc);
+ tag->addField("SOURCEMEDIA", "Digital Media");
+ tag->addField("RELEASETYPE", tReleaseType);
+ tag->addField("TOTALTRACKS", tTotalTracks);
+
+ audioFile.save();
+ break;
+ }
+ case FileType::MP3:
+ {
+ TagLib::MPEG::File audioFile(songPath.c_str());
+ TagLib::ID3v2::Tag* tag = audioFile.ID3v2Tag(true);
+
+ tag->setTitle(tTitle);
+ tag->setArtist(tArtist);
+ tag->setAlbum(tAlbum);
+ tag->setTrack(songInfo->trackNum);
+ tag->setYear(songInfo->year);
+
+ TagLib::ID3v2::AttachedPictureFrame* frame = new TagLib::ID3v2::AttachedPictureFrame;
+ if (frame->picture().size() < tCoverArtData.size())
+ {
+ frame->setMimeType("image/jpeg");
+ frame->setPicture(tCoverArtData);
+ tag->addFrame(frame);
+ }
+
+ audioFile.save();
+ break;
+ }
+ }
+}
+
+int GetUrlNum(int quality)
+{
+ switch (quality)
+ {
+ case 0: // Automatic
+ return 1; // Set to high quality
+ case 1: // Low
+ return 8;
+ case 2: // Normal
+ return 0;
+ case 3: // High
+ return 1;
+ case 4: // Very high
+ return 2;
+ default:
+ return 1; // Shouldn't happen; set to high quality
+ }
}
-static const std::string songRegex =
- "https?:\\/\\/(?:www\.)?([-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6})"
- "\\b([-a-zA-Z0-9()@:%_\\+.~#?&\\/\\/=]*)";
static const std::string albumSearchPattern = "\x68\x65\x69\x67\x68\x74\x22\x20\x3A\x20\x36\x34\x30";
static const std::wstring songDirRoot = L"Downloads";
static std::wstring songDir = songDirRoot;
-void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, std::string authToken)
+void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, std::string authToken, int quality)
{
std::string downloadStr;
std::wstring songExtension = L".ogg";
+ SongInfo* songInfo = new SongInfo();
+ /*songInfo->title = "";
+ songInfo->artist = "";
+ songInfo->album = "";
+ songInfo->coverUrl = "";
+ songInfo->fileType = FileType::OGG;*/
+
if (fileId.empty() || uri.empty() || authToken.empty())
{
std::cout << "Could not download song or episode: missing fileId, trackUri, or authToken!" << std::endl;
@@ -157,8 +287,9 @@ void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, s
}
// Get storage resolve from Spotify
+ std::string urlNum = std::to_string(GetUrlNum(quality));
std::string srStr = DownloadSpotifyUrl("spclient.wg.spotify.com",
- "/storage-resolve/files/audio/interactive_prefetch/" + fileId + "?product=0", authToken);
+ "/storage-resolve/v2/files/audio/interactive/" + urlNum + "/" + fileId + "?product=0", authToken);
if (srStr.length() <= 5)
{
@@ -177,7 +308,7 @@ void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, s
std::string songPath;
try
{
- std::regex re(songRegex);
+ std::regex re(urlRegex);
std::smatch match;
if (std::regex_search(srStr, match, re) && match.size() > 1)
{
@@ -206,11 +337,16 @@ void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, s
return;
}
- if (downloadStr.substr(0, 6).compare("") == 0)
+ if (downloadStr.compare(0, 6, "") == 0)
{
std::cout << "Error: " + downloadStr << std::endl;
return;
}
+ else if (downloadStr.compare(0, 5, "Error") == 0)
+ {
+ std::cout << downloadStr << std::endl;
+ return;
+ }
// Decrypt encrypted song data with Tiny AES in C
struct AES_ctx ctx;
@@ -231,10 +367,21 @@ void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, s
std::string metadata = DownloadSpotifyUrl("api.spotify.com", "/v1/tracks/"
+ uri.substr(uri.find("spotify:track:") + 14), authToken);
- songInfo.title = strtok((char*)(metadata.substr(metadata.find("is_local") + 55)).c_str(), "\"");
- songInfo.artist = strtok((char*)(metadata.substr(metadata.find("name") + 9)).c_str(), "\"");
- songInfo.album = strtok((char*)(metadata.substr(metadata.find(albumSearchPattern) + 404)).c_str(), "\"");
- songInfo.cover = strtok((char*)(metadata.substr(metadata.find("height") + 30)).c_str(), "\"");
+ songInfo->title = strtok((char*)(metadata.substr(metadata.find("is_local\" :") + 55)).c_str(), "\"");
+ songInfo->artist = strtok((char*)(metadata.substr(metadata.find("name\" :") + 9)).c_str(), "\"");
+ songInfo->album = strtok((char*)(metadata.substr(metadata.find(albumSearchPattern) + 404)).c_str(), "\"");
+ songInfo->coverUrl = strtok((char*)(metadata.substr(metadata.find("height\" :") + 30)).c_str(), "\"");
+ songInfo->releaseType = strtok((char*)(metadata.substr(metadata.find("album_type\" :") + 15)).c_str(), "\"");
+ songInfo->releaseDate = strtok((char*)(metadata.substr(metadata.find("release_date\" :") + 17)).c_str(), "\"");
+ songInfo->isrc = strtok((char*)(metadata.substr(metadata.find("isrc\" :") + 9)).c_str(), "\"");
+ songInfo->trackNum = std::stoi(strtok((char*)(metadata.substr(metadata.find("track_number\" :") + 16)).c_str(),
+ ","));
+ songInfo->totalTracks = std::stoi(strtok((char*)(metadata.substr(metadata.find("total_tracks\" :")
+ + 16)).c_str(), ","));
+ songInfo->discNum = std::stoi(strtok((char*)(metadata.substr(metadata.find("disc_number\" :") + 15)).c_str(),
+ ","));
+ songInfo->isExplicit = strtok((char*)(metadata.substr(metadata.find("explicit\" :") + 12)).c_str(), ",");
+ songInfo->fileType = FileType::OGG;
songExtension = L".ogg";
}
@@ -249,7 +396,7 @@ void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, s
// Parse episode URL to separate host and path
try
{
- std::regex re(songRegex);
+ std::regex re(urlRegex);
std::smatch match;
if (std::regex_search(episodeUrl, match, re) && match.size() > 1)
{
@@ -284,46 +431,50 @@ void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, s
std::string metadata = DownloadSpotifyUrl("api.spotify.com", "/v1/episodes/"
+ uri.substr(uri.find("spotify:episode:") + 16), authToken);
- songInfo.title = strtok((char*)(metadata.substr(metadata.find("name") + 9)).c_str(), "\"");
- songInfo.artist = strtok((char*)(metadata.substr(metadata.find("publisher") + 14)).c_str(), "\"");
- songInfo.album = strtok((char*)(metadata.substr(metadata.find("media_type") + 37)).c_str(), "\"");
- songInfo.cover = strtok((char*)(metadata.substr(metadata.find("height") + 28)).c_str(), "\"");
+ songInfo->title = strtok((char*)(metadata.substr(metadata.find("name") + 9)).c_str(), "\"");
+ songInfo->artist = strtok((char*)(metadata.substr(metadata.find("publisher") + 14)).c_str(), "\"");
+ songInfo->album = strtok((char*)(metadata.substr(metadata.find("media_type") + 37)).c_str(), "\"");
+ songInfo->coverUrl = strtok((char*)(metadata.substr(metadata.find("height") + 28)).c_str(), "\"");
+ songInfo->fileType = FileType::MP3;
songExtension = L".mp3";
}
- if (songInfo.title.empty() || songInfo.artist.empty() || songInfo.album.empty())
+ if (songInfo->title.empty() || songInfo->artist.empty() || songInfo->album.empty())
{
std::cout << "Error: Invalid title/artist/album name!" << std::endl;
+ delete songInfo;
return;
}
- std::wstring tempDirArtist = FixPathStr(Utf8ToUtf16(songInfo.artist));
+ std::wstring tempDirArtist = FixPathStr(Utf8ToUtf16(songInfo->artist));
songDir = songDirRoot;
if (!CreateDirectoryW(songDir.c_str(), NULL) && ERROR_ALREADY_EXISTS != GetLastError())
std::cout << "Couldn't create main downloads directory!" << std::endl;
-
- if (CreateDirectoryW(std::wstring(songDir + L"\\" + tempDirArtist).c_str(), NULL)
+ else if (CreateDirectoryW(std::wstring(songDir + L"\\" + tempDirArtist).c_str(), NULL)
|| ERROR_ALREADY_EXISTS == GetLastError())
{
- std::wstring tempDirAlbum = FixPathStr(Utf8ToUtf16(songInfo.album));
+ std::wstring tempDirAlbum = FixPathStr(Utf8ToUtf16(songInfo->album));
if (CreateDirectoryW(std::wstring(songDir + L"\\" + tempDirArtist + std::wstring(L"\\")
+ tempDirAlbum).c_str(), NULL) || ERROR_ALREADY_EXISTS == GetLastError())
{
- songDir += L"\\" + tempDirArtist + std::wstring(L"\\") + tempDirAlbum;
+ std::wstring tempDirSong = FixPathStr(Utf8ToUtf16(songInfo->title));
- std::wstring tempDirSong = FixPathStr(Utf8ToUtf16(songInfo.title));
+ songDir += L"\\" + tempDirArtist + std::wstring(L"\\") + tempDirAlbum + L".\\" + tempDirArtist + L" - "
+ + tempDirSong + songExtension;
- std::ofstream songFileOut(songDir + L".\\" + tempDirArtist + L" - " + tempDirSong + songExtension,
- std::ios_base::binary);
+ std::ofstream songFileOut(songDir, std::ios_base::binary);
songFileOut.write(downloadStr.c_str(), downloadStr.size());
songFileOut.close();
- std::cout << "Finished downloading: " << songInfo.artist << " - \"" << songInfo.title << "\"!" << std::endl;
+ TagSong(songDir, songInfo);
- ClearSongInfo();
+ std::cout << "Finished downloading: " << songInfo->artist << " - \"" << songInfo->title << "\"!"
+ << std::endl;
+
+ delete songInfo;
return;
}
else
@@ -335,29 +486,6 @@ void Utils::DownloadSong(std::string fileId, std::string uri, std::string key, s
{
std::cout << "Couldn't create artist directory!" << std::endl;
}
-
- std::cout << "Could not finish downloading song!" << std::endl;
-
- ClearSongInfo();
-}
-
-std::string GetLastErrorAsString()
-{
- //Get the error message, if any.
- DWORD errorMessageID = ::GetLastError();
- if (errorMessageID == 0)
- return std::string(); //No error message has been recorded
-
- LPSTR messageBuffer = nullptr;
- size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
-
- std::string message(messageBuffer, size);
-
- //Free the buffer.
- LocalFree(messageBuffer);
-
- return message;
}
std::string Utils::DownloadSpotifyUrl(std::string host, std::string path, std::string authToken)
@@ -373,26 +501,26 @@ std::string Utils::DownloadSpotifyUrl(std::string host, std::string path, std::s
hSession = InternetOpenA(userAgent.c_str(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hSession == NULL)
- return "Error: Could not initialize request!";
+ return "Error: Could not initialize request: " + GetLastError();
hConnect = InternetConnectA(hSession, host.c_str(), 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0,
NULL);
if (hConnect == NULL)
- return "Error: Could not create connect!";
+ return "Error: Could not create connect: " + GetLastError();
hRequest = HttpOpenRequestA(hConnect, "GET", path.c_str(), NULL, NULL, NULL, INTERNET_FLAG_NO_AUTH, 0);
if (hRequest == NULL)
- return "Error: Could not create open request!";
+ return "Error: Could not create open request: " + GetLastError();
HttpAddRequestHeadersA(hRequest, authHeader.c_str(), -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
bRequestSent = HttpSendRequestA(hRequest, NULL, 0, NULL, 0);
if (!bRequestSent)
- return "Error: Could not send request!";
+ return "Error: Could not send request: " + GetLastError();
- char tmpBuffer[bufferSize];
+ char tmpBuffer[bufferSize] = {};
BOOL canRead = true;
DWORD bytesRead = -1;
diff --git a/SpotifyKeyDumper/Utils.h b/SpotifyKeyDumper/Utils.h
index a09e41f..e38f82e 100644
--- a/SpotifyKeyDumper/Utils.h
+++ b/SpotifyKeyDumper/Utils.h
@@ -9,7 +9,7 @@ public:
static std::string HexString(BYTE* data, int len);
static std::wstring FixPathStr(std::wstring str);
static std::wstring Utf8ToUtf16(const std::string& str);
- static void DownloadSong(std::string fileId, std::string fileUri, std::string key, std::string authToken);
+ static void DownloadSong(std::string fileId, std::string uri, std::string key, std::string authToken, int quality);
static std::string DownloadSpotifyUrl(std::string host, std::string path, std::string authToken);
static bool BadPtr(void* ptr);
};
diff --git a/SpotifyKeyDumper/pch.h b/SpotifyKeyDumper/pch.h
index 68ed8b3..4b7ab37 100644
--- a/SpotifyKeyDumper/pch.h
+++ b/SpotifyKeyDumper/pch.h
@@ -25,4 +25,11 @@
#include
#include
+// TagLib
+#define TAGLIB_STATIC
+#include
+#include
+#include
+#include
+
#endif //PCH_H