Browse Source

trying to follow cspot...

philippe44 1 year ago
parent
commit
7dbed7a67b
36 changed files with 621 additions and 420 deletions
  1. 5 5
      components/spotify/cspot/include/AccessKeyFetcher.h
  2. 1 5
      components/spotify/cspot/include/ApResolve.h
  3. 8 14
      components/spotify/cspot/include/AuthChallenges.h
  4. 12 8
      components/spotify/cspot/include/CDNTrackStream.h
  5. 1 0
      components/spotify/cspot/include/CSpotContext.h
  6. 7 12
      components/spotify/cspot/include/LoginBlob.h
  7. 16 15
      components/spotify/cspot/include/MercurySession.h
  8. 6 10
      components/spotify/cspot/include/PlainConnection.h
  9. 7 11
      components/spotify/cspot/include/PlaybackState.h
  10. 11 15
      components/spotify/cspot/include/Session.h
  11. 3 2
      components/spotify/cspot/include/Shannon.h
  12. 11 11
      components/spotify/cspot/include/ShannonConnection.h
  13. 12 8
      components/spotify/cspot/include/SpircHandler.h
  14. 2 4
      components/spotify/cspot/include/TimeProvider.h
  15. 20 11
      components/spotify/cspot/include/TrackPlayer.h
  16. 12 7
      components/spotify/cspot/include/TrackProvider.h
  17. 2 3
      components/spotify/cspot/include/TrackReference.h
  18. 9 16
      components/spotify/cspot/include/Utils.h
  19. 2 1
      components/spotify/cspot/protobuf/metadata.options
  20. 2 1
      components/spotify/cspot/protobuf/metadata.proto
  21. 29 9
      components/spotify/cspot/src/AccessKeyFetcher.cpp
  22. 15 1
      components/spotify/cspot/src/ApResolve.cpp
  23. 8 0
      components/spotify/cspot/src/AuthChallenges.cpp
  24. 25 3
      components/spotify/cspot/src/CDNTrackStream.cpp
  25. 12 2
      components/spotify/cspot/src/LoginBlob.cpp
  26. 22 8
      components/spotify/cspot/src/MercurySession.cpp
  27. 16 4
      components/spotify/cspot/src/PlainConnection.cpp
  28. 16 3
      components/spotify/cspot/src/PlaybackState.cpp
  29. 17 2
      components/spotify/cspot/src/Session.cpp
  30. 3 5
      components/spotify/cspot/src/Shannon.cpp
  31. 13 1
      components/spotify/cspot/src/ShannonConnection.cpp
  32. 19 11
      components/spotify/cspot/src/SpircHandler.cpp
  33. 8 1
      components/spotify/cspot/src/TimeProvider.cpp
  34. 18 8
      components/spotify/cspot/src/TrackPlayer.cpp
  35. 128 66
      components/spotify/cspot/src/TrackProvider.cpp
  36. 123 137
      components/spotify/cspot/src/Utils.cpp

+ 5 - 5
components/spotify/cspot/include/AccessKeyFetcher.h

@@ -1,12 +1,12 @@
 #pragma once
 
-#include <functional>
-#include <memory>
-
-#include "CSpotContext.h"
-#include "Utils.h"
+#include <functional>  // for function
+#include <memory>      // for shared_ptr
+#include <string>      // for string
 
 namespace cspot {
+struct Context;
+
 class AccessKeyFetcher {
  public:
   AccessKeyFetcher(std::shared_ptr<cspot::Context> ctx);

+ 1 - 5
components/spotify/cspot/include/ApResolve.h

@@ -1,13 +1,9 @@
 #pragma once
 
-#include <memory>
-#include <string>
-
-#include "HTTPClient.h"
+#include <string>  // for string
 #ifdef BELL_ONLY_CJSON
 #include "cJSON.h"
 #else
-#include "nlohmann/json.hpp"
 #endif
 
 namespace cspot {

+ 8 - 14
components/spotify/cspot/include/AuthChallenges.h

@@ -1,20 +1,14 @@
 #pragma once
 
 
-#include <algorithm>
-#include <climits>
-#include <functional>
-#include <memory>
-#include <random>
-#include <vector>
-
-#include "Crypto.h"
-#include "Logger.h"
-#include "NanoPBHelper.h"
-#include "Utils.h"
-
-#include "protobuf/authentication.pb.h"
-#include "protobuf/keyexchange.pb.h"
+#include <cstdint>                       // for uint8_t
+#include <memory>                        // for unique_ptr
+#include <string>                        // for string
+#include <vector>                        // for vector
+
+#include "Crypto.h"                      // for Crypto
+#include "protobuf/authentication.pb.h"  // for ClientResponseEncrypted
+#include "protobuf/keyexchange.pb.h"     // for APResponseMessage, ClientHello
 
 namespace cspot {
 class AuthChallenges {

+ 12 - 8
components/spotify/cspot/include/CDNTrackStream.h

@@ -1,16 +1,20 @@
 #pragma once
 
-#include <cstddef>
-#include <memory>
-#include "Crypto.h"
-#include "WrappedSemaphore.h"
+#include <cstddef>       // for size_t
+#include <cstdint>       // for uint8_t
+#include <memory>        // for shared_ptr, unique_ptr
+#include <string>        // for string
+#include <vector>        // for vector
 
-#include "Logger.h"
-#include "Utils.h"
-#include "CSpotContext.h"
-#include "AccessKeyFetcher.h"
+#include "Crypto.h"      // for Crypto
+#include "HTTPClient.h"  // for HTTPClient
+
+namespace bell {
+class WrappedSemaphore;
+}  // namespace bell
 
 namespace cspot {
+class AccessKeyFetcher;
 
 class CDNTrackStream {
 

+ 1 - 0
components/spotify/cspot/include/CSpotContext.h

@@ -5,6 +5,7 @@
 #include "MercurySession.h"
 #include "TimeProvider.h"
 #include "protobuf/metadata.pb.h"
+#include "LoginBlob.h"
 
 namespace cspot {
 struct Context {

+ 7 - 12
components/spotify/cspot/include/LoginBlob.h

@@ -1,17 +1,12 @@
 #pragma once
 
-#include <iostream>
-#include <map>
-#include <memory>
-#ifndef BELL_ONLY_CJSON
-#include <nlohmann/json.hpp>
-#endif
-#include <vector>
-
-#include "ConstantParameters.h"
-#include "Crypto.h"
-
-#include "protobuf/authentication.pb.h"
+#include <cstdint>   // for uint8_t, uint32_t
+#include <map>       // for map
+#include <memory>    // for unique_ptr
+#include <string>    // for string
+#include <vector>    // for vector
+
+#include "Crypto.h"  // for CryptoMbedTLS, Crypto
 
 namespace cspot {
 class LoginBlob {

+ 16 - 15
components/spotify/cspot/include/MercurySession.h

@@ -1,22 +1,23 @@
 #pragma once
 
-#include <atomic>
-#include <functional>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-#include "BellTask.h"
-#include "Logger.h"
-#include "NanoPBHelper.h"
-#include "Packet.h"
-#include "Queue.h"
-#include "Session.h"
-#include "TimeProvider.h"
-#include "Utils.h"
-#include "protobuf/mercury.pb.h"
+#include <atomic>                 // for atomic
+#include <cstdint>                // for uint8_t, uint64_t, uint32_t
+#include <functional>             // for function
+#include <memory>                 // for shared_ptr
+#include <mutex>                  // for mutex
+#include <string>                 // for string
+#include <unordered_map>          // for unordered_map
+#include <vector>                 // for vector
+
+#include "BellTask.h"             // for Task
+#include "Packet.h"               // for Packet
+#include "Queue.h"                // for Queue
+#include "Session.h"              // for Session
+#include "protobuf/mercury.pb.h"  // for Header
 
 namespace cspot { 
+class TimeProvider;
+
 class MercurySession : public bell::Task, public cspot::Session {
  public:
   MercurySession(std::shared_ptr<cspot::TimeProvider> timeProvider);

+ 6 - 10
components/spotify/cspot/include/PlainConnection.h

@@ -3,19 +3,15 @@
 #ifdef _WIN32
 #include <winsock2.h>
 #include <ws2tcpip.h>
+
 #include "win32shim.h"
 #else
-#include <netdb.h>
-#include <unistd.h>
-#include "sys/socket.h"
-#include <netinet/in.h>
+#include <unistd.h>    // for size_t
 #endif
-#include <cstdint>
-#include <functional>
-#include <string>
-#include <vector>
-#include "Packet.h"
-#include "Utils.h"
+#include <cstdint>     // for uint8_t
+#include <functional>  // for function
+#include <string>      // for string
+#include <vector>      // for vector
 
 typedef std::function<bool()> timeoutCallback;
 

+ 7 - 11
components/spotify/cspot/include/PlaybackState.h

@@ -1,18 +1,14 @@
 #pragma once
 
-#include <NanoPBHelper.h>
-#include <memory>
-#include <string>
-#include <vector>
-#include "CSpotContext.h"
-#include "ConstantParameters.h"
-#include "CspotAssert.h"
-#include "TimeProvider.h"
-#include "Utils.h"
-
-#include "protobuf/spirc.pb.h"
+#include <stdint.h>             // for uint8_t, uint32_t
+#include <memory>               // for shared_ptr
+#include <string>               // for string
+#include <vector>               // for vector
+
+#include "protobuf/spirc.pb.h"  // for Frame, TrackRef, CapabilityType, Mess...
 
 namespace cspot {
+struct Context;
 
 class PlaybackState {
  private:

+ 11 - 15
components/spotify/cspot/include/Session.h

@@ -1,20 +1,16 @@
 #pragma once
 
-#include <algorithm>
-#include <functional>
-#include <memory>
-#include <vector>
-
-#include "ApResolve.h"
-#include "AuthChallenges.h"
-#include "ConstantParameters.h"
-#include "Logger.h"
-#include "LoginBlob.h"
-#include "Packet.h"
-#include "PlainConnection.h"
-#include "ShannonConnection.h"
-#include "Utils.h"
-#include "protobuf/mercury.pb.h"
+#include <stdint.h>  // for uint8_t
+#include <memory>    // for shared_ptr, unique_ptr
+#include <string>    // for string
+#include <vector>    // for vector
+
+namespace cspot {
+class AuthChallenges;
+class LoginBlob;
+class PlainConnection;
+class ShannonConnection;
+}  // namespace cspot
 
 #define LOGIN_REQUEST_COMMAND 0xAB
 #define AUTH_SUCCESSFUL_COMMAND 0xAC

+ 3 - 2
components/spotify/cspot/include/Shannon.h

@@ -1,8 +1,9 @@
 #ifndef SHANNON_H
 #define SHANNON_H
 
-#include <cstdint>
-#include <vector>
+#include <cstdint>  // for uint32_t, uint8_t
+#include <vector>   // for vector
+
 class Shannon
 {
 public:

+ 11 - 11
components/spotify/cspot/include/ShannonConnection.h

@@ -1,18 +1,18 @@
 #ifndef SHANNONCONNECTION_H
 #define SHANNONCONNECTION_H
 
-#include <sys/types.h>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
+#include <cstdint>   // for uint8_t, uint32_t
+#include <memory>    // for shared_ptr, unique_ptr
+#include <mutex>     // for mutex
+#include <vector>    // for vector
 
-#include "Packet.h"
-#include "PlainConnection.h"
-#include "Shannon.h"
-#include <mutex>
-#include "Utils.h"
-#include "Logger.h"
+#include "Packet.h"  // for Packet
+
+class Shannon;
+namespace cspot {
+
+class PlainConnection;
+}  // namespace cspot
 
 #define MAC_SIZE 4
 namespace cspot {

+ 12 - 8
components/spotify/cspot/include/SpircHandler.h

@@ -1,16 +1,20 @@
 #pragma once
 
-#include <memory>
-#include "BellTask.h"
+#include <stdint.h>             // for uint32_t, uint8_t
+#include <functional>           // for function
+#include <memory>               // for shared_ptr, unique_ptr
+#include <string>               // for string
+#include <variant>              // for variant
+#include <vector>               // for vector
 
-#include "CDNTrackStream.h"
-#include "CSpotContext.h"
-#include "PlaybackState.h"
-#include "TrackPlayer.h"
-#include "TrackProvider.h"
-#include "protobuf/spirc.pb.h"
+#include "CDNTrackStream.h"     // for CDNTrackStream, CDNTrackStream::Track...
+#include "PlaybackState.h"      // for PlaybackState
+#include "protobuf/spirc.pb.h"  // for MessageType
 
 namespace cspot {
+class TrackPlayer;
+struct Context;
+
 class SpircHandler {
  public:
   SpircHandler(std::shared_ptr<cspot::Context> ctx);

+ 2 - 4
components/spotify/cspot/include/TimeProvider.h

@@ -1,9 +1,7 @@
 #pragma once
 
-#include <stdint.h>
-#include <vector>
-
-#include "Utils.h"
+#include <stdint.h>  // for uint8_t
+#include <vector>    // for vector
 
 namespace cspot {
 class TimeProvider {

+ 20 - 11
components/spotify/cspot/include/TrackPlayer.h

@@ -1,22 +1,31 @@
 #pragma once
 
-#include <functional>
-#include <memory>
-#include <mutex>
-#include <atomic>
-#include <BellUtils.h>
-#include <WrappedSemaphore.h>
-#include "CDNTrackStream.h"
-#include "CSpotContext.h"
-#include "TrackProvider.h"
-#include "TrackReference.h"
+#include <atomic>            // for atomic
+#include <cstdint>           // for uint8_t, int64_t
+#include <ctime>             // for size_t, time
+#include <functional>        // for function
+#include <memory>            // for shared_ptr, unique_ptr
+#include <mutex>             // for mutex
+#include <string_view>       // for string_view
+#include <vector>            // for vector
+
+#include "BellTask.h"        // for Task
+#include "CDNTrackStream.h"  // for CDNTrackStream, CDNTrackStream::TrackInfo
+
+namespace bell {
+class WrappedSemaphore;
+}  // namespace bell
 #ifdef BELL_VORBIS_FLOAT
 #include "vorbis/vorbisfile.h"
 #else
-#include "ivorbisfile.h"
+#include "ivorbisfile.h"     // for OggVorbis_File, ov_callbacks
 #endif
 
 namespace cspot {
+class TrackProvider;
+struct Context;
+struct TrackReference;
+
 class TrackPlayer : bell::Task {
  public:
   typedef std::function<void()> TrackLoadedCallback;

+ 12 - 7
components/spotify/cspot/include/TrackProvider.h

@@ -1,15 +1,18 @@
 #pragma once
 
-#include <memory>
+#include <stdint.h>                // for uint8_t
+#include <memory>                  // for shared_ptr, unique_ptr, weak_ptr
+#include <vector>                  // for vector
 
-#include "AccessKeyFetcher.h"
-#include "CDNTrackStream.h"
-#include "CSpotContext.h"
-#include "TrackReference.h"
-#include "protobuf/metadata.pb.h"
-#include "protobuf/spirc.pb.h"
+#include "MercurySession.h"        // for MercurySession
+#include "TrackReference.h"        // for TrackReference
+#include "protobuf/metadata.pb.h"  // for Episode, Restriction, Track
 
 namespace cspot {
+class AccessKeyFetcher;
+class CDNTrackStream;
+struct Context;
+
 class TrackProvider {
  public:
   TrackProvider(std::shared_ptr<cspot::Context> ctx);
@@ -23,11 +26,13 @@ class TrackProvider {
   std::unique_ptr<cspot::CDNTrackStream> cdnStream;
 
   Track trackInfo;
+  Episode episodeInfo;
   std::weak_ptr<CDNTrackStream> currentTrackReference;
   TrackReference trackIdInfo;
 
   void queryMetadata();
   void onMetadataResponse(MercurySession::Response& res);
+  bool doRestrictionsApply(Restriction* restrictions, int count);
   void fetchFile(const std::vector<uint8_t>& fileId,
                  const std::vector<uint8_t>& trackId);
   bool canPlayTrack(int index);

+ 2 - 3
components/spotify/cspot/include/TrackReference.h

@@ -28,12 +28,11 @@ struct TrackReference {
       // Episode GID is being fetched via base62 encoded URI
       auto uri = std::string(ref->uri);
       auto idString = uri.substr(uri.find_last_of(":") + 1, uri.size());
-
       trackRef.gid = {0};
 
       std::string_view alphabet(base62Alphabet);
-      for (int x = 0; x < uri.size(); x++) {
-        size_t d = alphabet.find(uri[x]);
+      for (int x = 0; x < idString.size(); x++) {
+        size_t d = alphabet.find(idString[x]);
         trackRef.gid = bigNumMultiply(trackRef.gid, 62);
         trackRef.gid = bigNumAdd(trackRef.gid, d);
       }

+ 9 - 16
components/spotify/cspot/include/Utils.h

@@ -1,27 +1,20 @@
 #ifndef UTILS_H
 #define UTILS_H
-#include <vector>
+#include <cstdio>     // for snprintf, size_t
+#include <vector>     // for vector
 #ifdef _WIN32
 #include <winsock2.h>
 #include <ws2tcpip.h>
+
 #include "win32shim.h"
 #else
-#include <unistd.h>
-#include "sys/socket.h"
-#include <netdb.h>
-#include <netinet/in.h>
+
 #endif
-#include <cstdint>
-#include <cstring>
-#include <memory>
-#include <chrono>
-#include <string>
-#include <sstream>
-#include <iostream>
-#include <iomanip>
-#include <memory>
-#include <string>
-#include <stdexcept>
+#include <cstdint>    // for uint8_t, uint64_t
+#include <cstring>    // for memcpy
+#include <memory>     // for unique_ptr
+#include <stdexcept>  // for runtime_error
+#include <string>     // for string
 
 #define HMAC_SHA1_BLOCKSIZE 64
 

+ 2 - 1
components/spotify/cspot/protobuf/metadata.options

@@ -12,7 +12,8 @@ Album.name type: FT_POINTER
 Episode.gid type: FT_POINTER
 Episode.name type: FT_POINTER
 ImageGroup.image type: FT_POINTER
-Episode.audio type: FT_POINTER
+Episode.file type: FT_POINTER
+Episode.restriction type: FT_POINTER
 Episode.covers type: FT_POINTER
 Restriction.countries_allowed type: FT_POINTER
 Restriction.countries_forbidden type: FT_POINTER

+ 2 - 1
components/spotify/cspot/protobuf/metadata.proto

@@ -44,7 +44,8 @@ message Episode {
     optional bytes gid = 1;
     optional string name = 2;
     optional sint32 duration = 7;
-    repeated AudioFile audio = 12;
+    repeated AudioFile file = 12;
+    repeated Restriction restriction = 0x4B;
     optional ImageGroup covers = 0x44;
 }
 

+ 29 - 9
components/spotify/cspot/src/AccessKeyFetcher.cpp

@@ -1,7 +1,24 @@
 #include "AccessKeyFetcher.h"
-#include <cstring>
-#include "Logger.h"
-#include "Utils.h"
+
+#include <cstring>           // for strrchr
+#include <initializer_list>  // for initializer_list
+#include <map>               // for operator!=, operator==
+#include <type_traits>       // for remove_extent_t
+#include <vector>            // for vector
+
+#include "BellLogger.h"           // for AbstractLogger
+#include "CSpotContext.h"         // for Context
+#include "Logger.h"               // for CSPOT_LOG
+#include "MercurySession.h"       // for MercurySession, MercurySession::Res...
+#include "Packet.h"               // for cspot
+#include "TimeProvider.h"         // for TimeProvider
+#include "Utils.h"                // for string_format
+#ifdef BELL_ONLY_CJSON
+#include "cJSON.h"
+#else
+#include "nlohmann/json.hpp"      // for basic_json<>::object_t, basic_json
+#include "nlohmann/json_fwd.hpp"  // for json
+#endif
 
 using namespace cspot;
 
@@ -38,18 +55,21 @@ void AccessKeyFetcher::getAccessKey(AccessKeyFetcher::Callback callback) {
   ctx->session->execute(
       MercurySession::RequestType::GET, url,
       [this, timeProvider, callback](MercurySession::Response& res) {
-        if (res.fail) return;
+        if (res.fail)
+          return;
         char* accessKeyJson = (char*)res.parts[0].data();
-        auto accessJSON = std::string(accessKeyJson, strrchr(accessKeyJson, '}') - accessKeyJson + 1);
+        auto accessJSON = std::string(
+            accessKeyJson, strrchr(accessKeyJson, '}') - accessKeyJson + 1);
 #ifdef BELL_ONLY_CJSON
         cJSON* jsonBody = cJSON_Parse(accessJSON.c_str());
-        this->accessKey = cJSON_GetObjectItem(jsonBody, "accessToken")->valuestring;
+        this->accessKey =
+            cJSON_GetObjectItem(jsonBody, "accessToken")->valuestring;
         int expiresIn = cJSON_GetObjectItem(jsonBody, "expiresIn")->valueint;
 #else
         auto jsonBody = nlohmann::json::parse(accessJSON);
         this->accessKey = jsonBody["accessToken"];
         int expiresIn = jsonBody["expiresIn"];
-#endif        
+#endif
         expiresIn = expiresIn / 2;  // Refresh token before it expires
 
         this->expiresAt =
@@ -57,8 +77,8 @@ void AccessKeyFetcher::getAccessKey(AccessKeyFetcher::Callback callback) {
 #ifdef BELL_ONLY_CJSON
         callback(cJSON_GetObjectItem(jsonBody, "accessToken")->valuestring);
         cJSON_Delete(jsonBody);
-#else            
+#else
         callback(jsonBody["accessToken"]);
-#endif    
+#endif
       });
 }

+ 15 - 1
components/spotify/cspot/src/ApResolve.cpp

@@ -1,5 +1,19 @@
 #include "ApResolve.h"
 
+#include <initializer_list>       // for initializer_list
+#include <map>                    // for operator!=, operator==
+#include <memory>                 // for allocator, unique_ptr
+#include <string_view>            // for string_view
+#include <vector>                 // for vector
+
+#include "HTTPClient.h"           // for HTTPClient, HTTPClient::Response
+#ifdef BELL_ONLY_CJSON
+#include "cJSON.h"
+#else
+#include "nlohmann/json.hpp"      // for basic_json<>::object_t, basic_json
+#include "nlohmann/json_fwd.hpp"  // for json
+#endif
+
 using namespace cspot;
 
 ApResolve::ApResolve(std::string apOverride) 
@@ -18,7 +32,7 @@ std::string ApResolve::fetchFirstApAddress()
     std::string_view responseStr = request->body();
 
     // parse json with nlohmann
-#if BELL_ONLY_CJSON
+#ifdef BELL_ONLY_CJSON
    cJSON* json = cJSON_Parse(responseStr.data());
    auto ap_string = std::string(cJSON_GetArrayItem(cJSON_GetObjectItem(json, "ap_list"), 0)->valuestring);
    cJSON_Delete(json);

+ 8 - 0
components/spotify/cspot/src/AuthChallenges.cpp

@@ -1,5 +1,13 @@
 #include "AuthChallenges.h"
 
+#include <algorithm>       // for copy
+#include <climits>         // for CHAR_BIT
+#include <random>          // for default_random_engine, independent_bits_en...
+
+#include "NanoPBHelper.h"  // for pbPutString, pbEncode, pbDecode
+#include "pb.h"            // for pb_byte_t
+#include "pb_decode.h"     // for pb_release
+
 using namespace cspot;
 using random_bytes_engine =
     std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;

+ 25 - 3
components/spotify/cspot/src/CDNTrackStream.cpp

@@ -1,5 +1,26 @@
 #include "CDNTrackStream.h"
 
+#include <string.h>          // for memcpy
+#include <functional>        // for __base
+#include <initializer_list>  // for initializer_list
+#include <map>               // for operator!=, operator==
+#include <string_view>       // for string_view
+#include <type_traits>       // for remove_extent_t
+
+#include "AccessKeyFetcher.h"     // for AccessKeyFetcher
+#include "BellLogger.h"           // for AbstractLogger
+#include "Logger.h"               // for CSPOT_LOG
+#include "Packet.h"               // for cspot
+#include "SocketStream.h"         // for SocketStream
+#include "Utils.h"                // for bigNumAdd, bytesToHexString, string...
+#include "WrappedSemaphore.h"     // for WrappedSemaphore
+#ifdef BELL_ONLY_CJSON
+#include "cJSON.h"
+#else
+#include "nlohmann/json.hpp"      // for basic_json<>::object_t, basic_json
+#include "nlohmann/json_fwd.hpp"  // for json
+#endif
+
 using namespace cspot;
 
 CDNTrackStream::CDNTrackStream(
@@ -10,8 +31,7 @@ CDNTrackStream::CDNTrackStream(
   this->crypto = std::make_unique<Crypto>();
 }
 
-CDNTrackStream::~CDNTrackStream() {
-}
+CDNTrackStream::~CDNTrackStream() {}
 
 void CDNTrackStream::fail() {
   this->status = Status::FAILED;
@@ -40,7 +60,9 @@ void CDNTrackStream::fetchFile(const std::vector<uint8_t>& trackId,
 
 #ifdef BELL_ONLY_CJSON
     cJSON* jsonResult = cJSON_Parse(result.data());
-    std::string cdnUrl = cJSON_GetArrayItem(cJSON_GetObjectItem(jsonResult, "cdnurl"), 0)->valuestring;
+    std::string cdnUrl =
+        cJSON_GetArrayItem(cJSON_GetObjectItem(jsonResult, "cdnurl"), 0)
+            ->valuestring;
     cJSON_Delete(jsonResult);
 #else
     auto jsonResult = nlohmann::json::parse(result);

+ 12 - 2
components/spotify/cspot/src/LoginBlob.cpp

@@ -1,8 +1,18 @@
 #include "LoginBlob.h"
-#include "ConstantParameters.h"
-#include "Logger.h"
+
+#include <stdio.h>                           // for sprintf
+#include <initializer_list>                  // for initializer_list
+
+#include "BellLogger.h"                      // for AbstractLogger
+#include "ConstantParameters.h"              // for brandName, cspot, protoc...
+#include "Logger.h"                          // for CSPOT_LOG
+#include "protobuf/authentication.pb.h"      // for AuthenticationType_AUTHE...
 #ifdef BELL_ONLY_CJSON
 #include "cJSON.h"
+#else
+#include "nlohmann/detail/json_pointer.hpp"  // for json_pointer<>::string_t
+#include "nlohmann/json.hpp"                 // for basic_json<>::object_t
+#include "nlohmann/json_fwd.hpp"             // for json
 #endif
 
 using namespace cspot;

+ 22 - 8
components/spotify/cspot/src/MercurySession.cpp

@@ -1,11 +1,25 @@
 #include "MercurySession.h"
-#include <memory>
-#include <mutex>
-#include "BellLogger.h"
-#include "BellTask.h"
-#include "BellUtils.h"
-#include "CSpotContext.h"
-#include "Logger.h"
+
+#include <string.h>     // for memcpy
+#include <memory>       // for shared_ptr
+#include <mutex>        // for scoped_lock
+#include <stdexcept>    // for runtime_error
+#include <type_traits>  // for remove_extent_t, __underlying_type_impl<>:...
+#include <utility>      // for pair
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#endif
+
+#include "BellLogger.h"         // for AbstractLogger
+#include "BellTask.h"           // for Task
+#include "BellUtils.h"          // for BELL_SLEEP_MS
+#include "Logger.h"             // for CSPOT_LOG
+#include "NanoPBHelper.h"       // for pbPutString, pbDecode, pbEncode
+#include "PlainConnection.h"    // for PlainConnection
+#include "ShannonConnection.h"  // for ShannonConnection
+#include "TimeProvider.h"       // for TimeProvider
+#include "Utils.h"              // for extract, pack, hton64
 
 using namespace cspot;
 
@@ -167,7 +181,7 @@ void MercurySession::handlePacket() {
 }
 
 void MercurySession::failAllPending() {
-  Response response = { };
+  Response response = {};
   response.fail = true;
 
   // Fail all callbacks

+ 16 - 4
components/spotify/cspot/src/PlainConnection.cpp

@@ -1,12 +1,24 @@
 #include "PlainConnection.h"
-#include <cstring>
+
+#ifndef _WIN32
+#include <netdb.h>        // for addrinfo, freeaddrinfo, getaddrinfo
+#include <netinet/in.h>   // for IPPROTO_IP, IPPROTO_TCP
+#include <sys/errno.h>    // for EAGAIN, EINTR, ETIMEDOUT, errno
+#include <sys/socket.h>   // for setsockopt, connect, recv, send, shutdown
+#include <sys/time.h>     // for timeval
+#endif
+#include <cstring>        // for memset
+#include <stdexcept>      // for runtime_error
 #ifdef _WIN32
 #include <ws2tcpip.h>
 #else
-#include <netinet/tcp.h>
+#include <netinet/tcp.h>  // for TCP_NODELAY
+#include <arpa/inet.h>
 #endif
-#include <errno.h>
-#include "Logger.h"
+#include "BellLogger.h"   // for AbstractLogger
+#include "Logger.h"       // for CSPOT_LOG
+#include "Packet.h"       // for cspot
+#include "Utils.h"        // for extract, pack
 
 using namespace cspot;
 

+ 16 - 3
components/spotify/cspot/src/PlaybackState.cpp

@@ -1,7 +1,20 @@
 #include "PlaybackState.h"
-#include <memory>
-#include "CSpotContext.h"
-#include "Logger.h"
+
+#include <string.h>              // for strdup, memcpy, strcpy, strlen
+#include <cstdint>               // for uint8_t
+#include <cstdlib>               // for free, NULL, realloc, rand
+#include <memory>                // for shared_ptr
+#include <type_traits>           // for remove_extent_t
+#include <utility>               // for swap
+
+#include "BellLogger.h"          // for AbstractLogger
+#include "CSpotContext.h"        // for Context::ConfigState, Context (ptr o...
+#include "ConstantParameters.h"  // for protocolVersion, swVersion
+#include "Logger.h"              // for CSPOT_LOG
+#include "NanoPBHelper.h"        // for pbEncode, pbPutString
+#include "Packet.h"              // for cspot
+#include "pb.h"                  // for pb_bytes_array_t, PB_BYTES_ARRAY_T_A...
+#include "pb_decode.h"           // for pb_release
 
 using namespace cspot;
 

+ 17 - 2
components/spotify/cspot/src/Session.cpp

@@ -1,6 +1,21 @@
 #include "Session.h"
-#include <memory>
-#include "AuthChallenges.h"
+
+#include <limits.h>     // for CHAR_BIT
+#include <cstdint>      // for uint8_t
+#include <functional>   // for __base
+#include <memory>       // for shared_ptr, unique_ptr, make_unique
+#include <random>       // for default_random_engine, independent_bi...
+#include <type_traits>  // for remove_extent_t
+#include <utility>      // for move
+
+#include "ApResolve.h"          // for ApResolve, cspot
+#include "AuthChallenges.h"     // for AuthChallenges
+#include "BellLogger.h"         // for AbstractLogger
+#include "Logger.h"             // for CSPOT_LOG
+#include "LoginBlob.h"          // for LoginBlob
+#include "Packet.h"             // for Packet
+#include "PlainConnection.h"    // for PlainConnection, timeoutCallback
+#include "ShannonConnection.h"  // for ShannonConnection
 
 using random_bytes_engine =
     std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;

+ 3 - 5
components/spotify/cspot/src/Shannon.cpp

@@ -1,9 +1,7 @@
 #include "Shannon.h"
-// #include <bit>
-#include <stdint.h> // for uint32_t
-#include <limits.h> // for CHAR_BIT
-// #define NDEBUG
-#include <assert.h>
+
+#include <limits.h>  // for CHAR_BIT
+#include <stddef.h>  // for size_t
 
 using std::size_t;
 

+ 13 - 1
components/spotify/cspot/src/ShannonConnection.cpp

@@ -1,5 +1,17 @@
 #include "ShannonConnection.h"
-#include "Packet.h"
+
+#include <type_traits>  // for remove_extent_t
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#endif
+
+#include "BellLogger.h"       // for AbstractLogger
+#include "Logger.h"           // for CSPOT_LOG
+#include "Packet.h"           // for Packet, cspot
+#include "PlainConnection.h"  // for PlainConnection
+#include "Shannon.h"          // for Shannon
+#include "Utils.h"            // for pack, extract
 
 using namespace cspot;
 

+ 19 - 11
components/spotify/cspot/src/SpircHandler.cpp

@@ -1,14 +1,22 @@
 #include "SpircHandler.h"
-#include <memory>
-#include "AccessKeyFetcher.h"
-#include "BellUtils.h"
-#include "CSpotContext.h"
-#include "Logger.h"
-#include "MercurySession.h"
-#include "PlaybackState.h"
-#include "TrackPlayer.h"
-#include "TrackReference.h"
-#include "protobuf/spirc.pb.h"
+
+#include <cstdint>              // for uint8_t
+#include <memory>               // for shared_ptr, make_unique, unique_ptr
+#include <type_traits>          // for remove_extent_t
+#include <utility>              // for move
+
+#include "BellLogger.h"         // for AbstractLogger
+#include "CSpotContext.h"       // for Context::ConfigState, Context (ptr only)
+#include "Logger.h"             // for CSPOT_LOG
+#include "MercurySession.h"     // for MercurySession, MercurySession::Response
+#include "NanoPBHelper.h"       // for pbDecode
+#include "Packet.h"             // for cspot
+#include "PlaybackState.h"      // for PlaybackState, PlaybackState::State
+#include "TrackPlayer.h"        // for TrackPlayer
+#include "TrackReference.h"     // for TrackReference
+#include "Utils.h"              // for stringHexToBytes
+#include "pb_decode.h"          // for pb_release
+#include "protobuf/spirc.pb.h"  // for Frame, State, Frame_fields, MessageTy...
 
 using namespace cspot;
 
@@ -155,9 +163,9 @@ void SpircHandler::handleFrame(std::vector<uint8_t>& data) {
        * when last track has been reached, we has to restart as we can't tell the difference */
       if ((!isNextTrackPreloaded && this->playbackState.getNextTrackRef()) || isRequestedFromLoad) {
           CSPOT_LOG(debug, "Seek command while streaming current");
-          sendEvent(EventType::SEEK, (int)playbackState.remoteFrame.position);
           playbackState.updatePositionMs(playbackState.remoteFrame.position);
           trackPlayer->seekMs(playbackState.remoteFrame.position);
+          sendEvent(EventType::SEEK, (int)playbackState.remoteFrame.position);		  
       } else {
           CSPOT_LOG(debug, "Seek command while streaming next or before started");
           isRequestedFromLoad = true;

+ 8 - 1
components/spotify/cspot/src/TimeProvider.cpp

@@ -1,5 +1,12 @@
 #include "TimeProvider.h"
-#include "Logger.h"
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#endif
+
+#include "BellLogger.h"   // for AbstractLogger
+#include "Logger.h"       // for CSPOT_LOG
+#include "Utils.h"        // for extract, getCurrentTimestamp
 
 using namespace cspot;
 

+ 18 - 8
components/spotify/cspot/src/TrackPlayer.cpp

@@ -1,12 +1,22 @@
 #include "TrackPlayer.h"
-#include <cstddef>
-#include <fstream>
-#include <memory>
-#include <mutex>
-#include <vector>
-#include "CDNTrackStream.h"
-#include "Logger.h"
-#include "TrackReference.h"
+
+#include <mutex>               // for mutex, scoped_lock
+#include <string>              // for string
+#include <type_traits>         // for remove_extent_t
+#include <vector>              // for vector, vector<>::value_type
+
+#include "BellLogger.h"        // for AbstractLogger
+#include "BellUtils.h"         // for BELL_SLEEP_MS
+#include "CDNTrackStream.h"    // for CDNTrackStream, CDNTrackStream::TrackInfo
+#include "Logger.h"            // for CSPOT_LOG
+#include "Packet.h"            // for cspot
+#include "TrackProvider.h"     // for TrackProvider
+#include "WrappedSemaphore.h"  // for WrappedSemaphore
+
+namespace cspot {
+struct Context;
+struct TrackReference;
+}  // namespace cspot
 
 using namespace cspot;
 

+ 128 - 66
components/spotify/cspot/src/TrackProvider.cpp

@@ -1,12 +1,26 @@
 #include "TrackProvider.h"
-#include <memory>
-#include "AccessKeyFetcher.h"
-#include "CDNTrackStream.h"
-#include "Logger.h"
-#include "MercurySession.h"
-#include "TrackReference.h"
-#include "Utils.h"
-#include "protobuf/metadata.pb.h"
+
+#include <assert.h>                // for assert
+#include <string.h>                // for strlen
+#include <cstdint>                 // for uint8_t
+#include <functional>              // for __base
+#include <memory>                  // for shared_ptr, weak_ptr, make_shared
+#include <string>                  // for string, operator+
+#include <type_traits>             // for remove_extent_t
+
+#include "AccessKeyFetcher.h"      // for AccessKeyFetcher
+#include "BellLogger.h"            // for AbstractLogger
+#include "CDNTrackStream.h"        // for CDNTrackStream, CDNTrackStream::Tr...
+#include "CSpotContext.h"          // for Context::ConfigState, Context (ptr...
+#include "Logger.h"                // for CSPOT_LOG
+#include "MercurySession.h"        // for MercurySession, MercurySession::Da...
+#include "NanoPBHelper.h"          // for pbArrayToVector, pbDecode
+#include "Packet.h"                // for cspot
+#include "TrackReference.h"        // for TrackReference, TrackReference::Type
+#include "Utils.h"                 // for bytesToHexString, string_format
+#include "WrappedSemaphore.h"      // for WrappedSemaphore
+#include "pb_decode.h"             // for pb_release
+#include "protobuf/metadata.pb.h"  // for Track, _Track, AudioFile, Episode
 
 using namespace cspot;
 
@@ -21,9 +35,11 @@ TrackProvider::TrackProvider(std::shared_ptr<cspot::Context> ctx) {
 
 TrackProvider::~TrackProvider() {
   pb_release(Track_fields, &trackInfo);
+  pb_release(Episode_fields, &trackInfo);
 }
 
-std::shared_ptr<cspot::CDNTrackStream> TrackProvider::loadFromTrackRef(TrackReference& trackRef) {
+std::shared_ptr<cspot::CDNTrackStream> TrackProvider::loadFromTrackRef(
+    TrackReference& trackRef) {
   auto track = std::make_shared<cspot::CDNTrackStream>(this->accessKeyFetcher);
   this->currentTrackReference = track;
   this->trackIdInfo = trackRef;
@@ -34,7 +50,8 @@ std::shared_ptr<cspot::CDNTrackStream> TrackProvider::loadFromTrackRef(TrackRefe
 
 void TrackProvider::queryMetadata() {
   std::string requestUrl = string_format(
-      "hm://metadata/3/%s/%s", trackIdInfo.type == TrackReference::Type::TRACK ? "track" : "episode",
+      "hm://metadata/3/%s/%s",
+      trackIdInfo.type == TrackReference::Type::TRACK ? "track" : "episode",
       bytesToHexString(trackIdInfo.gid).c_str());
   CSPOT_LOG(debug, "Requesting track metadata from %s", requestUrl.c_str());
 
@@ -50,54 +67,40 @@ void TrackProvider::queryMetadata() {
 void TrackProvider::onMetadataResponse(MercurySession::Response& res) {
   CSPOT_LOG(debug, "Got track metadata response");
 
-  pb_release(Track_fields, &trackInfo);
-  pbDecode(trackInfo, Track_fields, res.parts[0]);
-
-  CSPOT_LOG(info, "Track name: %s", trackInfo.name);
-  CSPOT_LOG(info, "Track duration: %d", trackInfo.duration);
-
-  CSPOT_LOG(debug, "trackInfo.restriction.size() = %d",
-            trackInfo.restriction_count);
-
-  int altIndex = -1;
-  while (!canPlayTrack(altIndex)) {
-    altIndex++;
-    CSPOT_LOG(info, "Trying alternative %d", altIndex);
-
-    if (altIndex >= trackInfo.alternative_count) {
-      // no alternatives for song
-      if (!this->currentTrackReference.expired()) {
-        auto trackRef = this->currentTrackReference.lock();
-        trackRef->status = CDNTrackStream::Status::FAILED;
-        trackRef->trackReady->give();
-      }
-      return;
-    }
-  }
-
-  std::vector<uint8_t> trackId;
-  std::vector<uint8_t> fileId;
-  
-  if (altIndex < 0) {
-    trackId = pbArrayToVector(trackInfo.gid);
-    for (int x = 0; x < trackInfo.file_count; x++) {
-      if (trackInfo.file[x].format == ctx->config.audioFormat) {
-        fileId = pbArrayToVector(trackInfo.file[x].file_id);
-        break;  // If file found stop searching
-      }
-    }
-  } else {
-    trackId = pbArrayToVector(trackInfo.alternative[altIndex].gid);
-    for (int x = 0; x < trackInfo.alternative[altIndex].file_count; x++) {
-      if (trackInfo.alternative[altIndex].file[x].format == ctx->config.audioFormat) {
-        fileId =
-            pbArrayToVector(trackInfo.alternative[altIndex].file[x].file_id);
-        break;  // If file found stop searching
+  int alternativeCount, filesCount = 0;
+  bool canPlay = false;
+  AudioFile* selectedFiles;
+  std::vector<uint8_t> trackId, fileId;
+
+  if (trackIdInfo.type == TrackReference::Type::TRACK) {
+    pb_release(Track_fields, &trackInfo);
+    assert(res.parts.size() > 0);
+    pbDecode(trackInfo, Track_fields, res.parts[0]);
+    CSPOT_LOG(info, "Track name: %s", trackInfo.name);
+    CSPOT_LOG(info, "Track duration: %d", trackInfo.duration);
+
+    CSPOT_LOG(debug, "trackInfo.restriction.size() = %d",
+              trackInfo.restriction_count);
+
+    if (doRestrictionsApply(trackInfo.restriction,
+                            trackInfo.restriction_count)) {
+      // Go through alternatives
+      for (int x = 0; x < trackInfo.alternative_count; x++) {
+        if (!doRestrictionsApply(trackInfo.alternative[x].restriction,
+                                 trackInfo.alternative[x].restriction_count)) {
+          selectedFiles = trackInfo.alternative[x].file;
+          filesCount = trackInfo.alternative[x].file_count;
+          trackId = pbArrayToVector(trackInfo.alternative[x].gid);
+          break;
+        }
       }
+    } else {
+      selectedFiles = trackInfo.file;
+      filesCount = trackInfo.file_count;
+      trackId = pbArrayToVector(trackInfo.gid);
     }
-  }
 
-  if (!this->currentTrackReference.expired()) {
+    // Set track's metadata
     auto trackRef = this->currentTrackReference.lock();
 
     auto imageId =
@@ -110,6 +113,60 @@ void TrackProvider::onMetadataResponse(MercurySession::Response& res) {
     trackRef->trackInfo.imageUrl =
         "https://i.scdn.co/image/" + bytesToHexString(imageId);
     trackRef->trackInfo.duration = trackInfo.duration;
+  } else {
+    pb_release(Episode_fields, &episodeInfo);
+    assert(res.parts.size() > 0);
+    pbDecode(episodeInfo, Episode_fields, res.parts[0]);
+
+    CSPOT_LOG(info, "Episode name: %s", episodeInfo.name);
+    CSPOT_LOG(info, "Episode duration: %d", episodeInfo.duration);
+
+    CSPOT_LOG(debug, "episodeInfo.restriction.size() = %d",
+              episodeInfo.restriction_count);
+    if (!doRestrictionsApply(episodeInfo.restriction,
+                             episodeInfo.restriction_count)) {
+      selectedFiles = episodeInfo.file;
+      filesCount = episodeInfo.file_count;
+      trackId = pbArrayToVector(episodeInfo.gid);
+    }
+
+    auto trackRef = this->currentTrackReference.lock();
+
+    auto imageId = pbArrayToVector(episodeInfo.covers->image[0].file_id);
+
+    trackRef->trackInfo.trackId = bytesToHexString(trackIdInfo.gid);
+    trackRef->trackInfo.name = std::string(episodeInfo.name);
+    trackRef->trackInfo.album = "";
+    trackRef->trackInfo.artist = "",
+    trackRef->trackInfo.imageUrl =
+        "https://i.scdn.co/image/" + bytesToHexString(imageId);
+    trackRef->trackInfo.duration = episodeInfo.duration;
+  }
+
+  for (int x = 0; x < filesCount; x++) {
+    CSPOT_LOG(debug, "File format: %d", selectedFiles[x].format);
+    if (selectedFiles[x].format == ctx->config.audioFormat) {
+      fileId = pbArrayToVector(selectedFiles[x].file_id);
+      break;  // If file found stop searching
+    }
+
+    // Fallback to OGG Vorbis 96kbps
+    if (fileId.size() == 0 &&
+        selectedFiles[x].format == AudioFormat_OGG_VORBIS_96) {
+      fileId = pbArrayToVector(selectedFiles[x].file_id);
+    }
+  }
+
+  // No viable files found for playback
+  if (fileId.size() == 0) {
+    CSPOT_LOG(info, "File not available for playback");
+    // no alternatives for song
+    if (!this->currentTrackReference.expired()) {
+      auto trackRef = this->currentTrackReference.lock();
+      trackRef->status = CDNTrackStream::Status::FAILED;
+      trackRef->trackReady->give();
+    }
+    return;
   }
 
   this->fetchFile(fileId, trackId);
@@ -147,20 +204,25 @@ bool countryListContains(char* countryList, char* country) {
   return false;
 }
 
+bool TrackProvider::doRestrictionsApply(Restriction* restrictions, int count) {
+  for (int x = 0; x < count; x++) {
+    if (restrictions[x].countries_allowed != nullptr) {
+      return !countryListContains(restrictions[x].countries_allowed,
+                                  (char*)ctx->config.countryCode.c_str());
+    }
+
+    if (restrictions[x].countries_forbidden != nullptr) {
+      return countryListContains(restrictions[x].countries_forbidden,
+                                 (char*)ctx->config.countryCode.c_str());
+    }
+  }
+
+  return false;
+}
+
 bool TrackProvider::canPlayTrack(int altIndex) {
   if (altIndex < 0) {
-    for (int x = 0; x < trackInfo.restriction_count; x++) {
-      if (trackInfo.restriction[x].countries_allowed != nullptr) {
-        return countryListContains(trackInfo.restriction[x].countries_allowed,
-                                   (char*)ctx->config.countryCode.c_str());
-      }
 
-      if (trackInfo.restriction[x].countries_forbidden != nullptr) {
-        return !countryListContains(
-            trackInfo.restriction[x].countries_forbidden,
-            (char*)ctx->config.countryCode.c_str());
-      }
-    }
   } else {
     for (int x = 0; x < trackInfo.alternative[altIndex].restriction_count;
          x++) {

+ 123 - 137
components/spotify/cspot/src/Utils.cpp

@@ -1,168 +1,154 @@
 #include "Utils.h"
-#include <cstring>
-#include <memory>
+
+#include <stdlib.h>     // for strtol
+#include <iomanip>      // for operator<<, setfill, setw
+#include <iostream>     // for basic_ostream, hex
+#include <sstream>      // for stringstream
+#include <string>       // for string
+#include <type_traits>  // for enable_if<>::type
 #include <chrono>
-#include <string>
-#include <sstream>
-#include <iostream>
-#include <iomanip>
-
-unsigned long long getCurrentTimestamp()
-{
-	return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
+#ifndef _WIN32
+#include <arpa/inet.h>
+#endif
+
+unsigned long long getCurrentTimestamp() {
+  return std::chrono::duration_cast<std::chrono::milliseconds>(
+             std::chrono::system_clock::now().time_since_epoch())
+      .count();
 }
 
 uint64_t hton64(uint64_t value) {
-    int num = 42;
-    if (*(char *)&num == 42) {
-        uint32_t high_part = htonl((uint32_t)(value >> 32));
-        uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFLL));
-        return (((uint64_t)low_part) << 32) | high_part;
-    } else {
-        return value;
-    }
+  int num = 42;
+  if (*(char*)&num == 42) {
+    uint32_t high_part = htonl((uint32_t)(value >> 32));
+    uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFLL));
+    return (((uint64_t)low_part) << 32) | high_part;
+  } else {
+    return value;
+  }
 }
 
-std::vector<uint8_t> stringHexToBytes(const std::string & s) {
-    std::vector<uint8_t> v;
-    v.reserve(s.length() / 2);
+std::vector<uint8_t> stringHexToBytes(const std::string& s) {
+  std::vector<uint8_t> v;
+  v.reserve(s.length() / 2);
 
-    for (std::string::size_type i = 0; i < s.length(); i += 2) {
-        std::string byteString = s.substr(i, 2);
-        uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16);
-        v.push_back(byte);
-    }
+  for (std::string::size_type i = 0; i < s.length(); i += 2) {
+    std::string byteString = s.substr(i, 2);
+    uint8_t byte = (uint8_t)strtol(byteString.c_str(), NULL, 16);
+    v.push_back(byte);
+  }
 
-    return v;
+  return v;
 }
 
 std::string bytesToHexString(const std::vector<uint8_t>& v) {
-    std::stringstream ss;
-    ss << std::hex << std::setfill('0');
-    std::vector<uint8_t>::const_iterator it;
+  std::stringstream ss;
+  ss << std::hex << std::setfill('0');
+  std::vector<uint8_t>::const_iterator it;
 
-    for (it = v.begin(); it != v.end(); it++) {
-        ss << std::setw(2) << static_cast<unsigned>(*it);
-    }
+  for (it = v.begin(); it != v.end(); it++) {
+    ss << std::setw(2) << static_cast<unsigned>(*it);
+  }
 
-    return ss.str();
+  return ss.str();
 }
 
-std::vector<uint8_t> bigNumAdd(std::vector<uint8_t> num, int n)
-{
-    auto carry = n;
-    for (int x = num.size() - 1; x >= 0; x--)
-    {
-        int res = num[x] + carry;
-        if (res < 256)
-        {
-            carry = 0;
-            num[x] = res;
-        }
-        else
-        {
-            // Carry the rest of the division
-            carry = res / 256;
-            num[x] = res % 256;
-
-            // extend the vector at the last index
-            if (x == 0)
-            {
-                num.insert(num.begin(), carry);
-                return num;
-            }
-        }
+std::vector<uint8_t> bigNumAdd(std::vector<uint8_t> num, int n) {
+  auto carry = n;
+  for (int x = num.size() - 1; x >= 0; x--) {
+    int res = num[x] + carry;
+    if (res < 256) {
+      carry = 0;
+      num[x] = res;
+    } else {
+      // Carry the rest of the division
+      carry = res / 256;
+      num[x] = res % 256;
+
+      // extend the vector at the last index
+      if (x == 0) {
+        num.insert(num.begin(), carry);
+        return num;
+      }
     }
+  }
 
-    return num;
+  return num;
 }
 
-std::vector<uint8_t> bigNumDivide(std::vector<uint8_t> num, int n)
-{
-    auto carry = 0;
-    for (int x = 0; x < num.size(); x++)
-    {
-        int res = num[x] + carry * 256;
-        if (res < n)
-        {
-            carry = res;
-            num[x] = 0;
-        }
-        else
-        {
-            // Carry the rest of the division
-            carry = res % n;
-            num[x] = res / n;
-        }
+std::vector<uint8_t> bigNumDivide(std::vector<uint8_t> num, int n) {
+  auto carry = 0;
+  for (int x = 0; x < num.size(); x++) {
+    int res = num[x] + carry * 256;
+    if (res < n) {
+      carry = res;
+      num[x] = 0;
+    } else {
+      // Carry the rest of the division
+      carry = res % n;
+      num[x] = res / n;
     }
+  }
 
-    return num;
+  return num;
 }
 
-std::vector<uint8_t> bigNumMultiply(std::vector<uint8_t> num, int n)
-{
-    auto carry = 0;
-    for (int x = num.size() - 1; x >= 0; x--)
-    {
-        int res = num[x] * n + carry;
-        if (res < 256)
-        {
-            carry = 0;
-            num[x] = res;
-        }
-        else
-        {
-            // Carry the rest of the division
-            carry = res / 256;
-            num[x] = res % 256;
-
-            // extend the vector at the last index
-            if (x == 0)
-            {
-                num.insert(num.begin(), carry);
-                return num;
-            }
-        }
+std::vector<uint8_t> bigNumMultiply(std::vector<uint8_t> num, int n) {
+  auto carry = 0;
+  for (int x = num.size() - 1; x >= 0; x--) {
+    int res = num[x] * n + carry;
+    if (res < 256) {
+      carry = 0;
+      num[x] = res;
+    } else {
+      // Carry the rest of the division
+      carry = res / 256;
+      num[x] = res % 256;
+
+      // extend the vector at the last index
+      if (x == 0) {
+        num.insert(num.begin(), carry);
+        return num;
+      }
     }
+  }
 
-    return num;
+  return num;
 }
-unsigned char h2int(char c)
-{
-    if (c >= '0' && c <='9'){
-        return((unsigned char)c - '0');
-    }
-    if (c >= 'a' && c <='f'){
-        return((unsigned char)c - 'a' + 10);
-    }
-    if (c >= 'A' && c <='F'){
-        return((unsigned char)c - 'A' + 10);
-    }
-    return(0);
+unsigned char h2int(char c) {
+  if (c >= '0' && c <= '9') {
+    return ((unsigned char)c - '0');
+  }
+  if (c >= 'a' && c <= 'f') {
+    return ((unsigned char)c - 'a' + 10);
+  }
+  if (c >= 'A' && c <= 'F') {
+    return ((unsigned char)c - 'A' + 10);
+  }
+  return (0);
 }
 
-std::string urlDecode(std::string str)
-{
-    std::string encodedString="";
-    char c;
-    char code0;
-    char code1;
-    for (int i =0; i < str.length(); i++){
-        c=str[i];
-      if (c == '+'){
-        encodedString+=' ';  
-      }else if (c == '%') {
-        i++;
-        code0=str[i];
-        i++;
-        code1=str[i];
-        c = (h2int(code0) << 4) | h2int(code1);
-        encodedString+=c;
-      } else{
-        
-        encodedString+=c;  
-      }
+std::string urlDecode(std::string str) {
+  std::string encodedString = "";
+  char c;
+  char code0;
+  char code1;
+  for (int i = 0; i < str.length(); i++) {
+    c = str[i];
+    if (c == '+') {
+      encodedString += ' ';
+    } else if (c == '%') {
+      i++;
+      code0 = str[i];
+      i++;
+      code1 = str[i];
+      c = (h2int(code0) << 4) | h2int(code1);
+      encodedString += c;
+    } else {
+
+      encodedString += c;
     }
-    
-   return encodedString;
+  }
+
+  return encodedString;
 }