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