Benjamin-Loison / YouTube-operational-API

YouTube operational API works when YouTube Data API v3 fails.
373 stars 45 forks source link

Retrieve more than 200 community posts #257

Open Benjamin-Loison opened 5 months ago

Benjamin-Loison commented 5 months ago

Would answer the Stack Overflow question 76699812.

https://www.youtube.com/post/Ugkxvor5AtR4vx01XbXSqXz-I4l9Fae1mmkc

curl.sh is the request to https://www.youtube.com/youtubei/v1/browse when reach final page of https://www.youtube.com/@NatGeo/community.

minimizeCURL curl.sh 'Polar Bear Day'
curl https://www.youtube.com/youtubei/v1/browse -H 'Content-Type: application/json' --data-raw '{"context": {"client": {"clientName": "WEB", "clientVersion": "2.20240325.01.00"}}, "continuation": "4qmFsgKdARIYVUNwVm03Ymc2cFhLbzFQcjZrNWt4RzlBGmhFZ2xqYjIxdGRXNXBkSG00QVFDU0F3Q3FBeWtLSkZFeVl6VlNSazVXVkcxd2FWWllVa05WYWtKWFZFZEdjMWR0T1ZkaE1GWlNVVlZGUFNpLUFmSUdDUW9IU2dDaUFRSUlBUSUzRCUzRJoCFmJhY2tzdGFnZS1pdGVtLXNlY3Rpb24%3D"}'
Python script using hardcoded continuation base64 encoded string: ```py import requests url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': '4qmFsgKdARIYVUNwVm03Ymc2cFhLbzFQcjZrNWt4RzlBGmhFZ2xqYjIxdGRXNXBkSG00QVFDU0F3Q3FBeWtLSkZFeVl6VlNSazVXVkcxd2FWWllVa05WYWtKWFZFZEdjMWR0T1ZkaE1GWlNVVlZGUFNpLUFmSUdDUW9IU2dDaUFRSUlBUSUzRCUzRJoCFmJhY2tzdGFnZS1pdGVtLXNlY3Rpb24=' } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```
Python script first level decoded Protobuf: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': 'Egljb21tdW5pdHm4AQCSAwCqAykKJFEyYzVSRk5WVG1waVZYUkNVakJXVEdGc1dtOVdhMFZSUVVFPSi-AfIGCQoHSgCiAQIIAQ==', '35': 'backstage-item-section' } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, '35': { 'type': 'string' } }, 'field_order': [ '2', '3', '35' ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```
Python script first level decoded Protobuf simplified: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': 'Egljb21tdW5pdHm4AQCSAwCqAykKJFEyYzVSRk5WVG1waVZYUkNVakJXVEdGc1dtOVdhMFZSUVVFPSi-AfIGCQoHSgCiAQIIAQ==', } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, }, 'field_order': [ '2', '3', ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```
Python script second level decoded Protobuf: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '2': 'community', '23': 0, '50': {}, '53': { '1': 'Q2c5RFNVTmpiVXRCUjBWTGFsWm9Wa0VRQUE=', '5': 190 }, '110': { '1': { '9': {}, '20': { '1': 1 } } } } typedef = { '2': { 'type': 'string' }, '23': { 'type': 'int' }, '50': { 'type': 'message', 'message_typedef': {}, 'field_order': [] }, '53': { 'type': 'message', 'message_typedef': { '1': { 'type': 'string' }, '5': { 'type': 'int' } }, 'field_order': [ '1', '5' ] }, '110': { 'type': 'message', 'message_typedef': { '1': { 'type': 'message', 'message_typedef': { '9': { 'type': 'message', 'message_typedef': {}, 'field_order': [] }, '20': { 'type': 'message', 'message_typedef': { '1': { 'type': 'int' } }, 'field_order': [ '1' ] } }, 'field_order': [ '9', '20' ] } }, 'field_order': [ '1' ] } } three = getBase64Protobuf(message, typedef) message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': three, } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, }, 'field_order': [ '2', '3', ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```
Python script second level decoded Protobuf simplified: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '2': 'community', '53': { '1': 'Q2c5RFNVTmpiVXRCUjBWTGFsWm9Wa0VRQUE=', }, } typedef = { '2': { 'type': 'string' }, '53': { 'type': 'message', 'message_typedef': { '1': { 'type': 'string' }, }, }, } three = getBase64Protobuf(message, typedef) message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': three, } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, }, 'field_order': [ '2', '3', ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```

Getting:

blackboxprotobuf.lib.exceptions.DecoderException: Encountered error decoding field 8: GROUP wire types not supported

Base64 decoding leads to Cg9DSUNjbUtBR0VLalZoVkEQAA, then possibly to something like CICcmKAGEKjVhVA but then the base64 decoded does not seem to make much sense.

Related to #256, #153, https://github.com/Benjamin-Loison/YouTube-operational-API/issues/4#issuecomment-1642445988,

Benjamin-Loison commented 5 months ago

Note that for simplifying Protobuf I usually proceed level by level as it helps me prototyping.

None of both following work:

data = base64.b64decode(base64.urlsafe_b64decode('Q2c5RFNVTmpiVXRCUjBWTGFsWm9Wa0VRQUE='), altchars = '-/')
data = base64.urlsafe_b64decode(base64.urlsafe_b64decode('Q2c5RFNVTmpiVXRCUjBWTGFsWm9Wa0VRQUE='))

However, considering Cg9DSUNjbUtBR0VLalZoVkEQAA== as Protobuf works fine!

Python script third level decoded Protobuf: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '1': 'CICcmKAGEKjVhVA', '2': 0 } typedef = { '1': { 'type': 'string' }, '2': { 'type': 'int' } } one = base64.b64encode(getBase64Protobuf(message, typedef).encode('ascii')) message = { '2': 'community', '53': { '1': one, }, } typedef = { '2': { 'type': 'string' }, '53': { 'type': 'message', 'message_typedef': { '1': { 'type': 'string' }, }, }, } three = getBase64Protobuf(message, typedef) message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': three, } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, }, 'field_order': [ '2', '3', ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```
Python script third level decoded Protobuf simplified: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '1': 'CICcmKAGEKjVhVA' } typedef = { '1': { 'type': 'string' } } one = base64.b64encode(getBase64Protobuf(message, typedef).encode('ascii')) message = { '2': 'community', '53': { '1': one, }, } typedef = { '2': { 'type': 'string' }, '53': { 'type': 'message', 'message_typedef': { '1': { 'type': 'string' }, }, }, } three = getBase64Protobuf(message, typedef) message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': three, } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, }, 'field_order': [ '2', '3', ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```
Python script fourth level decoded Protobuf: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '1': 1678118400, '2': 167865000 } typedef = { '1': { 'type': 'int' }, '2': { 'type': 'int' } } one = getBase64Protobuf(message, typedef) message = { '1': one, } typedef = { '1': { 'type': 'string' }, } one = base64.b64encode(getBase64Protobuf(message, typedef).encode('ascii')) message = { '2': 'community', '53': { '1': one, }, } typedef = { '2': { 'type': 'string' }, '53': { 'type': 'message', 'message_typedef': { '1': { 'type': 'string' }, }, }, } three = getBase64Protobuf(message, typedef) message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': three, } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, }, 'field_order': [ '2', '3', ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```
Python script fourth level decoded Protobuf simplified: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '1': 1678118400, } typedef = { '1': { 'type': 'int' }, } one = getBase64Protobuf(message, typedef) message = { '1': one, } typedef = { '1': { 'type': 'string' }, } one = base64.b64encode(getBase64Protobuf(message, typedef).encode('ascii')) message = { '2': 'community', '53': { '1': one, }, } typedef = { '2': { 'type': 'string' }, '53': { 'type': 'message', 'message_typedef': { '1': { 'type': 'string' }, }, }, } three = getBase64Protobuf(message, typedef) message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': three, } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, }, 'field_order': [ '2', '3', ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() print('Polar Bear Day' in str(data)) ```
Benjamin-Loison commented 5 months ago

The question is where does this timestamp comes from.

Note that the community post id does not seem just base64 encoded, nor Protobuf.

Benjamin-Loison commented 5 months ago
Python script fourth level decoded Protobuf simplified modified: ```py import requests import blackboxprotobuf import base64 def getBase64Protobuf(message, typedef): data = blackboxprotobuf.encode_message(message, typedef) return base64.b64encode(data, altchars = b'-/').decode('ascii') message = { '1': 1678000128, } typedef = { '1': { 'type': 'int' }, } one = getBase64Protobuf(message, typedef) message = { '1': one, } typedef = { '1': { 'type': 'string' }, } one = base64.b64encode(getBase64Protobuf(message, typedef).encode('ascii')) message = { '2': 'community', '53': { '1': one, }, } typedef = { '2': { 'type': 'string' }, '53': { 'type': 'message', 'message_typedef': { '1': { 'type': 'string' }, }, }, } three = getBase64Protobuf(message, typedef) message = { '80226972': { '2': 'UCpVm7bg6pXKo1Pr6k5kxG9A', '3': three, } } typedef = { '80226972': { 'type': 'message', 'message_typedef': { '2': { 'type': 'string' }, '3': { 'type': 'string' }, }, 'field_order': [ '2', '3', ] } } continuation = getBase64Protobuf(message, typedef) url = 'https://www.youtube.com/youtubei/v1/browse' headers = { 'Content-Type': 'application/json' } data = { 'context': { 'client': { 'clientName': 'WEB', 'clientVersion': '2.20240313.05.00' } }, 'continuation': continuation } data = requests.post(url, headers = headers, json = data).json() items = data['continuationContents']['itemSectionContinuation']['contents'] postIds = set() for item in items: postId = item['backstagePostThreadRenderer']['post']['backstagePostRenderer']['postId'] postIds.add(postId) print(postId) print('Ugkxvor5AtR4vx01XbXSqXz-I4l9Fae1mmkc' in postIds) ```
1678000128 works but 1678000127 returns: ```json { "responseContext": { "visitorData": "CgtuMVNSUF9pcEJXZyjuiIiwBjIOCgJGUhIIEgQSAgsMICI%3D", "serviceTrackingParams": [ { "service": "GFEEDBACK", "params": [ { "key": "route", "value": "channel.community" }, { "key": "is_casual", "value": "false" }, { "key": "is_owner", "value": "false" }, { "key": "is_alc_surface", "value": "false" }, { "key": "browse_id", "value": "UCpVm7bg6pXKo1Pr6k5kxG9A" }, { "key": "browse_id_prefix", "value": "" }, { "key": "logged_in", "value": "0" }, { "key": "e", "value": "23804281,23843877,23946420,23966208,23983296,23986029,23998056,24004644,24036948,24077241,24080738,24120820,24135310,24166867,24181174,24187377,24241378,24255545,24290971,24377598,24378826,24390675,24425063,24439361,24451319,24453989,24458317,24458324,24458329,24468724,24499532,24506784,24515423,24524098,24524562,24542367,24548627,24548629,24550458,24560416,24566687,24697069,24699899,39324567,39325347,39325801,39325808,39325818,39325930,39325958,39325978,39326019,39326072,39326089,39326096,51003636,51006181,51009781,51010235,51012659,51014091,51016856,51017346,51019626,51020570,51025415,51026715,51027870,51030101,51033399,51033765,51037346,51037349,51037540,51038805,51039200,51040836,51048489,51050361,51053689,51057501,51057846,51057853,51059571,51060353,51061001,51063643,51064835,51069269,51072748,51074183,51074739,51078195,51079239,51079303,51080343,51082238,51083234,51084277,51084288,51089175,51089441,51089956,51091331,51092660,51092929,51094175,51094197,51094200,51094209,51095478,51096389,51096576,51096646,51096989,51098297,51098299,51099408,51101454,51103088,51103261,51103518,51103858,51105630,51105801,51105868,51106995,51107340,51108006,51108624,51108977,51109077,51110160,51111738,51112402,51112970,51112972,51113658,51113661,51116577,51118293,51118932,51119022,51119507,51119512,51119935,51120105,51123077,51124104,51124221,51125637,51125903,51127561,51128547,51128585,51128977,51129056,51129060,51129216,51129219,51129220,51129222,51129224,51129395,51130324,51132393,51133102,51134569,51135346,51135654,51136218,51136785,51136842,51136942,51137028,51137185,51139531,51140748,51141034,51141038,51141523,51141541,51141798,51142840,51142842,51143319,51143633,51144705,51145849,51146435,51146962,51148976,51148985,51149306" } ] }, { "service": "GOOGLE_HELP", "params": [ { "key": "browse_id", "value": "UCpVm7bg6pXKo1Pr6k5kxG9A" }, { "key": "browse_id_prefix", "value": "" } ] }, { "service": "CSI", "params": [ { "key": "c", "value": "WEB" }, { "key": "cver", "value": "2.20240313.05.00" }, { "key": "yt_li", "value": "0" }, { "key": "GetChannelPage_rid", "value": "0x271cf011001dae54" } ] }, { "service": "GUIDED_HELP", "params": [ { "key": "logged_in", "value": "0" } ] }, { "service": "ECATCHER", "params": [ { "key": "client.version", "value": "2.20240313" }, { "key": "client.name", "value": "WEB" } ] } ], "maxAgeSeconds": 300, "mainAppWebResponseContext": { "loggedOut": true, "trackingParam": "kx_fmPxhoPZRLAbLsC20kGZOU80ssd2pgfyYUkma41JMAmwRgkuswmIBwOcCE59TDtslLKPQ-SS" }, "webResponseContextExtensionData": { "hasDecorated": true } }, "continuationContents": { "itemSectionContinuation": { "contents": [ { "messageRenderer": { "text": { "runs": [ { "text": "This channel hasn't posted yet" } ] }, "trackingParams": "CAMQljsYACITCMS5-sDEkIUDFWYz8QUdUmkESA==" } } ], "trackingParams": "CAEQuy8iEwjEufrAxJCFAxVmM_EFHVJpBEg=", "header": { "commentsHeaderRenderer": { "isBackstageContent": true, "trackingParams": "CAIQ7pgBIhMIxLn6wMSQhQMVZjPxBR1SaQRI" } }, "sectionIdentifier": "backstage-item-section" } }, "metadata": { "channelMetadataRenderer": { "title": "National Geographic", "description": "Inspiring people to care about the planet! National Geographic is the world's premium destination for science, exploration, and adventure. \n\nWelcome to the National Geographic community, where we bring our stories, images and video to the world in real-time, inviting followers along on our ongoing 135-year journey. Our yellow border is a portal to the world, showcasing all of the wonder and beauty that it has to offer. This page allows our fans to join us while promoting an enriching and supportive climate for our community. Therefore, we do not tolerate words of hate, harassment or disparagement. We reserve the right to remove any posting or other material that we find off-topic, inappropriate or objectionable.\n", "rssUrl": "https://www.youtube.com/feeds/videos.xml?channel_id=UCpVm7bg6pXKo1Pr6k5kxG9A", "externalId": "UCpVm7bg6pXKo1Pr6k5kxG9A", "keywords": "national geographic animal earth water mountain adventure wild attack explorer dog whisperer dogtown cesar milan", "ownerUrls": [ "http://www.youtube.com/@NatGeo" ], "avatar": { "thumbnails": [ { "url": "https://yt3.googleusercontent.com/UsAi6ND-hXCgTyF9iwndj0cfqZTTZOMXnRc3o51CwwfLluIJluPeNFV4DwilfOhAPJnkTS0c=s900-c-k-c0x00ffffff-no-rj", "width": 900, "height": 900 } ] }, "channelUrl": "https://www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A", "isFamilySafe": true, "facebookProfileId": "natgeo", "availableCountryCodes": [ "MT", "NU", "PR", "HT", "NR", "GT", "TO", "AG", "MZ", "BT", "BI", "WF", "BM", "SK", "FK", "MA", "CG", "CM", "EH", "HK", "SY", "YT", "JO", "MY", "MO", "SA", "GF", "KM", "ME", "GA", "NE", "SH", "TG", "UG", "PL", "TT", "GD", "LS", "JM", "MR", "KW", "NG", "MF", "MU", "DJ", "IL", "KH", "NC", "SJ", "FO", "GS", "KN", "LT", "PA", "ZA", "IO", "SX", "FR", "PN", "AD", "FM", "CY", "UY", "NL", "VU", "QA", "KE", "PW", "KY", "JE", "BV", "JP", "GW", "CH", "HU", "RS", "DE", "AS", "HM", "SB", "NZ", "HN", "ZW", "VA", "CV", "AL", "KR", "SZ", "NP", "FI", "GN", "SL", "VI", "EC", "LV", "BB", "ET", "HR", "CU", "ID", "IQ", "OM", "MK", "CR", "AR", "IM", "NF", "CW", "AF", "IN", "GR", "TK", "FJ", "MM", "TH", "NI", "RO", "TR", "SO", "SI", "UM", "NO", "AE", "BJ", "AO", "CA", "MW", "EE", "CZ", "VG", "KP", "UA", "BH", "AZ", "AM", "TC", "RW", "AW", "BN", "TZ", "SR", "GP", "IT", "PH", "SV", "BQ", "EG", "KZ", "DZ", "PM", "BR", "IS", "LU", "ST", "MV", "ES", "VE", "BY", "IR", "GB", "MS", "SM", "DM", "GG", "TW", "PY", "UZ", "PG", "SN", "CC", "GE", "TL", "MN", "SS", "MC", "BW", "CI", "ER", "TF", "PT", "TD", "CO", "BL", "LB", "CD", "AQ", "BS", "LC", "KG", "NA", "SG", "MQ", "AU", "VN", "PS", "PF", "TN", "DK", "BG", "LA", "IE", "CX", "AT", "GI", "LK", "BA", "RU", "SD", "WS", "GY", "CL", "GQ", "AX", "MG", "TM", "LI", "KI", "PE", "MX", "CN", "MD", "CK", "SE", "GL", "YE", "PK", "GH", "BF", "BE", "SC", "BO", "VC", "CF", "LR", "MH", "RE", "US", "BZ", "LY", "MP", "ML", "ZM", "TJ", "BD", "AI", "DO", "GM", "GU", "TV" ], "androidDeepLink": "android-app://com.google.android.youtube/http/www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A", "androidAppindexingLink": "android-app://com.google.android.youtube/http/www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A", "iosAppindexingLink": "ios-app://544007664/vnd.youtube/www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A", "vanityChannelUrl": "http://www.youtube.com/@NatGeo" } }, "trackingParams": "CAAQhGciEwjEufrAxJCFAxVmM_EFHVJpBEg=", "microformat": { "microformatDataRenderer": { "urlCanonical": "https://www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A", "title": "National Geographic", "description": "Inspiring people to care about the planet! National Geographic is the world's premium destination for science, exploration, and adventure. Welcome to the Nat...", "thumbnail": { "thumbnails": [ { "url": "https://yt3.googleusercontent.com/UsAi6ND-hXCgTyF9iwndj0cfqZTTZOMXnRc3o51CwwfLluIJluPeNFV4DwilfOhAPJnkTS0c=s200-c-k-c0x00ffffff-no-rj?days_since_epoch=19807", "width": 200, "height": 200 } ] }, "siteName": "YouTube", "appName": "YouTube", "androidPackage": "com.google.android.youtube", "iosAppStoreId": "544007664", "iosAppArguments": "https://www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A", "ogType": "yt-fb-app:channel", "urlApplinksWeb": "https://www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A?feature=applinks", "urlApplinksIos": "vnd.youtube://www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A?feature=applinks", "urlApplinksAndroid": "vnd.youtube://www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A?feature=applinks", "urlTwitterIos": "vnd.youtube://www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A?feature=twitter-deep-link", "urlTwitterAndroid": "vnd.youtube://www.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A?feature=twitter-deep-link", "twitterCardType": "summary", "twitterSiteHandle": "@YouTube", "schemaDotOrgType": "http://schema.org/http://schema.org/YoutubeChannelV2", "noindex": false, "unlisted": false, "familySafe": true, "tags": [ "national", "geographic", "animal", "earth", "water", "mountain", "adventure", "wild", "attack", "explorer", "dog", "whisperer", "dogtown", "cesar", "milan" ], "availableCountries": [ "MT", "NU", "PR", "HT", "NR", "GT", "TO", "AG", "MZ", "BT", "BI", "WF", "BM", "SK", "FK", "MA", "CG", "CM", "EH", "HK", "SY", "YT", "JO", "MY", "MO", "SA", "GF", "KM", "ME", "GA", "NE", "SH", "TG", "UG", "PL", "TT", "GD", "LS", "JM", "MR", "KW", "NG", "MF", "MU", "DJ", "IL", "KH", "NC", "SJ", "FO", "GS", "KN", "LT", "PA", "ZA", "IO", "SX", "FR", "PN", "AD", "FM", "CY", "UY", "NL", "VU", "QA", "KE", "PW", "KY", "JE", "BV", "JP", "GW", "CH", "HU", "RS", "DE", "AS", "HM", "SB", "NZ", "HN", "ZW", "VA", "CV", "AL", "KR", "SZ", "NP", "FI", "GN", "SL", "VI", "EC", "LV", "BB", "ET", "HR", "CU", "ID", "IQ", "OM", "MK", "CR", "AR", "IM", "NF", "CW", "AF", "IN", "GR", "TK", "FJ", "MM", "TH", "NI", "RO", "TR", "SO", "SI", "UM", "NO", "AE", "BJ", "AO", "CA", "MW", "EE", "CZ", "VG", "KP", "UA", "BH", "AZ", "AM", "TC", "RW", "AW", "BN", "TZ", "SR", "GP", "IT", "PH", "SV", "BQ", "EG", "KZ", "DZ", "PM", "BR", "IS", "LU", "ST", "MV", "ES", "VE", "BY", "IR", "GB", "MS", "SM", "DM", "GG", "TW", "PY", "UZ", "PG", "SN", "CC", "GE", "TL", "MN", "SS", "MC", "BW", "CI", "ER", "TF", "PT", "TD", "CO", "BL", "LB", "CD", "AQ", "BS", "LC", "KG", "NA", "SG", "MQ", "AU", "VN", "PS", "PF", "TN", "DK", "BG", "LA", "IE", "CX", "AT", "GI", "LK", "BA", "RU", "SD", "WS", "GY", "CL", "GQ", "AX", "MG", "TM", "LI", "KI", "PE", "MX", "CN", "MD", "CK", "SE", "GL", "YE", "PK", "GH", "BF", "BE", "SC", "BO", "VC", "CF", "LR", "MH", "RE", "US", "BZ", "LY", "MP", "ML", "ZM", "TJ", "BD", "AI", "DO", "GM", "GU", "TV" ], "linkAlternates": [ { "hrefUrl": "https://m.youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A" }, { "hrefUrl": "android-app://com.google.android.youtube/http/youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A" }, { "hrefUrl": "ios-app://544007664/http/youtube.com/channel/UCpVm7bg6pXKo1Pr6k5kxG9A" } ] } } } ```

Note the This channel hasn't posted yet.

Should check the timestamp again on the next community post publication to see if it still works.

I set a notification system to notify me once a new community post is published on this channel.

    {
        'url': 'https://yt.lemnoslife.com/channels?part=community&id=UCpVm7bg6pXKo1Pr6k5kxG9A',
        'message': 'New YouTube community post, consider investigating again https://github.com/Benjamin-Loison/YouTube-operational-API/issues/257',
        'filterText': lambda text : json.loads(text)['items'][0]['community'][0]['id'],
    },
Benjamin-Loison commented 4 months ago

Multiple comments may have been published as I stopped for a while the notification algorithm.

Benjamin-Loison commented 4 months ago

Well this timestamp does not work anymore and now the next page timestamp is 1679071734.

date -d @1678118400
Mon Mar  6 05:00:00 PM CET 2023
date -d @1679071734
Fri Mar 17 05:48:54 PM CET 2023

The latter date does not seem related to current date and it does not seem clear to state if it is the post date as we only know that it was 1 year ago, as channels?part=community seems to confirm.

Benjamin-Loison commented 1 month ago
print(json.dumps(getCommunityPost(1678118400 + 3600 * 24 * 25)['continuationContents']['itemSectionContinuation']['contents'][0]))
print(getCommunityPost(1678118400 + 3600 * 24 * 25)['continuationContents']['itemSectionContinuation']['contents'][0]['backstagePostThreadRenderer']['post']['backstagePostRenderer']['postId'])
UgkxWv2lH-5Jn02GWCPtgSz7nieXeclHLoG4
len(communityPosts)
200
'UgkxWv2lH-5Jn02GWCPtgSz7nieXeclHLoG4' in communityPosts
True

seems to show that using older than normally currently provided timestamp does not help.

Benjamin-Loison commented 6 days ago

Would answer the Stack Overflow question 78985164.

Benjamin-Loison commented 6 days ago

To verify again that unable to get more than 200 community posts can list first 200 ones and from last continuation timestamp remove one hour per hour until a significant amount of time showing that no community post posted before is retrievable. To make sure could go until channel creation. Note that this is assuming a community post has been published more than one hour before the first retrievable one which seems to be a reasonable assumption if some posts have been posted.

Benjamin-Loison commented 6 days ago

Based on #295#issuecomment-2267626825:

Consider last params['pageToken'] when iterating over YouTube operational API channels?part=community

import requests
import blackboxprotobuf
import base64
import time
import math
from datetime import datetime, timedelta
import re
from enum import Enum, auto
import time
import urllib.parse as ul

CHANNEL_ID = 'UCpVm7bg6pXKo1Pr6k5kxG9A'
YOUTUBE_OPERATIONAL_API_INSTANCE_URL = 'http://localhost/YouTube-operational-API'

def getBase64Protobuf(message, typedef):
    data = blackboxprotobuf.encode_message(message, typedef)
    return base64.b64encode(data).decode('ascii')

def getContinuation(timestamp):
    message = {
        '1': timestamp,
    }

    typedef = {
        '1': {
            'type': 'int'
        },
    }

    one = getBase64Protobuf(message, typedef)

    message = {
        '1': one,
    }

    typedef = {
        '1': {
            'type': 'string'
        },
    }

    one = base64.b64encode(getBase64Protobuf(message, typedef).encode('ascii'))

    message = {
        '2': 'community',
        '53': {
            '1': one,
        },
    }

    typedef = {
        '2': {
            'type': 'string'
        },
        '53': {
            'type': 'message',
            'message_typedef': {
                '1': {
                    'type': 'string'
                },
            },
        },
    }

    three = getBase64Protobuf(message, typedef)

    message = {
        '80226972': {
            '2': CHANNEL_ID,
            '3': three,
        }
    }

    typedef = {
        '80226972': {
            'type': 'message',
            'message_typedef': {
                '2': {
                    'type': 'string'
                },
                '3': {
                    'type': 'string'
                },
            },
            'field_order': [
                '2',
                '3',
            ]
        }
    }

    continuation = getBase64Protobuf(message, typedef)
    return continuation

def getCommunity(timestamp):
    continuation = getContinuation(timestamp)

    json_data = {
        'context': {
            'client': {
                'clientName': 'WEB',
                'clientVersion': '2.20240731.04.00',
            },
        },
        'continuation': continuation,
    }

    response = requests.post('https://www.youtube.com/youtubei/v1/browse', json = json_data)
    return response.json()

def getApi(url, params):
    return requests.get(YOUTUBE_OPERATIONAL_API_INSTANCE_URL + f'/{url}', params).json()

params = {
    'part': 'about',
    'id': CHANNEL_ID,
}

channelJoinedDateTime = getApi('channels', params)['items'][0]['about']['stats']['joinedDate']

HOURS_AGO = re.compile('(\d) hour(s|) ago')
DAYS_AGO = re.compile('(\d) day(s|) ago')
MONTHS_AGO = re.compile('(\d) month(s|) ago')

class Approximation(Enum):
    UPPER = auto()
    LOWER = auto()

# To avoid possible time shift issue in community post date string and pagination.
MOST_TIME_SHIFT = timedelta(days = 1)

def getTimeDelta(timeDeltaStr, approximation):
    hoursAgoMatch = HOURS_AGO.match(timeDeltaStr)
    relativeOffsetUnit = -1 if approximation is Approximation.UPPER else 1
    relativeOffset = relativeOffsetUnit * MOST_TIME_SHIFT
    if hoursAgoMatch is not None:
        myTimedelta = timedelta(hours = int(hoursAgoMatch[1]) + relativeOffsetUnit)
    daysAgoMatch = DAYS_AGO.match(timeDeltaStr)
    if daysAgoMatch is not None:
        myTimedelta = timedelta(days = int(daysAgoMatch[1]) + relativeOffsetUnit)
    monthsAgoMatch = MONTHS_AGO.match(timeDeltaStr)
    #if monthsAgoMatch is not None:
        # Between 28 and 31.
    #    myTimedelta = timedelta(days = 31 * int(monthsAgoMatch[1]) + relativeOffsetUnit)
    return int((myTimedelta + relativeOffset).total_seconds())

def decodeBase64Protobuf(base64Protobuf):
    #print(ul.unquote_plus(base64Protobuf))
    data = base64.b64decode(ul.unquote_plus(base64Protobuf) + '==', altchars = '-_')
    message = blackboxprotobuf.decode_message(data)[0]
    return message

def getTimestampFromPageToken(pageToken):
    message = decodeBase64Protobuf(pageToken)
    #print(json.dumps(message['80226972']['3'], indent = 4))
    message = decodeBase64Protobuf(message['80226972']['3'])
    message = decodeBase64Protobuf(base64.b64decode(message['53']['1'], altchars = '-_').decode('ascii'))

    message = decodeBase64Protobuf(message['1'])
    #print(json.dumps(message, indent = 4))
    return message['1']

communityPosts = []
params = {
    'part': 'community',
    'id': CHANNEL_ID,
}
communityPostIds = set()
while True:
    data = getApi('channels', params)
    item = data['items'][0]
    for communityPost in item['community']:
        communityPosts += [{
            'id': communityPost['id'],
            'date': communityPost['date'],
        }]
        communityPostIds.add(communityPost['id'])
    print(len(communityPostIds))
    if not 'nextPageToken' in item:
        break
    nextPageToken = item['nextPageToken']
    #print('received', nextPageToken)
    timestamp = getTimestampFromPageToken(nextPageToken)# + 1
    print(timestamp)
    #nextPageToken = getContinuation(timestamp)
    #print('sent', nextPageToken)
    params['pageToken'] = nextPageToken

currentTimestamp = time.time()
currentTimestampCeil = math.ceil(currentTimestamp)

communityPostIds = set()
def getCommunityPosts(timestamp, approximation):
    shift = 1
    while True:
        community = getCommunity(timestamp + (1 if approximation is Approximation.UPPER else -1) * shift)
        items = community['continuationContents']['itemSectionContinuation']['contents']
        content = items[0]
        if 'messageRenderer' in content and content['messageRenderer']['text']['runs'][0]['text'] == "This channel hasn't posted yet":
            #if shift == 1:
            #    print('2 community posts missing in a row!')
            #print(f'{shift=}')
            shift *= 2
            continue
        print(f'{len(items)=}')
        for item in items:
            if not 'backstagePostThreadRenderer' in item:
                #print(json.dumps(item, indent = 4))
                continuationToken = item['continuationItemRenderer']['continuationEndpoint']['continuationCommand']['token']
                #print(continuationToken)
                timestamp = getTimestampFromPageToken(continuationToken)
                print(f'{timestamp=}')
                return getCommunityPosts(timestamp, approximation)
            itemId = item['backstagePostThreadRenderer']['post']['backstagePostRenderer']['postId']
            communityPostIds.add(itemId)
            print(f'{len(communityPostIds)=} {itemId=}')
        break

getCommunityPosts(currentTimestampCeil, Approximation.UPPER)
Benjamin-Loison commented 6 days ago

Note that first timestamp returned in nextPageToken (1723118400) is not current one (1726330724).

Benjamin-Loison commented 6 days ago
Output: ``` len(items)=11 len(communityPostIds)=1 itemId='UgkxcxV7Qq6yTy5-FBD38rzT1QgsF0Cupp0P' len(communityPostIds)=2 itemId='Ugkxzyywo6bsQTmBUvT89JYe6CnGbmgUAh9P' len(communityPostIds)=3 itemId='UgkxWLLktHUnKYdIzB2ZK3k5XXhAmq4aIUhk' len(communityPostIds)=4 itemId='UgkxSOM8vhs8WWAZ_hyt_krpc4XP5zxn0cvE' len(communityPostIds)=5 itemId='Ugkxb_XpJw6TW54XAi0XCrksaB-fGC4KrhI4' len(communityPostIds)=6 itemId='UgkxfKdiNrqkVEPGolIrpGltT_DKkuq3IbQ8' len(communityPostIds)=7 itemId='UgkxGGKtVqEkj6nouKdFKbF6DTpJST-qSnnd' len(communityPostIds)=8 itemId='UgkxUvJ3Jxtx3M6ufHHwhviZf4JiIieeuj4P' len(communityPostIds)=9 itemId='UgkxcYUEsdLfuvKVc6PP0H3P2WgFKI_ZLuWk' len(communityPostIds)=10 itemId='Ugkxzv2Td_uS9Aw5BkK1KKW_1Pt5ptTKpjbn' timestamp=1723118400 len(items)=11 len(communityPostIds)=10 itemId='Ugkxzv2Td_uS9Aw5BkK1KKW_1Pt5ptTKpjbn' len(communityPostIds)=11 itemId='Ugkx254iv-3nYTslcU_lK0PKr-kwnGgvmrlm' len(communityPostIds)=12 itemId='UgkxR33ap24Qongct7C7yGBktBF3TMo8R9Sh' len(communityPostIds)=13 itemId='UgkxnTGQYf4_wJb4_sfyNvUdQRXCTrfUXmFJ' len(communityPostIds)=14 itemId='Ugkx32muMk6lo0SeXp3Shi5BMUS7TPxSmy_i' len(communityPostIds)=15 itemId='UgkxdfgC-WvI8uyPsTXmZ_N67zFc2QBOBxDy' len(communityPostIds)=16 itemId='Ugkxvhd6tOC5wHEStA6TNcXZJ3Y_SgPbvG_e' len(communityPostIds)=17 itemId='UgkxJ3dcgsoaqlUnm8Mn3XarzdxYhTi437jo' len(communityPostIds)=18 itemId='UgkxXenoFdqx4wSUwBc4BuxaAi37njsxKp90' len(communityPostIds)=19 itemId='Ugkxy-JJ3XLd38aFUWNuK3tA-IKgYCiayK1s' timestamp=1719838801 len(items)=11 len(communityPostIds)=19 itemId='Ugkxy-JJ3XLd38aFUWNuK3tA-IKgYCiayK1s' len(communityPostIds)=20 itemId='UgkxHupp34iqFu_3MnA5mVwyoBkQhON1BNyr' len(communityPostIds)=21 itemId='UgkxCVt7ZYJIeb-6YJiyqbU1-BFZTQ6AA09R' len(communityPostIds)=22 itemId='UgkxT6QLLO5z6IRf9582857X-d6-Y4rc3z9R' len(communityPostIds)=23 itemId='Ugkxn4cMdq7pChKdPvwyxEFcN_OEm19DFqnb' len(communityPostIds)=24 itemId='Ugkx6lNoCYQukMn4Dn-_7f7vqYXyoKi6JiUw' len(communityPostIds)=25 itemId='UgkxcQXc1bEH5h3lVwrhz_TqcJeR-D2ZLHc-' len(communityPostIds)=26 itemId='UgkxzkGf857I5BLelhofB0fAUmmM2NLzt_4n' len(communityPostIds)=27 itemId='Ugkx6H_v3qbuEjRxz8UnzOHdhGxQFoXwrur4' len(communityPostIds)=28 itemId='UgkxZliTcp07IRo-ScvFKxu-16noV3_uTsiN' timestamp=1715868000 len(items)=11 len(communityPostIds)=28 itemId='UgkxZliTcp07IRo-ScvFKxu-16noV3_uTsiN' len(communityPostIds)=29 itemId='UgkxhhsKWaR6ax3MK4f4fKFhRbcLzzi_4fL7' len(communityPostIds)=30 itemId='UgkxRKdFLqBDX-jel6DSXjcY34snS_8xAeOE' len(communityPostIds)=31 itemId='UgkxbN3HhAm_BWiisdGgA9LTZMTTgOFFLeBC' len(communityPostIds)=32 itemId='Ugkxg38JlDugxbAevod-YH96DuaZgfy5IAmg' len(communityPostIds)=33 itemId='UgkxMHy3ri9IycFNCcLKOBEP1wxr3z6iiXfn' len(communityPostIds)=34 itemId='UgkxDqDBhsELTHs6eoCJYLLUgl4cjKJEWryb' len(communityPostIds)=35 itemId='Ugkxgrm2emNMVcJikPeCp4pRaGp4BdNYLq-h' len(communityPostIds)=36 itemId='Ugkxx9KAtU_mMMMChQf-O4u2dzVSzu9HoxX8' len(communityPostIds)=37 itemId='Ugkx-IGKTHJ2ua-PDpbbNw8pw_bjARlIWwIS' timestamp=1713457097 len(items)=11 len(communityPostIds)=37 itemId='Ugkx-IGKTHJ2ua-PDpbbNw8pw_bjARlIWwIS' len(communityPostIds)=38 itemId='Ugkxjv7cSMaCTuVjW7pz-P9uEhfJLC8Vrk9f' len(communityPostIds)=39 itemId='UgkxNKMwHy38HbGXx9q4w9RGr2svNBl45LJ6' len(communityPostIds)=40 itemId='UgkxP4L02ZtrUGnXXCQulBp9My9Pq56EEPc6' len(communityPostIds)=41 itemId='UgkxSdU6GBvTQma9TK9APhnpG8SlJxDEDil6' len(communityPostIds)=42 itemId='UgkxluujjpSCDuErPs1DSaxGs8mxpkOPtwTt' len(communityPostIds)=43 itemId='UgkxFZgMn9i9OFOqvwjctFDlpZjebVDyHzS_' len(communityPostIds)=44 itemId='UgkxEe7iQ7rQFSrORs8Kj2Mi_zl10KXfRPsj' len(communityPostIds)=45 itemId='UgkxQahdELhjnkfohaqoy3hl1Xqa1_ArCHaX' len(communityPostIds)=46 itemId='UgkxOjYe_xjjI4B6ahwxT9oxqeB0_GTZVy1Q' timestamp=1707766035 len(items)=11 len(communityPostIds)=46 itemId='UgkxOjYe_xjjI4B6ahwxT9oxqeB0_GTZVy1Q' len(communityPostIds)=47 itemId='UgkxHqSnjy_N0IJI2M4MBcsh5xQId8F_n7DT' len(communityPostIds)=48 itemId='Ugkx7bgob_H9U_PKtTOjJEGxyFEw1TvUPJPA' len(communityPostIds)=49 itemId='UgkxQbSDxZL5DVsGVPZ7sAIMecW8z5W1q4yY' len(communityPostIds)=50 itemId='UgkxxItyN2PokbyULelJeF9h0PO1aYu9wHlS' len(communityPostIds)=51 itemId='UgkxMVsrJQ48ZcF0qgza1-O2mJWEMQWUaIOO' len(communityPostIds)=52 itemId='Ugkx8PWsmZENQfisHmFuJeelDqe0kJ1h82de' len(communityPostIds)=53 itemId='Ugkxb-RCIU-4V-TJ4DqxQ3rhHpnIeJuy2TSG' len(communityPostIds)=54 itemId='UgkxbVfvQ2dUkDRWSxQcMmDiHXY0hxCF2N9_' len(communityPostIds)=55 itemId='Ugkx8PbHq034ajYjdHoLOdZ_EQGrua_nYCX9' timestamp=1705371453 len(items)=11 len(communityPostIds)=55 itemId='Ugkx8PbHq034ajYjdHoLOdZ_EQGrua_nYCX9' len(communityPostIds)=56 itemId='UgkxC3PwRd9t5tyDpYDSgPE9NUXNTXoIiJ4u' len(communityPostIds)=57 itemId='UgkxvRlyeno9dT_eM_volq5Awlo3ocIuYDYo' len(communityPostIds)=58 itemId='UgkxEnvc-Uu4YEwWlTvU_yfAOIxS832trcMv' len(communityPostIds)=59 itemId='Ugkxh3IRebx5hiflVOMayltKVPH5WI4V_2B4' len(communityPostIds)=60 itemId='Ugkx9et_kHwkB7LuT-cSd3x5Mc96EXWdotSK' len(communityPostIds)=61 itemId='Ugkxh4rcipgUozgLTDSndK5vQEumJZfiw6p8' len(communityPostIds)=62 itemId='UgkxWp-GjCuj4OMtF3ak5f63Zg97rGKsPb-k' len(communityPostIds)=63 itemId='UgkxHZzEp0dKuIy-y4W3beY0PVrY_rfPfoFU' len(communityPostIds)=64 itemId='Ugkxq7kGbyrpk_kiVLgRRKrAl8eFlGl2WYJC' timestamp=1703264401 len(items)=11 len(communityPostIds)=64 itemId='Ugkxq7kGbyrpk_kiVLgRRKrAl8eFlGl2WYJC' len(communityPostIds)=65 itemId='UgkxCZYpxTXQQ04Lg1iUBImQ5U3eQ2BXW0UH' len(communityPostIds)=66 itemId='UgkxTvd1k2xs11pxm6vMjq3PxJQR6aK31xah' len(communityPostIds)=67 itemId='UgkxTDdvwkorheq18-5s67GGcRa6UeEzBMn7' len(communityPostIds)=68 itemId='UgkxoYZp3x0HviIZ4h_Gxi7SXp6pQAN1xMxP' len(communityPostIds)=69 itemId='Ugkxw08TV8zRoGgX2jXUyiz-pbmxBlttjzo9' len(communityPostIds)=70 itemId='UgkxyF3Rg81-QtERIO17X1Npps0Q-6XSnuRj' len(communityPostIds)=71 itemId='Ugkxu-3sAGNz0ErJxKOoviUaKAK312dsMRqf' len(communityPostIds)=72 itemId='UgkxM1tEHGlORPWrhE8AtYoqHsWbfCsUYlYS' len(communityPostIds)=73 itemId='UgkxQ3fZtm8ZbuUpaVFmP4TSsMOsCzahPkiT' timestamp=1700236804 len(items)=11 len(communityPostIds)=73 itemId='UgkxQ3fZtm8ZbuUpaVFmP4TSsMOsCzahPkiT' len(communityPostIds)=74 itemId='UgkxZW-ldSLKx3qxntXk428jVfzbCdIKGhX9' len(communityPostIds)=75 itemId='UgkxUuI01G1UqIMgXoNig3F8qyYp06skdnpW' len(communityPostIds)=76 itemId='UgkxUOtzAl6T8vAB3JSyzgE4WnvS0CPlDBaw' len(communityPostIds)=77 itemId='UgkxhMzg07NE_DmOmlVVG9RfBsYTPkdWxlGW' len(communityPostIds)=78 itemId='UgkxZgVuxAx6lDnIUSzFtZcZlP4y8On50ccr' len(communityPostIds)=79 itemId='UgkxCZWZvBfWipaSako96LAQRJ_zcJythkIl' len(communityPostIds)=80 itemId='UgkxVKjoExo3QxNzXUaydXrArrX2FG9YBVb3' len(communityPostIds)=81 itemId='Ugkx-LGEDLlyKuUqlbCmH2J5Fp3J1tloigzk' len(communityPostIds)=82 itemId='UgkxDajgxlgYwD0YG9Rm3ou6xjB6NV8o-qd9' timestamp=1698768000 len(items)=11 len(communityPostIds)=82 itemId='UgkxDajgxlgYwD0YG9Rm3ou6xjB6NV8o-qd9' len(communityPostIds)=83 itemId='UgkxTUQFm0hpPoFFkkf2f17REwvELYHbCV31' len(communityPostIds)=84 itemId='UgkxDhd9YsjDLoreCXcxqe7_kCUv1lmKsNuG' len(communityPostIds)=85 itemId='Ugkxb0DejpNXLvQK74zZSicDzkHEruJ3Clwd' len(communityPostIds)=86 itemId='Ugkx9TOuAFQJMxclIrP0hRwczjegcJzyzns2' len(communityPostIds)=87 itemId='Ugkxa2r7d5Z8IfgkQvTu9EZCaFYD6c10StxQ' len(communityPostIds)=88 itemId='UgkxUgGZZSRw10gY8AQl3RURYhN9WqtACkwa' len(communityPostIds)=89 itemId='UgkxoLViXrK1ox1wQr1A38yYDwho3VoAy737' len(communityPostIds)=90 itemId='Ugkx9R_R8Fcr8difgaEx1adAC3AFNOe_M75N' len(communityPostIds)=91 itemId='UgkxPVwLzEhr2Ecz9Vw3Wxy_foSh7adDMRo5' timestamp=1697212800 len(items)=11 len(communityPostIds)=91 itemId='UgkxPVwLzEhr2Ecz9Vw3Wxy_foSh7adDMRo5' len(communityPostIds)=92 itemId='UgkxxN0-CSaGnlYWCQPSfXXa5PrZNKMvoVvD' len(communityPostIds)=93 itemId='UgkxnfkEvn7rPxUFdGs49BTXaT_IBuc1cRNv' len(communityPostIds)=94 itemId='UgkxSNuRn4XnTGrrKJnnhwmXm1hl_WW4kCzT' len(communityPostIds)=95 itemId='Ugkx0OfZ1VQXlW3T6IxWrAT1IZlFePH56i-K' len(communityPostIds)=96 itemId='UgkxFDnCY85_Tdpq9oQ6Wd_b-8hqgLUHO32y' len(communityPostIds)=97 itemId='UgkxEi9ou8AO2IwEIz9fZKPiQU4v7sXJjEmT' len(communityPostIds)=98 itemId='UgkxQCwjq2GariTf2saA-cGXg6T-Rg-WGRQE' len(communityPostIds)=99 itemId='UgkxxE3ySPbWsGviTczctnPzQYY5soTk9oMe' len(communityPostIds)=100 itemId='UgkxRvV7lnsCk1bqRKMEkgHSQsCFkS17i6pd' timestamp=1695919416 len(items)=11 len(communityPostIds)=100 itemId='UgkxRvV7lnsCk1bqRKMEkgHSQsCFkS17i6pd' len(communityPostIds)=101 itemId='Ugkxjv80KcGfs2wTu4O2Mj1khE7lYMy07xQ4' len(communityPostIds)=102 itemId='UgkxzVcHuR5ohyAQAEvNqgfkxzXVgZrXONRv' len(communityPostIds)=103 itemId='Ugkx9PB1yNtDldxoc0ygRV8VNPRb2ZdZ2vR9' len(communityPostIds)=104 itemId='Ugkx8RHsd_u8IeMOa76AvjR5rlrbEOTe_YO3' len(communityPostIds)=105 itemId='Ugkxx5bYnyFmX-vA3mwNGZDW-w4fPp96sr3R' len(communityPostIds)=106 itemId='UgkxMsosa26ftvKd621ySQJOHlBKWjUPorM0' len(communityPostIds)=107 itemId='Ugkx61D_Yey7gpdKTFxaeamZ5Mv-FE4BTr0m' len(communityPostIds)=108 itemId='UgkxrFN2OWvTF5RT_ICwPbe50np28xT356bG' len(communityPostIds)=109 itemId='Ugkx29JTGV66_lnBdMuiz5piLk5DbzMCoFSA' timestamp=1694798657 len(items)=11 len(communityPostIds)=109 itemId='Ugkx29JTGV66_lnBdMuiz5piLk5DbzMCoFSA' len(communityPostIds)=110 itemId='UgkxaYLJYEFClXywsgOf3VenqTN721G1H7wl' len(communityPostIds)=111 itemId='UgkxuD5ze9xgBBdmAVIJkBep35PPVAasG4Tf' len(communityPostIds)=112 itemId='UgkxN49M-KvCmQ5pUOaCovmQ0Rs0aMZuAfks' len(communityPostIds)=113 itemId='Ugkxp5yofhQKegvDQ14DshYYFYmqv1t9KSg7' len(communityPostIds)=114 itemId='UgkxI7uIOka-_6aLGz9AVm4H2Jl6rktgl7h9' len(communityPostIds)=115 itemId='UgkxVewE_lAGrfiXugswDTyezr6e7xqt3Lgq' len(communityPostIds)=116 itemId='Ugkx8FJZQA1yetDJs5aw3BNM39aDy_6YEbzC' len(communityPostIds)=117 itemId='UgkxFHOLoDYyYtW9ojny_tUmPV5Fv4K3Wqkm' len(communityPostIds)=118 itemId='Ugkxk7_jtR-qtTTDk1saqpk9EZWNpq5im72r' timestamp=1693249391 len(items)=11 len(communityPostIds)=118 itemId='Ugkxk7_jtR-qtTTDk1saqpk9EZWNpq5im72r' len(communityPostIds)=119 itemId='UgkxkKV7lX-qrhoSCOIksmH-VAJCk9BQ6PFR' len(communityPostIds)=120 itemId='Ugkx8Adj9xx4-4FDe1epcIa4SQ6wtdaCly0K' len(communityPostIds)=121 itemId='Ugkxs2Gc5XLGX1dfk0n1jIeJ256LTHH7XY8M' len(communityPostIds)=122 itemId='UgkxOxNp0HftGmlaygUUV3vzdjB6E2hAq453' len(communityPostIds)=123 itemId='UgkxIZqQld9ibXEdY1L6e6onqxwnEtO6_OyR' len(communityPostIds)=124 itemId='UgkxA7cENr8vNlbyzwNX536H1KYPAPJRIC6i' len(communityPostIds)=125 itemId='UgkxC-UvLdMz7dC5lI8exua2ntM77nfwk8VM' len(communityPostIds)=126 itemId='UgkxzWttmhM-mQmy9JJc6_YdgnUKE6RaOpW-' len(communityPostIds)=127 itemId='Ugkxm9wD2nBYT9g1bWhTq_-9p4ValUCnxLQ_' timestamp=1691856000 len(items)=11 len(communityPostIds)=127 itemId='Ugkxm9wD2nBYT9g1bWhTq_-9p4ValUCnxLQ_' len(communityPostIds)=128 itemId='UgkxL3kOPsj1x-dX9WWb1hl5slJ9c5CELmVZ' len(communityPostIds)=129 itemId='Ugkx9fKpIaWFAFCwT-7us5W7yTl02_Lq1f-w' len(communityPostIds)=130 itemId='UgkxbQiBHtluy-PEbn6IFSz685g5HNR3Kmsh' len(communityPostIds)=131 itemId='UgkxHk5v39HYJhAyh6m3kjaRIhSkrHJ8eLYw' len(communityPostIds)=132 itemId='UgkxnHlhrublFJFg4hzx03ePCtUN8vEp_9T2' len(communityPostIds)=133 itemId='UgkxKaBYD6HTt0ZtRkw3_VOlVxHXj8QHKEaV' len(communityPostIds)=134 itemId='Ugkxl3Cg0l3tWtN4-dD6BnRwuRIrmFqyBTvZ' len(communityPostIds)=135 itemId='Ugkx9qapLrK6IN-t3gAMXgIFrUUPncT_VI7X' len(communityPostIds)=136 itemId='UgkxbQH3kOmGajT1ItHorf687kRhPUoM1wFS' timestamp=1690642800 len(items)=11 len(communityPostIds)=136 itemId='UgkxbQH3kOmGajT1ItHorf687kRhPUoM1wFS' len(communityPostIds)=137 itemId='Ugkx1_YJ7Qy_RTGDqLDgRnUZkPiViCiPKFnR' len(communityPostIds)=138 itemId='Ugkxa5CueC9uzfDVPIJI-82fnhTCq-nCmeAK' len(communityPostIds)=139 itemId='UgkxG_eHBgXVuc2GceoxgYLwjUOgpEyv3AOh' len(communityPostIds)=140 itemId='UgkxJy80aehejl1CDlP7TmfDJRr3kc3fjLMq' len(communityPostIds)=141 itemId='UgkxSiI9ciUUuP9yG5OC6w4qr1CLLVPpnmCE' len(communityPostIds)=142 itemId='Ugkxb0zY02vq96OkSJSAj0lvmwjyr4oL0o-o' len(communityPostIds)=143 itemId='UgkxEoO71AQFWmIW8KqGq6z96J_Kyfah51ga' len(communityPostIds)=144 itemId='UgkxIfHI-aEhTl23_nZ-5kbFJyKYCj5RGSXn' len(communityPostIds)=145 itemId='UgkxDSMN24y8eaK7AcOuorqgBuHwpIsWTvqk' timestamp=1689778800 len(items)=11 len(communityPostIds)=145 itemId='UgkxDSMN24y8eaK7AcOuorqgBuHwpIsWTvqk' len(communityPostIds)=146 itemId='Ugkxh1pExB0fMe0bMack6PbczYDjnaR0NFMs' len(communityPostIds)=147 itemId='UgkxIP30kEnxTdgJn1opHtuB2wJLepwEu5Kq' len(communityPostIds)=148 itemId='Ugkx-3u1RuJR_5lVAQhWGTRHPdkyCDzDZCTN' len(communityPostIds)=149 itemId='UgkxdK5g8CtwbPGqSoqBuLFCsjzWXcBjWsKV' len(communityPostIds)=150 itemId='Ugkxn8kX_8C4CUqZ6oxJxoky3pQCB7DUD9-T' len(communityPostIds)=151 itemId='Ugkx4GrEc-Cq4t3YFJpgBDnmqCLU-jp1Jyr9' len(communityPostIds)=152 itemId='UgkxvAyOtyxNoTFPAzIs21yDcoFch9tSBOdZ' len(communityPostIds)=153 itemId='Ugkx_JoF7Y75p6iulAHmYu0VO8QFHkYogOGJ' len(communityPostIds)=154 itemId='UgkxppEnEq7-YtiQQX_gdJuvGxX2DzAwRHV_' timestamp=1688493600 len(items)=11 len(communityPostIds)=154 itemId='UgkxppEnEq7-YtiQQX_gdJuvGxX2DzAwRHV_' len(communityPostIds)=155 itemId='UgkxWlyb6bCzjEGK6CeFznujpi6-AzoQ6JC7' len(communityPostIds)=156 itemId='UgkxVShJa7y_GrY8KDkGaABh9JUaCpbyooDj' len(communityPostIds)=157 itemId='Ugkx3Lq47kFpqHzuz5yKAhopOihoU5KxP8wy' len(communityPostIds)=158 itemId='UgkxrfJ1ByaPfY8o-kP5GbGyp9wO6d_zuvT-' len(communityPostIds)=159 itemId='Ugkx1jn2MKFR_boBMxzAIvcUCUOkDn-DcrVA' len(communityPostIds)=160 itemId='Ugkxc05I5yDG8OifjDrio60hfGgBJVrwdARL' len(communityPostIds)=161 itemId='Ugkx7DlEXI2mOXQU_BjFgvTZCys2qosB6U8H' len(communityPostIds)=162 itemId='UgkxCMfnE_V-tiw586-4Me4QB98Zxrz902p-' len(communityPostIds)=163 itemId='UgkxH0UYWNrz7ncCc-PRxZ0FkdcDrvxTxAbZ' timestamp=1687392393 len(items)=11 len(communityPostIds)=163 itemId='UgkxH0UYWNrz7ncCc-PRxZ0FkdcDrvxTxAbZ' len(communityPostIds)=164 itemId='UgkxZ-x8Y7hugfmgOkOAO0IK4CuKLqvpuX5o' len(communityPostIds)=165 itemId='UgkxEoG3TyLN1sM02UuXgUqWY2Z25I_ahvRW' len(communityPostIds)=166 itemId='Ugkx2AYrTcDg2DFzrkTDAV26azVQJZs2-jFC' len(communityPostIds)=167 itemId='UgkxSJ79kE4IiNCJQGbQwjeb7qaKhhktR710' len(communityPostIds)=168 itemId='Ugkxf-o0GUgtVontyy7QSiKgOjXb2qqSfEQE' len(communityPostIds)=169 itemId='UgkxbO1OpZsOZ-IQgOU9Bk7Np9WYqTI_p4-s' len(communityPostIds)=170 itemId='UgkxF9WO1hmrbgY1BLWxHUl2fhxbOEGdMNNK' len(communityPostIds)=171 itemId='UgkxbV9DGm9PMb1IOfxrKgoCO7SA-k_0Hzsd' len(communityPostIds)=172 itemId='Ugkx9FDDE6Rkg6vyfk2R_BgpUTT_Ti3l4SCU' timestamp=1686073221 len(items)=11 len(communityPostIds)=172 itemId='Ugkx9FDDE6Rkg6vyfk2R_BgpUTT_Ti3l4SCU' len(communityPostIds)=173 itemId='Ugkx1sSmrAyYkHE7QDz9D5K1jtZk_6yPsTVh' len(communityPostIds)=174 itemId='UgkxaDGo8Aq4UxF4Oqm695pvAVGrtttIusQl' len(communityPostIds)=175 itemId='UgkxZovd2OSuml6jSF3apNPfYeR50WJIrP0e' len(communityPostIds)=176 itemId='UgkxlbGkNU7lNA1JZEcme7JPgXHyrgRUBzJO' len(communityPostIds)=177 itemId='UgkxTic3QLkSbwh37L1qnC7fqGiBMLdUX2-g' len(communityPostIds)=178 itemId='Ugkxbue_QFcjsVEoVoaRg3W0LObOluKH0ehq' len(communityPostIds)=179 itemId='Ugkx9zE8S7oqv0xHMFZjgOwKAX-CDA8eoCov' len(communityPostIds)=180 itemId='Ugkxab_tf-zJOpDG-Kh1k2RbBw5TktUZiqdH' len(communityPostIds)=181 itemId='UgkxxCbUktpNR3rlg6clWEzYiupS7tPWc2zs' timestamp=1684249200 len(items)=11 len(communityPostIds)=181 itemId='UgkxxCbUktpNR3rlg6clWEzYiupS7tPWc2zs' len(communityPostIds)=182 itemId='Ugkx6BYUgutoRe4KzMCSSVfFqQFdWNeWtVE_' len(communityPostIds)=183 itemId='UgkxcPFP2j9GXB8XJ3DknZP5N802X3FD7sUi' len(communityPostIds)=184 itemId='UgkxVVg26OOg4fE9kS0Jl5N4tbMGzrqtBPct' len(communityPostIds)=185 itemId='Ugkx8PNhJ5DMEvALB4p-GQChAd6wWQPfTXwY' len(communityPostIds)=186 itemId='UgkxPkhP2rZb5uVwpIEUPjoWnmjv8M1iZNJj' len(communityPostIds)=187 itemId='UgkxoPJsFjHR0bjHCFuaYjWqqijjI6ycQN8v' len(communityPostIds)=188 itemId='UgkxuGBjYb7YfPAVi7jofRhar9Z3vUK71wSK' len(communityPostIds)=189 itemId='UgkxXG9FP-qb7rPKG1Wjl_BVvfjYmnkeYnTr' len(communityPostIds)=190 itemId='UgkxoIswuvauOQM5wKp2XvJGMe6ASYPiyWf5' timestamp=1683126000 len(items)=11 len(communityPostIds)=190 itemId='UgkxoIswuvauOQM5wKp2XvJGMe6ASYPiyWf5' len(communityPostIds)=191 itemId='Ugkxp3ZExCr_4ELj9Cah1qU1b1MTq4AYdZ6D' len(communityPostIds)=192 itemId='Ugkx74OH4Ti_Lg8AmVd6x39M2d63za2p-yxV' len(communityPostIds)=193 itemId='UgkxpH6k9Ysrf3PXERRWbFP5W68IxAUEU9bs' len(communityPostIds)=194 itemId='UgkxKu7NuGTq7jWY7sOe_aiKmoddKGS34i_k' len(communityPostIds)=195 itemId='Ugkx6AKocJpr0dvK41BgXfDSkf7CzdQ7ZgO0' len(communityPostIds)=196 itemId='UgkxNGbxpjAoI1gCTX8XI3XJXqow_E6rvhMn' len(communityPostIds)=197 itemId='UgkxA9O4DOwrMbaB5Bbbu4hNb1NpiF8Z8EMV' len(communityPostIds)=198 itemId='Ugkx3wsrcbHubfvu_fAWMc6ECk5157vXRtK3' len(communityPostIds)=199 itemId='Ugkx13jX6l5-2SRrbk_2I5Aj3O7Ifqc5MEMq' timestamp=1681828053 len(items)=3 len(communityPostIds)=199 itemId='Ugkx3wsrcbHubfvu_fAWMc6ECk5157vXRtK3' len(communityPostIds)=199 itemId='Ugkx13jX6l5-2SRrbk_2I5Aj3O7Ifqc5MEMq' len(communityPostIds)=200 itemId='UgkxLsB8VcO_oL-8_rar2P_FKpE-DJ4ooykO' ```

seems to clearly shows that even internally we cannot retrieve more than 200 results. We could be biased by pagination but here the last page has strictly less than 10 results, so it does not seem to be the case. However, we may be biased by the 200 limit but I doubt so, to verify should try the timestamp just before the oldest community post one.

Benjamin-Loison commented 2 days ago

Webscrap_any_website/issues/29#issuecomment-2319819 and following comments shows that we can generate quite easily our own channel with more than 200 community posts in more than 48 hours.