Skip to content

Commit

Permalink
Implement new recordings API
Browse files Browse the repository at this point in the history
  • Loading branch information
flubshi committed Jun 16, 2024
1 parent 4cfd13f commit b26c751
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 75 deletions.
235 changes: 160 additions & 75 deletions src/WaipuData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <chrono>
#include <ctime>
#include <regex>
#include <set>
#include <thread>

#include <kodi/gui/dialogs/Progress.h>
Expand Down Expand Up @@ -1536,110 +1537,194 @@ PVR_ERROR WaipuData::GetRecordingsAmount(bool deleted, int& amount)
return PVR_ERROR_NO_ERROR;
}

PVR_ERROR WaipuData::GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results)
kodi::addon::PVRRecording WaipuData::ParseRecordingEntry(const rapidjson::Value& recordingEntry)
{
if (!IsConnected())
return PVR_ERROR_SERVER_ERROR;

m_active_recordings_update = true;
kodi::addon::PVRRecording tag;

tag.SetIsDeleted(false);
std::string recordingId = recordingEntry["id"].GetString();
tag.SetRecordingId(recordingId);
tag.SetPlayCount(recordingEntry.HasMember("fullyWatchedCount") &&
recordingEntry["fullyWatchedCount"].GetInt());

const std::string rec_title = recordingEntry["title"].GetString();
tag.SetTitle(rec_title);
tag.SetDirectory(rec_title);

if (recordingEntry.HasMember("previewImage") && !recordingEntry["previewImage"].IsNull())
{
std::string json = HttpGet("https://recording.waipu.tv/api/recordings",
{{"Accept", "application/vnd.waipu.recordings-v2+json"}});
kodi::Log(ADDON_LOG_DEBUG, "[recordings] %s", json.c_str());
std::string rec_img = recordingEntry["previewImage"].GetString();
rec_img = std::regex_replace(rec_img, std::regex("\\$\\{resolution\\}"), "320x180");
tag.SetIconPath(rec_img);
tag.SetThumbnailPath(rec_img);
}

rapidjson::Document doc;
doc.Parse(json.c_str());
if (doc.HasParseError())
if (recordingEntry.HasMember("durationSeconds") && !recordingEntry["durationSeconds"].IsNull())
tag.SetDuration(recordingEntry["durationSeconds"].GetInt());

if (recordingEntry.HasMember("positionPercentage") &&
!recordingEntry["positionPercentage"].IsNull())
{
int positionPercentage = recordingEntry["positionPercentage"].GetInt();
int position = tag.GetDuration() * positionPercentage / 100;
tag.SetLastPlayedPosition(position);
}

if (recordingEntry.HasMember("recordingStartTime") &&
!recordingEntry["recordingStartTime"].IsNull())
tag.SetRecordingTime(Utils::StringToTime(recordingEntry["recordingStartTime"].GetString()));

if (recordingEntry.HasMember("genreDisplayName") && !recordingEntry["genreDisplayName"].IsNull())
{
std::string genreStr = recordingEntry["genreDisplayName"].GetString();
int genre = m_categories.Category(genreStr);
if (genre)
{
kodi::Log(ADDON_LOG_ERROR, "[GetRecordings] ERROR: error while parsing json");
return PVR_ERROR_SERVER_ERROR;
tag.SetGenreSubType(genre & 0x0F);
tag.SetGenreType(genre & 0xF0);
}
kodi::Log(ADDON_LOG_DEBUG, "[recordings] iterate entries");
kodi::Log(ADDON_LOG_DEBUG, "[recordings] size: %i;", doc.Size());
else
{
tag.SetGenreType(EPG_GENRE_USE_STRING);
tag.SetGenreSubType(0); /* not supported */
tag.SetGenreDescription(genreStr);
}
}

int recordings_count = 0;
if (recordingEntry.HasMember("episodeTitle") && !recordingEntry["episodeTitle"].IsNull())
tag.SetEpisodeName(recordingEntry["episodeTitle"].GetString());

for (const auto& recording : doc.GetArray())
{
// skip not FINISHED entries
std::string status = recording["status"].GetString();
if (status != "FINISHED" && status != "RECORDING")
continue;
if (recordingEntry.HasMember("season") && !recordingEntry["season"].IsNull())
tag.SetSeriesNumber(Utils::StringToInt(recordingEntry["season"].GetString(),
PVR_RECORDING_INVALID_SERIES_EPISODE));

kodi::addon::PVRRecording tag;
if (recordingEntry.HasMember("episode") && !recordingEntry["episode"].IsNull())
tag.SetEpisodeNumber(Utils::StringToInt(recordingEntry["episode"].GetString(),
PVR_RECORDING_INVALID_SERIES_EPISODE));

tag.SetIsDeleted(false);
tag.SetRecordingId(recording["id"].GetString());
tag.SetPlayCount(recording.HasMember("watched") && recording["watched"].GetBool());
// epg mapping
if (recordingEntry.HasMember("programId") && !recordingEntry["programId"].IsNull())
{
std::string epg_id = recordingEntry["programId"].GetString();
int dirtyID = Utils::GetIDDirty(epg_id);
tag.SetEPGEventId(dirtyID);
}

const rapidjson::Value& epgData = recording["epgData"];
const bool fetchAdditionalInfos = false; // TODO make setting
if (fetchAdditionalInfos)
{

const std::string rec_title = epgData["title"].GetString();
tag.SetTitle(rec_title);
tag.SetDirectory(rec_title);
std::string json = HttpGet("https://recording.waipu.tv/api/recordings/" + recordingId,
{{"Accept", "application/vnd.waipu.recording-v4+json"}});
kodi::Log(ADDON_LOG_DEBUG, "[recordings] %s", json.c_str());

if (epgData.HasMember("previewImages") && epgData["previewImages"].IsArray() &&
epgData["previewImages"].Size() > 0)
rapidjson::Document doc;
doc.Parse(json.c_str());
if (!doc.HasParseError())
{
if (doc.HasMember("programDetails"))
{
std::string rec_img =
std::string(epgData["previewImages"][0].GetString()) + "?width=256&height=256";
tag.SetIconPath(rec_img);
tag.SetThumbnailPath(rec_img);
if (doc["programDetails"].HasMember("textContent"))
{
if (doc["programDetails"]["textContent"].HasMember("descLong"))
{
std::string descr = doc["programDetails"]["textContent"]["descLong"].GetString();
tag.SetPlot(descr);
tag.SetPlotOutline(descr);
}
else if (doc["programDetails"]["textContent"].HasMember("descShort"))
{
std::string descr = doc["programDetails"]["textContent"]["descShort"].GetString();
tag.SetPlot(descr);
tag.SetPlotOutline(descr);
}
}
if (doc["programDetails"].HasMember("production"))
{
if (doc["programDetails"]["production"].HasMember("year"))
{
std::string year = doc["programDetails"]["production"]["year"].GetString();
tag.SetYear(Utils::StringToInt(year, 1970));
}
}
}
}
}
return tag;
}

if (epgData.HasMember("duration") && !epgData["duration"].IsNull())
tag.SetDuration(Utils::StringToInt(epgData["duration"].GetString(), 0) * 60);

if (epgData.HasMember("season") && !epgData["season"].IsNull())
tag.SetSeriesNumber(Utils::StringToInt(epgData["season"].GetString(),
PVR_RECORDING_INVALID_SERIES_EPISODE));

if (epgData.HasMember("episode") && !epgData["episode"].IsNull())
tag.SetEpisodeNumber(Utils::StringToInt(epgData["episode"].GetString(),
PVR_RECORDING_INVALID_SERIES_EPISODE));
PVR_ERROR WaipuData::GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results)
{
if (!IsConnected())
return PVR_ERROR_SERVER_ERROR;

if (epgData.HasMember("episodeTitle") && !epgData["episodeTitle"].IsNull())
tag.SetEpisodeName(epgData["episodeTitle"].GetString());
m_active_recordings_update = true;

if (epgData.HasMember("year") && !epgData["year"].IsNull())
tag.SetYear(Utils::StringToInt(epgData["year"].GetString(), 1970));
{
std::string recordingGroupsJSON =
HttpGet("https://recording.waipu.tv/api/recordings",
{{"Accept", "application/vnd.waipu.recordings-v4+json"}});
kodi::Log(ADDON_LOG_DEBUG, "[recordingGroupsJSON] %s", recordingGroupsJSON.c_str());

if (recording.HasMember("startTime") && !recording["startTime"].IsNull())
tag.SetRecordingTime(Utils::StringToTime(recording["startTime"].GetString()));
rapidjson::Document recordingGroupsDoc;
recordingGroupsDoc.Parse(recordingGroupsJSON.c_str());
if (recordingGroupsDoc.HasParseError())
{
kodi::Log(ADDON_LOG_ERROR, "[GetRecordings] ERROR: error while parsing recordingGroupsJSON");
return PVR_ERROR_SERVER_ERROR;
}
kodi::Log(ADDON_LOG_DEBUG, "[recordings] getGroups");
std::set<int> recordingGroups;
int recordings_count = 0;

if (epgData.HasMember("description") && !epgData["description"].IsNull())
tag.SetPlot(epgData["description"].GetString());
for (const auto& recordingEntry : recordingGroupsDoc.GetArray())
{
// skip not FINISHED entries
std::string status = recordingEntry["status"].GetString();

if (epgData.HasMember("genreDisplayName") && !epgData["genreDisplayName"].IsNull())
if (recordingEntry.HasMember("recordingGroup") && recordingEntry["recordingGroup"].IsInt())
{
std::string genreStr = epgData["genreDisplayName"].GetString();
int genre = m_categories.Category(genreStr);
if (genre)
{
tag.SetGenreSubType(genre & 0x0F);
tag.SetGenreType(genre & 0xF0);
}
else
{
tag.SetGenreType(EPG_GENRE_USE_STRING);
tag.SetGenreSubType(0); /* not supported */
tag.SetGenreDescription(genreStr);
}
int recordingGroup = recordingEntry["recordingGroup"].GetInt();
kodi::Log(ADDON_LOG_DEBUG, "[recordings] found group: %i;", recordingGroup);
recordingGroups.insert(recordingGroup);
}
else if (status == "FINISHED" || status == "RECORDING")
{
recordings_count++;
results.Add(ParseRecordingEntry(recordingEntry));
}
}

// epg mapping
if (epgData.HasMember("id") && !epgData["id"].IsNull())
for (const int& recordingGroup : recordingGroups)
{
std::string json = HttpGet("https://recording.waipu.tv/api/recordings?recordingGroup=" +
std::to_string(recordingGroup),
{{"Accept", "application/vnd.waipu.recordings-v4+json"}});
kodi::Log(ADDON_LOG_DEBUG, "[recordings] %s", json.c_str());

rapidjson::Document doc;
doc.Parse(json.c_str());
if (doc.HasParseError())
{
std::string epg_id = epgData["id"].GetString();
int dirtyID = Utils::GetIDDirty(epg_id);
tag.SetEPGEventId(dirtyID);
kodi::Log(ADDON_LOG_ERROR, "[GetRecordings] ERROR: error while parsing json");
return PVR_ERROR_SERVER_ERROR;
}
kodi::Log(ADDON_LOG_DEBUG, "[recordings] iterate entries");
kodi::Log(ADDON_LOG_DEBUG, "[recordings] size: %i;", doc.Size());

recordings_count++;
results.Add(tag);
for (const rapidjson::Value& recordingEntry : doc.GetArray())
{
// skip not FINISHED entries
std::string status = recordingEntry["status"].GetString();
if (status != "FINISHED" && status != "RECORDING")
continue;

recordings_count++;
results.Add(ParseRecordingEntry(recordingEntry));
}
m_recordings_count = recordings_count;
}
m_recordings_count = recordings_count;
}

{
Expand Down
1 change: 1 addition & 0 deletions src/WaipuData.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class ATTR_DLL_LOCAL WaipuData : public kodi::addon::CAddonBase,
std::vector<kodi::addon::PVRStreamProperty>& properties) override;

PVR_ERROR GetRecordingsAmount(bool deleted, int& amount) override;
kodi::addon::PVRRecording ParseRecordingEntry(const rapidjson::Value& recordingEntry);
PVR_ERROR GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) override;
PVR_ERROR DeleteRecording(const kodi::addon::PVRRecording& recording) override;
PVR_ERROR GetRecordingStreamProperties(
Expand Down

0 comments on commit b26c751

Please sign in to comment.