From 1ee767abbc9a23cf03c1d7c49a57ee437dcc27ae Mon Sep 17 00:00:00 2001 From: Benjamin Loison Date: Sun, 8 Jan 2023 16:31:57 +0100 Subject: [PATCH] Fix #23: YouTube Data API v3 PlaylistItems: list endpoint returns `playlistNotFound` error for regular `uploads` ones --- main.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/main.cpp b/main.cpp index 3a8b84b..4c22519 100644 --- a/main.cpp +++ b/main.cpp @@ -12,8 +12,10 @@ using namespace std; using namespace chrono; using json = nlohmann::json; +enum getJsonBehavior { normal, retryOnCommentsDisabled, returnErrorIfPlaylistNotFound }; + vector getFileContent(string filePath); -json getJson(unsigned short threadId, string url, string directoryPath, bool retryOnCommentsDisabled = false); +json getJson(unsigned short threadId, string url, string directoryPath, getJsonBehavior behavior = normal); void createDirectory(string path), print(ostringstream* toPrint), treatComment(unsigned short threadId, json comment, string channelId), @@ -139,7 +141,7 @@ void treatChannelOrVideo(unsigned short threadId, bool isChannel, string id, str ostringstream toString; toString << "commentThreads?part=snippet,replies&" << (isChannel ? "allThreadsRelatedToChannelId" : "videoId") << "=" << id << "&maxResults=100&pageToken=" << pageToken; string url = toString.str(); - json data = getJson(threadId, url, channelToTreat, pageToken != ""); + json data = getJson(threadId, url, channelToTreat, pageToken == "" ? normal : retryOnCommentsDisabled); bool doesRelyingOnCommentThreadsIsEnough = (!isChannel) || data["error"]["errors"][0]["reason"] != "commentsDisabled"; if(doesRelyingOnCommentThreadsIsEnough) { @@ -199,15 +201,20 @@ void treatChannelOrVideo(unsigned short threadId, bool isChannel, string id, str unsigned int videoCount = atoi(string(data["items"][0]["statistics"]["videoCount"]).c_str()); PRINT(threadId, "The channel has about " << videoCount << " videos.") // `UC-3A9g4U1PpLaeAuD4jSP_w` has a `videoCount` of 2, while its `uploads` playlist contains 3 videos. So we use a strict inequality here. - if(videoCount < 20000) + if(0 < videoCount && videoCount < 20000) { string playlistToTreat = "UU" + channelToTreat.substr(2), pageToken = ""; while(true) { // `snippet` and `status` are unneeded `part`s here but may be interesting later, as we log them. - json data = getJson(threadId, "playlistItems?part=snippet,contentDetails,status&playlistId=" + playlistToTreat + "&maxResults=50&pageToken=" + pageToken, channelToTreat), - items = data["items"]; + json data = getJson(threadId, "playlistItems?part=snippet,contentDetails,status&playlistId=" + playlistToTreat + "&maxResults=50&pageToken=" + pageToken, channelToTreat, returnErrorIfPlaylistNotFound); + if(data.contains("error")) + { + PRINT(threadId, "Not listing comments on videos, as `playlistItems` hasn't found the `uploads` playlist!") + exit(1); + } + json items = data["items"]; for(const auto& item : items) { string videoId = item["contentDetails"]["videoId"]; @@ -226,7 +233,12 @@ void treatChannelOrVideo(unsigned short threadId, bool isChannel, string id, str } break; } - else + else if(videoCount == 0) + { + PRINT(threadId, "Skip listing comments on videos, as they shouldn't be any according to `channels?part=statistics`.") + break; + } + else //if(videoCount >= 20000) { PRINT(threadId, "The videos count of the channel exceeds the supported 20,000 limit!") exit(1); @@ -330,7 +342,7 @@ vector getFileContent(string filePath) return lines; } -json getJson(unsigned short threadId, string url, string directoryPath, bool retryOnCommentsDisabled) +json getJson(unsigned short threadId, string url, string directoryPath, getJsonBehavior behavior) { #ifdef USE_YT_LEMNOSLIFE_COM_NO_KEY_SERVICE string finalUrl = "https://yt.lemnoslife.com/noKey/" + url; @@ -352,9 +364,10 @@ json getJson(unsigned short threadId, string url, string directoryPath, bool ret if(data.contains("error")) { PRINT(threadId, "Found error in JSON at URL: " << finalUrl << " for content: " << content << " !") - if(data["error"]["errors"][0]["reason"] != "commentsDisabled" || retryOnCommentsDisabled) + string reason = data["error"]["errors"][0]["reason"]; + if(reason != "commentsDisabled" || behavior == retryOnCommentsDisabled) { - return getJson(threadId, url, directoryPath); + return reason == "playlistNotFound" && behavior == returnErrorIfPlaylistNotFound ? data : getJson(threadId, url, directoryPath); } }