123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- #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"
- using namespace cspot;
- TrackProvider::TrackProvider(std::shared_ptr<cspot::Context> ctx) {
- this->accessKeyFetcher = std::make_shared<cspot::AccessKeyFetcher>(ctx);
- this->ctx = ctx;
- this->cdnStream =
- std::make_unique<cspot::CDNTrackStream>(this->accessKeyFetcher);
- this->trackInfo = {};
- }
- TrackProvider::~TrackProvider() {
- pb_release(Track_fields, &trackInfo);
- }
- std::shared_ptr<cspot::CDNTrackStream> TrackProvider::loadFromTrackRef(TrackReference& trackRef) {
- auto track = std::make_shared<cspot::CDNTrackStream>(this->accessKeyFetcher);
- this->currentTrackReference = track;
- this->trackIdInfo = trackRef;
- queryMetadata();
- return track;
- }
- void TrackProvider::queryMetadata() {
- std::string requestUrl = string_format(
- "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());
- auto responseHandler = [this](MercurySession::Response& res) {
- this->onMetadataResponse(res);
- };
- // Execute the request
- ctx->session->execute(MercurySession::RequestType::GET, requestUrl,
- responseHandler);
- }
- 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
- }
- }
- }
- if (!this->currentTrackReference.expired()) {
- auto trackRef = this->currentTrackReference.lock();
- auto imageId =
- pbArrayToVector(trackInfo.album.cover_group.image[0].file_id);
- trackRef->trackInfo.trackId = bytesToHexString(trackIdInfo.gid);
- trackRef->trackInfo.name = std::string(trackInfo.name);
- trackRef->trackInfo.album = std::string(trackInfo.album.name);
- trackRef->trackInfo.artist = std::string(trackInfo.artist[0].name);
- trackRef->trackInfo.imageUrl =
- "https://i.scdn.co/image/" + bytesToHexString(imageId);
- trackRef->trackInfo.duration = trackInfo.duration;
- }
- this->fetchFile(fileId, trackId);
- }
- void TrackProvider::fetchFile(const std::vector<uint8_t>& fileId,
- const std::vector<uint8_t>& trackId) {
- ctx->session->requestAudioKey(
- trackId, fileId,
- [this, fileId](bool success, const std::vector<uint8_t>& audioKey) {
- if (success) {
- CSPOT_LOG(info, "Got audio key");
- if (!this->currentTrackReference.expired()) {
- auto ref = this->currentTrackReference.lock();
- ref->fetchFile(fileId, audioKey);
- }
- } else {
- CSPOT_LOG(error, "Failed to get audio key");
- if (!this->currentTrackReference.expired()) {
- auto ref = this->currentTrackReference.lock();
- ref->fail();
- }
- }
- });
- }
- bool countryListContains(char* countryList, char* country) {
- uint16_t countryList_length = strlen(countryList);
- for (int x = 0; x < countryList_length; x += 2) {
- if (countryList[x] == country[0] && countryList[x + 1] == country[1]) {
- return true;
- }
- }
- 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++) {
- if (trackInfo.alternative[altIndex].restriction[x].countries_allowed !=
- nullptr) {
- return countryListContains(
- trackInfo.alternative[altIndex].restriction[x].countries_allowed,
- (char*)ctx->config.countryCode.c_str());
- }
- if (trackInfo.alternative[altIndex].restriction[x].countries_forbidden !=
- nullptr) {
- return !countryListContains(
- trackInfo.alternative[altIndex].restriction[x].countries_forbidden,
- (char*)ctx->config.countryCode.c_str());
- }
- }
- }
- return true;
- }
|