diff --git a/documentation/html/youtube/channel_api.md b/documentation/html/youtube/channel_api.md new file mode 100644 index 0000000..a51f1b8 --- /dev/null +++ b/documentation/html/youtube/channel_api.md @@ -0,0 +1,471 @@ +# Zombiez + + +https://www.youtube.com/youtubei/v1/browse?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false + +```json +{ + "responseContext": { + ... + }, + "contents": { + "twoColumnBrowseResultsRenderer": { + "tabs": [ + { + "tabRenderer": { + "endpoint": { + "clickTrackingParams": "CBAQ8JMBGAUiEwj_3NqFrcX_AhVCxxEIHV5sBYg=", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCV0Ntl3lVR7xDXKoCU6uUXA/featured", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCV0Ntl3lVR7xDXKoCU6uUXA", + "params": "EghmZWF0dXJlZPIGBAoCMgA%3D", + "canonicalBaseUrl": "/channel/UCV0Ntl3lVR7xDXKoCU6uUXA" + } + }, + "title": "Home", + "selected": true, + "content": { + "sectionListRenderer": { + "contents": [ + { + "itemSectionRenderer": { + "contents": [ + { + "shelfRenderer": { + "title": { + "runs": [ + { + "text": "Albums & Singles", + "navigationEndpoint": { + "clickTrackingParams": "CBMQ3BwYACITCP_c2oWtxf8CFULHEQgdXmwFiA==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCV0Ntl3lVR7xDXKoCU6uUXA/playlists?view=50&sort=dd&shelf_id=17666223384013636040", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCVQK_XpXPuE8xcIpWp_JtlA", + "params": "EglwbGF5bGlzdHMYAyAycMiD1PaWksKV9QHyBgkKB0IAogECCAE%3D", + "canonicalBaseUrl": "/channel/UCV0Ntl3lVR7xDXKoCU6uUXA" + } + } + } + ] + }, + "endpoint": { + ... + }, + "content": { + "horizontalListRenderer": { + "items": [ + + /* first playlist */ + { + "gridPlaylistRenderer": { + "playlistId": "OLAK5uy_nbvQeskr8nbIuzeLxoceNLuCL_KjAmzVw", + "thumbnail": { + "thumbnails": [ + { + "url": "https://i.ytimg.com/vi/-OPkZtrBlVM/hqdefault.jpg?sqp=-oaymwEXCOADEI4CSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLASssT7fLkqB10cML8k_Tv5qoF4hg", + "width": 480, + "height": 270 + } + ], + "sampledThumbnailColor": { + "red": 62, + "green": 21, + "blue": 114 + } + }, + "title": { + "runs": [ + { + "text": "KATHARZIZ", + "navigationEndpoint": { + "clickTrackingParams": "CCIQljUYACITCP_c2oWtxf8CFULHEQgdXmwFiDIGZy1oaWdoWhhVQ1YwTnRsM2xWUjd4RFhLb0NVNnVVWEGaAQYQ8jgYlwE=", + "commandMetadata": { + "webCommandMetadata": { + "url": "/watch?v=-OPkZtrBlVM&list=OLAK5uy_nbvQeskr8nbIuzeLxoceNLuCL_KjAmzVw", + "webPageType": "WEB_PAGE_TYPE_WATCH", + "rootVe": 3832 + } + }, + "watchEndpoint": { + "videoId": "-OPkZtrBlVM", + "playlistId": "OLAK5uy_nbvQeskr8nbIuzeLxoceNLuCL_KjAmzVw", + "params": "OAI%3D", + "loggingContext": { + "vssLoggingContext": { + "serializedContextData": "GilPTEFLNXV5X25idlFlc2tyOG5iSXV6ZUx4b2NlTkx1Q0xfS2pBbXpWdw%3D%3D" + } + }, + "watchEndpointSupportedOnesieConfig": { + "html5PlaybackOnesieConfig": { + "commonConfig": { + "url": "https://rr6---sn-8xgn5uxa-4g5l.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&ofpcc=1&beids=24350018&msp=1&odepv=1&id=f8e3e466dac19553&ip=87.123.241.91&initcwndbps=2165000&mt=1686834329&oweuc=" + } + } + } + } + } + } + ] + }, + "shortBylineText": { + ... + }, + "videoCountText": { + "runs": [ + { + "text": "16" + }, + { + "text": " videos" + } + ] + }, + "navigationEndpoint": { + ... + }, + "publishedTimeText": { + "simpleText": "Updated today" + }, + "videoCountShortText": { + "simpleText": "16" + }, + "trackingParams": "CCIQljUYACITCP_c2oWtxf8CFULHEQgdXmwFiA==", + "sidebarThumbnails": [ + ... + ], + "thumbnailText": { + "runs": [ + { + "text": "16", + "bold": true + }, + { + "text": " videos" + } + ] + }, + "longBylineText": { + "runs": [ + { + "text": "Album" + }, + { + "text": " ยท " + }, + { + "text": "ZOMBIEZ", + "navigationEndpoint": { + "clickTrackingParams": "CCIQljUYACITCP_c2oWtxf8CFULHEQgdXmwFiA==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCVQK_XpXPuE8xcIpWp_JtlA", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCVQK_XpXPuE8xcIpWp_JtlA", + "canonicalBaseUrl": "/channel/UCVQK_XpXPuE8xcIpWp_JtlA" + } + } + } + ] + }, + "thumbnailOverlays": [ + ... + ], + "viewPlaylistText": { + "runs": [ + { + "text": "View full playlist", + "navigationEndpoint": { + "clickTrackingParams": "CCIQljUYACITCP_c2oWtxf8CFULHEQgdXmwFiDIGZy1oaWdo", + "commandMetadata": { + "webCommandMetadata": { + "url": "/playlist?list=OLAK5uy_nbvQeskr8nbIuzeLxoceNLuCL_KjAmzVw", + "webPageType": "WEB_PAGE_TYPE_PLAYLIST", + "rootVe": 5754, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "VLOLAK5uy_nbvQeskr8nbIuzeLxoceNLuCL_KjAmzVw" + } + } + } + ] + } + } + }, + + /* next playlist (same format as first one) */ + { + ... + }, + + /* many more playlists */ + ... + + + ], + ... + } + }, + "trackingParams": "CBMQ3BwYACITCP_c2oWtxf8CFULHEQgdXmwFiA==" + } + } + ], + "trackingParams": "CBIQuy8YACITCP_c2oWtxf8CFULHEQgdXmwFiA==" + } + } + ], + "trackingParams": "CBEQui8iEwj_3NqFrcX_AhVCxxEIHV5sBYg=", + "targetId": "browse-feedUCV0Ntl3lVR7xDXKoCU6uUXA", + "disablePullToRefresh": true + } + }, + "trackingParams": "CBAQ8JMBGAUiEwj_3NqFrcX_AhVCxxEIHV5sBYg=" + } + }, + ... + ] + } + }, + + /* Some probably irrelevant stuff */ + + "header": { + ... + }, + "metadata": { + "channelMetadataRenderer": { + "title": "ZOMBIEZ - Topic", + "description": "", + "rssUrl": "https://www.youtube.com/feeds/videos.xml?channel_id=UCV0Ntl3lVR7xDXKoCU6uUXA", + "externalId": "UCV0Ntl3lVR7xDXKoCU6uUXA", + "keywords": "", + "ownerUrls": [ + "http://www.youtube.com/channel/UCV0Ntl3lVR7xDXKoCU6uUXA" + ], + "avatar": { + "thumbnails": [ + { + "url": "https://yt3.googleusercontent.com/nGpgytnZ-gQ8bcmUvqQ4UQruCRqWiQiujnAaHD6jSlLMMPGbl2J7V-j8iD1ZGj2iUEylvsFkNQ=s900-c-k-c0x00ffffff-no-rj", + "width": 900, + "height": 900 + } + ] + }, + "channelUrl": "https://www.youtube.com/channel/UCV0Ntl3lVR7xDXKoCU6uUXA", + "isFamilySafe": true, + "availableCountryCodes": [ + ], + "musicArtistName": "ZOMBIEZ", + "androidDeepLink": "android-app://com.google.android.youtube/http/www.youtube.com/channel/UCV0Ntl3lVR7xDXKoCU6uUXA", + "androidAppindexingLink": "android-app://com.google.android.youtube/http/www.youtube.com/channel/UCV0Ntl3lVR7xDXKoCU6uUXA", + "iosAppindexingLink": "ios-app://544007664/vnd.youtube/www.youtube.com/channel/UCV0Ntl3lVR7xDXKoCU6uUXA", + "vanityChannelUrl": "http://www.youtube.com/channel/UCV0Ntl3lVR7xDXKoCU6uUXA" + } + }, + "trackingParams": "CAAQhGciEwj_3NqFrcX_AhVCxxEIHV5sBYg=", + "topbar": { + ... + }, + "microformat": { + .... + } +} +``` + +# Eminem + +https://www.youtube.com/youtubei/v1/browse?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false + +```json +{ + "responseContext": { + ... + }, + "contents": { + "twoColumnBrowseResultsRenderer": { + "tabs": [ + { + "tabRenderer": { + "endpoint": { + "clickTrackingParams": "CDEQ8JMBGAUiEwiSlomurMX_AhWhiTgKHeKqA0o=", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCedvOgsKFzcK3hA5taf3KoQ/featured", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCedvOgsKFzcK3hA5taf3KoQ", + "params": "EghmZWF0dXJlZPIGBAoCMgA%3D", + "canonicalBaseUrl": "/channel/UCedvOgsKFzcK3hA5taf3KoQ" + } + }, + "title": "Home", + "trackingParams": "CDEQ8JMBGAUiEwiSlomurMX_AhWhiTgKHeKqA0o=" + } + }, + { + "tabRenderer": { + "endpoint": { + "clickTrackingParams": "CA8Q8JMBGAYiEwiSlomurMX_AhWhiTgKHeKqA0o=", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCedvOgsKFzcK3hA5taf3KoQ/playlists", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCedvOgsKFzcK3hA5taf3KoQ", + "params": "EglwbGF5bGlzdHPyBgQKAkIA", + "canonicalBaseUrl": "/channel/UCedvOgsKFzcK3hA5taf3KoQ" + } + }, + "title": "Playlists", + "selected": true, + "content": { + "sectionListRenderer": { + "contents": [ + { + "itemSectionRenderer": { + "contents": [ + { + "gridRenderer": { + "items": [ + { + "gridPlaylistRenderer": { + "playlistId": "OLAK5uy_mHmQtAojdO4PRMxhyG_9FR2cScq52Z_ww", + "thumbnail": { + "thumbnails": [ + { + "url": "https://i.ytimg.com/vi/r_0JjYUe5jo/hqdefault.jpg?sqp=-oaymwEXCOADEI4CSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLBDE5zUUu7bOlXU1uOhaNxJl5zIbQ", + "width": 480, + "height": 270 + } + ], + "sampledThumbnailColor": { + "red": 74, + "green": 89, + "blue": 88 + } + }, + "title": { + "runs": [ + { + "text": "Curtain Call 2", + "navigationEndpoint": { + "clickTrackingParams": "CDAQljUYACITCJKWia6sxf8CFaGJOAod4qoDSjIGZy1oaWdoWhhVQ2Vkdk9nc0tGemNLM2hBNXRhZjNLb1GaAQYQ8jgYlwE=", + "commandMetadata": { + "webCommandMetadata": { + "url": "/watch?v=r_0JjYUe5jo&list=OLAK5uy_mHmQtAojdO4PRMxhyG_9FR2cScq52Z_ww", + "webPageType": "WEB_PAGE_TYPE_WATCH", + "rootVe": 3832 + } + }, + "watchEndpoint": { + "videoId": "r_0JjYUe5jo", + "playlistId": "OLAK5uy_mHmQtAojdO4PRMxhyG_9FR2cScq52Z_ww", + "params": "OAI%3D", + "loggingContext": { + "vssLoggingContext": { + "serializedContextData": "GilPTEFLNXV5X21IbVF0QW9qZE80UFJNeGh5R185RlIyY1NjcTUyWl93dw%3D%3D" + } + }, + "watchEndpointSupportedOnesieConfig": { + "html5PlaybackOnesieConfig": { + "commonConfig": { + "url": "https://rr2---sn-8xgn5uxa-4g5s.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&ofpcc=1&beids=24350018&msp=1&odepv=1&id=affd098d851ee63a&ip=87.123.241.91&initcwndbps=1772500&mt=1686834084&oweuc=" + } + } + } + } + } + } + ] + }, + "shortBylineText": { + "runs": [ + + ] + }, + "videoCountText": { + "runs": [ + { + "text": "35" + }, + { + "text": " videos" + } + ] + }, + "navigationEndpoint": { + ... + } + }, + "publishedTimeText": { + "simpleText": "Updated today" + }, + "videoCountShortText": { + "simpleText": "35" + }, + ... + ], + "thumbnailText": { + "runs": [ + { + "text": "35", + "bold": true + }, + { + "text": " videos" + } + ] + }, + ... + "viewPlaylistText": { + "runs": [ + { + "text": "View full playlist", + "navigationEndpoint": { + "clickTrackingParams": "CDAQljUYACITCJKWia6sxf8CFaGJOAod4qoDSjIGZy1oaWdo", + "commandMetadata": { + "webCommandMetadata": { + "url": "/playlist?list=OLAK5uy_mHmQtAojdO4PRMxhyG_9FR2cScq52Z_ww", + "webPageType": "WEB_PAGE_TYPE_PLAYLIST", + "rootVe": 5754, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "VLOLAK5uy_mHmQtAojdO4PRMxhyG_9FR2cScq52Z_ww" + } + } + } + ] + } + } + }, +``` diff --git a/documentation/html/youtube/channel_api_request.md b/documentation/html/youtube/channel_api_request.md new file mode 100644 index 0000000..a2f3ffa --- /dev/null +++ b/documentation/html/youtube/channel_api_request.md @@ -0,0 +1,204 @@ +# Results + +## Request + +```curl +curl 'https://www.youtube.com/youtubei/v1/browse?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false' \ + -H 'authority: www.youtube.com' \ + -H 'accept: */*' \ + -H 'accept-language: en-US,en;q=0.7' \ + -H 'authorization: SAPISIDHASH 1686916263_e46803ac72f6036ba3b55e6edb0e45218c2d9222' \ + -H 'cache-control: no-cache' \ + -H 'content-type: application/json' \ + -H 'cookie: CONSENT=PENDING+359; SOCS=CAESEwgDEgk1MDQzNzQ2NDAaAmVuIAEaBgiAhceeBg; DEVICE_INFO=ChxOekU1Tnprd056a3lOalUxTURJd01EQTNOdz09EJ+2kJ8GGJ+2kJ8G; HSID=ACaGQ6WFrIz4Ip9MQ; SSID=AkEQqNjJYkdquRRu6; APISID=c9DHm8ianHgc4LdY/AQMhE_0ECWj0r_orU; SAPISID=a_vNFJhvrDylguw8/Ann5G_jsanpFtW0Pu; __Secure-1PAPISID=a_vNFJhvrDylguw8/Ann5G_jsanpFtW0Pu; __Secure-3PAPISID=a_vNFJhvrDylguw8/Ann5G_jsanpFtW0Pu; LOGIN_INFO=AFmmF2swRQIhANli-SWeYk6WvtIgBzsX4XMeuzlvdXMVtbfJTdhUJPRAAiAlG7PiNiEuUynQLUz5y-t7IvHPtpbmp0sU7_1B8ebQBw:QUQ3MjNmejhuWW5EZV9OVklIOTNxYXpEMXYwQWVvM1ptYTc2OWtObE9TcllyOEc4VndOR0tXVVRUOUhmT2hRbFRkNVZjeVhDRUJ0bmwxcTJTU3ZKWWhvX1hKMFdFbDVBYTdOS2tNMU41ZDI1Y3pIQ2NTVjNrdzJNVGFENDROT2IwdDBTTlV6cmh2RGFWaXpCWndGTHUxMzZBM1NGNk5FbVZn; VISITOR_INFO1_LIVE=swm2xaU6T4s; SID=WwivRnpt9CjuCydglBkAPlpoMnou9Djmu9MIggo5NnkT1-6N69ULSrjryLwj4ZSvzfy6qA.; __Secure-1PSID=WwivRnpt9CjuCydglBkAPlpoMnou9Djmu9MIggo5NnkT1-6NcKwuUDKgPPeuOmwXW3uZUg.; __Secure-3PSID=WwivRnpt9CjuCydglBkAPlpoMnou9Djmu9MIggo5NnkT1-6NIh3P5codR8w_2O6jDK4PVw.; PREF=tz=Europe.Berlin&f6=40000000&f7=100; YSC=nVbKyjjk8dw; __Secure-YEC=CgtuQ2lKWWg3NFhTVSidmbGkBg%3D%3D; SIDCC=AP8dLty32FdokPf_5Qg2eA8TWwebRgwg1n55TG2yQUd-mJkLvroZJj9QGMOIbE33Q2ovqK10H_uA; __Secure-1PSIDCC=AP8dLtz5c8aDk1Gw5VFhcM6EuUcQiZP50kH2XnUIx0PF4bDPWTPwLEq1LhVvadHnHwagqV8DXJI; __Secure-3PSIDCC=AP8dLtzfSXJb4bJhF8czo12Tuc90ONVeuOVXtinx8-_tXE7D4HW1XwHwDfspIBZItbz0aYCjgYDO; ST-txiubb=itct=CCgQ8JMBGAciEwjq7bzg3Mf_AhWjRHoFHezzDzw%3D&csn=MC45MTAyMTY0NjM3ODQ2MTUz&endpoint=%7B%22clickTrackingParams%22%3A%22CCgQ8JMBGAciEwjq7bzg3Mf_AhWjRHoFHezzDzw%3D%22%2C%22commandMetadata%22%3A%7B%22webCommandMetadata%22%3A%7B%22url%22%3A%22%2Fchannel%2FUC8JxlMZ9VPddCuQGwB49fYg%2Fplaylists%22%2C%22webPageType%22%3A%22WEB_PAGE_TYPE_CHANNEL%22%2C%22rootVe%22%3A3611%2C%22apiUrl%22%3A%22%2Fyoutubei%2Fv1%2Fbrowse%22%7D%7D%2C%22browseEndpoint%22%3A%7B%22browseId%22%3A%22UC8JxlMZ9VPddCuQGwB49fYg%22%2C%22params%22%3A%22EglwbGF5bGlzdHPyBgQKAkIA%22%2C%22canonicalBaseUrl%22%3A%22%2Fchannel%2FUC8JxlMZ9VPddCuQGwB49fYg%22%7D%7D; ST-plcuz1=' \ + -H 'origin: https://www.youtube.com' \ + -H 'pragma: no-cache' \ + -H 'referer: https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists' \ + -H 'sec-fetch-dest: empty' \ + -H 'sec-fetch-mode: same-origin' \ + -H 'sec-fetch-site: same-origin' \ + -H 'sec-gpc: 1' \ + -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \ + -H 'x-goog-authuser: 0' \ + -H 'x-goog-visitor-id: CgtuQ2lKWWg3NFhTVSidmbGkBg%3D%3D' \ + -H 'x-origin: https://www.youtube.com' \ + -H 'x-youtube-bootstrap-logged-in: true' \ + -H 'x-youtube-client-name: 1' \ + -H 'x-youtube-client-version: 2.20230613.01.00' \ + --data-raw '{ + "context":{ + "client":{ + "hl":"de", + "gl":"DE", + "remoteHost":"87.123.241.79", + "deviceMake":"", + "deviceModel":"", + "visitorData":"CgtuQ2lKWWg3NFhTVSidmbGkBg%3D%3D", + "userAgent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36,gzip(gfe)", + "clientName":"WEB", + "clientVersion":"2.20230613.01.00", + "osName":"X11", + "osVersion":"", + "originalUrl":"https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists", + "platform":"DESKTOP", + "clientFormFactor":"UNKNOWN_FORM_FACTOR", + "configInfo":{ + "appInstallData":"CJ2ZsaQGEKXC_hIQzLf-EhDftq8FELq0rwUQvbauBRDbr68FEPOorwUQ4tSuBRDj0f4SEMzfrgUQ7NH-EhDrk64FEI_DrwUQorSvBRDUoa8FEKqy_hIQpZmvBRC4i64FEMyu_hIQscavBRDnuq8FEN62rwUQouyuBRCCna8FEMO3_hIQ1bavBRCMt68FEJCjrwUQ7qKvBRDpw68FEInorgUQl9L-EhD4ta8FEOf3rgUQrLevBRD-ta8FEOSz_hIQ_u6uBQ%3D%3D" + }, + "userInterfaceTheme":"USER_INTERFACE_THEME_DARK", + "timeZone":"Europe/Berlin", + "browserName":"Chrome", + "browserVersion":"114.0.0.0", + "acceptHeader":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", + "deviceExperimentId":"ChxOekU1Tnprd056a3lOalUxTURJd01EQTNOdz09EJ2ZsaQGGJ-2kJ8G", + "screenWidthPoints":1090, + "screenHeightPoints":980, + "screenPixelDensity":1, + "screenDensityFloat":1, + "utcOffsetMinutes":120, + "memoryTotalKbytes":"500000", + "mainAppWebInfo":{ + "graftUrl":"/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists", + "pwaInstallabilityStatus":"PWA_INSTALLABILITY_STATUS_CAN_BE_INSTALLED", + "webDisplayMode":"WEB_DISPLAY_MODE_BROWSER", + "isWebNativeShareAvailable":false + } + }, + "user":{ + "lockedSafetyMode":false + }, + "request":{ + "useSsl":true, + "internalExperimentFlags":[ + + ], + "consistencyTokenJars":[ + + ] + }, + "clickTracking":{ + "clickTrackingParams":"CCgQ8JMBGAciEwjq7bzg3Mf_AhWjRHoFHezzDzw=" + }, + "adSignalsInfo":{ + "params":[{"key":"dt","value":"1686916254647"},{"key":"flash","value":"0"},{"key":"frm","value":"0"},{"key":"u_tz","value":"120"},{"key":"u_his","value":"14"},{"key":"u_h","value":"1080"},{"key":"u_w","value":"1920"},{"key":"u_ah","value":"1049"},{"key":"u_aw","value":"1866"},{"key":"u_cd","value":"24"},{"key":"bc","value":"31"},{"key":"bih","value":"980"},{"key":"biw","value":"1075"},{"key":"brdim","value":"1280,31,1280,31,1866,31,1866,1049,1090,980"},{"key":"vis","value":"1"},{"key":"wgl","value":"true"},{"key":"ca_type","value":"image"}] + } + }, + "browseId":"UC8JxlMZ9VPddCuQGwB49fYg", + "params":"EglwbGF5bGlzdHPyBgQKAkIA" +}' \ + --compressed +``` + + +# No Results + +## Request + +```curl +curl 'https://www.youtube.com/youtubei/v1/browse?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false' \ + -H 'authority: www.youtube.com' \ + -H 'accept: */*' \ + -H 'accept-language: en-US,en;q=0.7' \ + -H 'authorization: SAPISIDHASH 1686916270_9e68abaf319d6994e84c3b64f46a2f6b91258f26' \ + -H 'cache-control: no-cache' \ + -H 'content-type: application/json' \ + -H 'cookie: CONSENT=PENDING+359; SOCS=CAESEwgDEgk1MDQzNzQ2NDAaAmVuIAEaBgiAhceeBg; DEVICE_INFO=ChxOekU1Tnprd056a3lOalUxTURJd01EQTNOdz09EJ+2kJ8GGJ+2kJ8G; HSID=ACaGQ6WFrIz4Ip9MQ; SSID=AkEQqNjJYkdquRRu6; APISID=c9DHm8ianHgc4LdY/AQMhE_0ECWj0r_orU; SAPISID=a_vNFJhvrDylguw8/Ann5G_jsanpFtW0Pu; __Secure-1PAPISID=a_vNFJhvrDylguw8/Ann5G_jsanpFtW0Pu; __Secure-3PAPISID=a_vNFJhvrDylguw8/Ann5G_jsanpFtW0Pu; LOGIN_INFO=AFmmF2swRQIhANli-SWeYk6WvtIgBzsX4XMeuzlvdXMVtbfJTdhUJPRAAiAlG7PiNiEuUynQLUz5y-t7IvHPtpbmp0sU7_1B8ebQBw:QUQ3MjNmejhuWW5EZV9OVklIOTNxYXpEMXYwQWVvM1ptYTc2OWtObE9TcllyOEc4VndOR0tXVVRUOUhmT2hRbFRkNVZjeVhDRUJ0bmwxcTJTU3ZKWWhvX1hKMFdFbDVBYTdOS2tNMU41ZDI1Y3pIQ2NTVjNrdzJNVGFENDROT2IwdDBTTlV6cmh2RGFWaXpCWndGTHUxMzZBM1NGNk5FbVZn; VISITOR_INFO1_LIVE=swm2xaU6T4s; SID=WwivRnpt9CjuCydglBkAPlpoMnou9Djmu9MIggo5NnkT1-6N69ULSrjryLwj4ZSvzfy6qA.; __Secure-1PSID=WwivRnpt9CjuCydglBkAPlpoMnou9Djmu9MIggo5NnkT1-6NcKwuUDKgPPeuOmwXW3uZUg.; __Secure-3PSID=WwivRnpt9CjuCydglBkAPlpoMnou9Djmu9MIggo5NnkT1-6NIh3P5codR8w_2O6jDK4PVw.; PREF=tz=Europe.Berlin&f6=40000000&f7=100; YSC=nVbKyjjk8dw; __Secure-YEC=CgtuQ2lKWWg3NFhTVSidmbGkBg%3D%3D; SIDCC=AP8dLtxamg1oLrM-gw2tCtJfMUighwYfCtCfwGT6G39nrxXXhtRoBcacfSPMOQwAOIN0xyOUSLyb; __Secure-1PSIDCC=AP8dLtxZ3YHCdW5cYDDaNKO8wvAGqqy4Kp7_xZtEYQW5bryvlEuU2iuJArAJskwLMwqiCznn038; __Secure-3PSIDCC=AP8dLtywHnuXOD7p59fWeUsQXp6MpPsJgZiUgW5ydTzajVvM6w64k4u7aE5WIuB5InMlTNJzKGGK; ST-plcuz1=; ST-ximm1t=csn=MC43NjY5NTkyNzczNjg1NjUy&itct=CCkQui8iEwi3hYnl3Mf_AhU7zBEIHQ_pA8o%3D&endpoint=%7B%22clickTrackingParams%22%3A%22CCkQui8iEwi3hYnl3Mf_AhU7zBEIHQ_pA8o%3D%22%2C%22commandMetadata%22%3A%7B%22webCommandMetadata%22%3A%7B%22url%22%3A%22%2Fchannel%2FUC8JxlMZ9VPddCuQGwB49fYg%2Fplaylists%3Fview%3D1%22%2C%22webPageType%22%3A%22WEB_PAGE_TYPE_CHANNEL%22%2C%22rootVe%22%3A3611%2C%22apiUrl%22%3A%22%2Fyoutubei%2Fv1%2Fbrowse%22%7D%7D%2C%22browseEndpoint%22%3A%7B%22browseId%22%3A%22UC8JxlMZ9VPddCuQGwB49fYg%22%2C%22params%22%3A%22EglwbGF5bGlzdHMgAQ%253D%253D%22%2C%22canonicalBaseUrl%22%3A%22%2Fchannel%2FUC8JxlMZ9VPddCuQGwB49fYg%22%7D%7D' \ + -H 'origin: https://www.youtube.com' \ + -H 'pragma: no-cache' \ + -H 'referer: https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists?view=1' \ + -H 'sec-fetch-dest: empty' \ + -H 'sec-fetch-mode: same-origin' \ + -H 'sec-fetch-site: same-origin' \ + -H 'sec-gpc: 1' \ + -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \ + -H 'x-goog-authuser: 0' \ + -H 'x-goog-visitor-id: CgtuQ2lKWWg3NFhTVSidmbGkBg%3D%3D' \ + -H 'x-origin: https://www.youtube.com' \ + -H 'x-youtube-bootstrap-logged-in: true' \ + -H 'x-youtube-client-name: 1' \ + -H 'x-youtube-client-version: 2.20230613.01.00' \ + --data-raw '{ + "context":{ + "client":{ + "hl":"de", + "gl":"DE", + "remoteHost":"87.123.241.79", + "deviceMake":"", + "deviceModel":"", + "visitorData":"CgtuQ2lKWWg3NFhTVSidmbGkBg%3D%3D", + "userAgent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36,gzip(gfe)", + "clientName":"WEB", + "clientVersion":"2.20230613.01.00", + "osName":"X11", + "osVersion":"", + "originalUrl":"https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists?view=1", + "platform":"DESKTOP", + "clientFormFactor":"UNKNOWN_FORM_FACTOR", + "configInfo":{ + "appInstallData":"CJ2ZsaQGEKXC_hIQzLf-EhDftq8FELq0rwUQvbauBRDbr68FEPOorwUQ4tSuBRDj0f4SEMzfrgUQ7NH-EhDrk64FEI_DrwUQorSvBRDUoa8FEKqy_hIQpZmvBRC4i64FEMyu_hIQscavBRDnuq8FEN62rwUQouyuBRCCna8FEMO3_hIQ1bavBRCMt68FEJCjrwUQ7qKvBRDpw68FEInorgUQl9L-EhD4ta8FEOf3rgUQrLevBRD-ta8FEOSz_hIQ_u6uBQ%3D%3D" + }, + "userInterfaceTheme":"USER_INTERFACE_THEME_DARK", + "timeZone":"Europe/Berlin", + "browserName":"Chrome", + "browserVersion":"114.0.0.0", + "acceptHeader":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", + "deviceExperimentId":"ChxOekU1Tnprd056a3lOalUxTURJd01EQTNOdz09EJ2ZsaQGGJ-2kJ8G", + "screenWidthPoints":1090, + "screenHeightPoints":980, + "screenPixelDensity":1, + "screenDensityFloat":1, + "utcOffsetMinutes":120, + "memoryTotalKbytes":"500000", + "mainAppWebInfo":{ + "graftUrl":"/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists?view=1", + "pwaInstallabilityStatus":"PWA_INSTALLABILITY_STATUS_CAN_BE_INSTALLED", + "webDisplayMode":"WEB_DISPLAY_MODE_BROWSER", + "isWebNativeShareAvailable":false + } + }, + "user":{ + "lockedSafetyMode":false + }, + "request":{ + "useSsl":true, + "internalExperimentFlags":[ + + ], + "consistencyTokenJars":[ + + ] + }, + "clickTracking":{ + "clickTrackingParams":"CCkQui8iEwi3hYnl3Mf_AhU7zBEIHQ_pA8o=" + }, + "adSignalsInfo":{ + "params":[{"key":"dt","value":"1686916254647"},{"key":"flash","value":"0"},{"key":"frm","value":"0"},{"key":"u_tz","value":"120"},{"key":"u_his","value":"15"},{"key":"u_h","value":"1080"},{"key":"u_w","value":"1920"},{"key":"u_ah","value":"1049"},{"key":"u_aw","value":"1866"},{"key":"u_cd","value":"24"},{"key":"bc","value":"31"},{"key":"bih","value":"980"},{"key":"biw","value":"1075"},{"key":"brdim","value":"1280,31,1280,31,1866,31,1866,1049,1090,980"},{"key":"vis","value":"1"},{"key":"wgl","value":"true"},{"key":"ca_type","value":"image"}] + } + }, + "browseId":"UC8JxlMZ9VPddCuQGwB49fYg", + "params":"EglwbGF5bGlzdHMgAQ%3D%3D" +}' \ + --compressed + ``` + +# Potentially relevant difference + +difference | Result | No Result +referer | https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists | https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists?view=1 +`"originalURL"` | https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists | https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists?view=1 + +## What I think the problem is + +I think the problem arises, because the request is made in the wrong manner. Refering to the by the endpoint returned data from earlier, the data is given in pretty much the same format. + +Now the thing is, that there are some Topic Channels, where you can't switch the playlist type. + +- https://www.youtube.com/channel/UCPOUrPpYMpxQU_gKtBQZroQ/playlists +- https://www.youtube.com/channel/UCV0Ntl3lVR7xDXKoCU6uUXA/playlists + +But then there are those Topic Channels, where you actually can switch the playlist type. These are usually the bigger ones. I haven't found why that difference exists though. + +- https://www.youtube.com/channel/UC8JxlMZ9VPddCuQGwB49fYg/playlists +- https://www.youtube.com/channel/UCedvOgsKFzcK3hA5taf3KoQ/playlists + +So modifying the requests from one of those channels, that currently do yield results, to have the `?view=1` parameter in the url, they still yield results. So my bet right now would be, that the reasons some channels do yield results and some don't is, because invidious makes the requests with `?view=1`, or does something simmilar, which causes the same behaviour. diff --git a/src/actual_donwload.py b/src/actual_donwload.py index 360fbea..9e8bd89 100644 --- a/src/actual_donwload.py +++ b/src/actual_donwload.py @@ -15,7 +15,7 @@ if __name__ == "__main__": youtube_search = [ "s: #a Zombiez", "10", - "8" + "d: 5" ] - music_kraken.cli(genre="test", command_list=direct_download) + music_kraken.cli(genre="test", command_list=youtube_search) diff --git a/src/music_kraken/audio/codec.py b/src/music_kraken/audio/codec.py index f8ba952..42518a9 100644 --- a/src/music_kraken/audio/codec.py +++ b/src/music_kraken/audio/codec.py @@ -45,9 +45,9 @@ def correct_codec(target: Target, bitrate_kb: int = BITRATE, audio_format: str = # run the ffmpeg command with a progressbar ff = FfmpegProgress(ffmpeg_command) - with tqdm(total=100, desc="ffmpeg") as pbar: + with tqdm(total=100, desc=f"removing {len(interval_list)} segments") as pbar: for progress in ff.run_command_with_progress(): - pbar.update(int(progress)-pbar.n) + pbar.update(progress-pbar.n) LOGGER.debug(ff.stderr) diff --git a/src/music_kraken/connection/connection.py b/src/music_kraken/connection/connection.py index 81dc21a..cd739c4 100644 --- a/src/music_kraken/connection/connection.py +++ b/src/music_kraken/connection/connection.py @@ -17,7 +17,7 @@ class Connection: self, host: str, proxies: List[dict] = None, - tries: int = (len(PROXIES_LIST) + 1) * 2, + tries: int = (len(PROXIES_LIST) + 1) * 4, timeout: int = 7, logger: logging.Logger = logging.getLogger("connection"), header_values: Dict[str, str] = None, @@ -80,7 +80,7 @@ class Connection: self, request: Callable, try_count: int, - accepted_response_code: set, + accepted_response_codes: set, url: str, timeout: float, headers: dict, @@ -109,7 +109,7 @@ class Connection: try: r: requests.Response = request(request_url, timeout=timeout, headers=headers, **kwargs) - if r.status_code in accepted_response_code: + if r.status_code in accepted_response_codes: return r if self.SEMANTIC_NOT_FOUND and r.status_code == 404: @@ -136,7 +136,7 @@ class Connection: return self._request( request=request, try_count=try_count+1, - accepted_response_code=accepted_response_code, + accepted_response_codes=accepted_response_codes, url=url, timeout=timeout, headers=headers, @@ -154,10 +154,13 @@ class Connection: raw_url: bool = False, **kwargs ) -> Optional[requests.Response]: + if accepted_response_codes is None: + accepted_response_codes = self.ACCEPTED_RESPONSE_CODES + r = self._request( request=self.session.get, try_count=0, - accepted_response_code=accepted_response_codes or self.ACCEPTED_RESPONSE_CODES, + accepted_response_codes=accepted_response_codes, url=url, timeout=timeout, headers=headers, @@ -185,7 +188,7 @@ class Connection: r = self._request( request=self.session.post, try_count=0, - accepted_response_code=accepted_response_codes or self.ACCEPTED_RESPONSE_CODES, + accepted_response_codes=accepted_response_codes or self.ACCEPTED_RESPONSE_CODES, url=url, timeout=timeout, headers=headers, @@ -215,11 +218,19 @@ class Connection: progress: int = 0, **kwargs ) -> DownloadResult: + + if progress > 0: + if headers is None: + headers = dict() + headers["Range"] = f"bytes={target.size}-" + + if accepted_response_codes is None: + accepted_response_codes = self.ACCEPTED_RESPONSE_CODES r = self._request( request=self.session.get, try_count=0, - accepted_response_code=accepted_response_codes or self.ACCEPTED_RESPONSE_CODES, + accepted_response_codes=accepted_response_codes, url=url, timeout=timeout, headers=headers, @@ -238,45 +249,47 @@ class Connection: retry = False - with target.open("wb") as f: - try: - """ - https://en.wikipedia.org/wiki/Kilobyte - > The internationally recommended unit symbol for the kilobyte is kB. - """ + with target.open("ab") as f: + """ + https://en.wikipedia.org/wiki/Kilobyte + > The internationally recommended unit symbol for the kilobyte is kB. + """ - with tqdm(total=total_size, unit='B', unit_scale=True, unit_divisor=1024, desc=description) as t: - + with tqdm(total=total_size-target.size, unit='B', unit_scale=True, unit_divisor=1024, desc=description) as t: + try: for chunk in r.iter_content(chunk_size=chunk_size): size = f.write(chunk) progress += size t.update(size) - return True - except requests.exceptions.ConnectionError: - if try_count >= self.TRIES: - self.LOGGER.warning(f"Stream timed out at \"{url}\": to many retries, aborting.") - return DownloadResult(error_message=f"Stream timed out from {url}, reducing the chunksize might help.") - - self.LOGGER.warning(f"Stream timed out at \"{url}\": ({try_count}-{self.TRIES})") + except requests.exceptions.ConnectionError: + if try_count >= self.TRIES: + self.LOGGER.warning(f"Stream timed out at \"{url}\": to many retries, aborting.") + return DownloadResult(error_message=f"Stream timed out from {url}, reducing the chunksize might help.") + + self.LOGGER.warning(f"Stream timed out at \"{url}\": ({try_count}-{self.TRIES})") + retry = True + + if total_size > progress: retry = True - finally: - if total_size > progress or retry: - return self.stream_into( - url = url, - target = target, - description = description, - try_count=try_count+1, - progress=progress, - accepted_response_code=accepted_response_codes, - timeout=timeout, - headers=headers, - raw_url=raw_url, - refer_from_origin=refer_from_origin, - chunk_size=chunk_size, - **kwargs - ) - - return DownloadResult() + if retry: + self.LOGGER.warning(f"Retrying stream...") + accepted_response_codes.add(206) + return self.stream_into( + url = url, + target = target, + description = description, + try_count=try_count+1, + progress=progress, + accepted_response_codes=accepted_response_codes, + timeout=timeout, + headers=headers, + raw_url=raw_url, + refer_from_origin=refer_from_origin, + chunk_size=chunk_size, + **kwargs + ) + + return DownloadResult() diff --git a/src/music_kraken/pages/youtube.py b/src/music_kraken/pages/youtube.py index 797480e..40c62b5 100644 --- a/src/music_kraken/pages/youtube.py +++ b/src/music_kraken/pages/youtube.py @@ -394,7 +394,4 @@ class YouTube(Page): except HTTPException as e: self.LOGGER.warning(f"{e}") - if len(segments) > 0: - print(f"Removing {len(segments)} interruptions in the audio...") - return [(segment.start, segment.end) for segment in segments] diff --git a/src/music_kraken/utils/config/audio.py b/src/music_kraken/utils/config/audio.py index 969bb67..ea85d84 100644 --- a/src/music_kraken/utils/config/audio.py +++ b/src/music_kraken/utils/config/audio.py @@ -106,7 +106,7 @@ ID3.1: {', '.join(_sorted_id3_1_formats)} self.DOWNLOAD_PATH = StringAttribute( name="download_path", - value="{genre}/{artist}/{album_type}/{album}", + value="{genre}/{artist}/{album}", description="The folder music kraken should put the songs into." ) diff --git a/src/music_kraken/utils/support_classes/download_result.py b/src/music_kraken/utils/support_classes/download_result.py index a47a054..2f54111 100644 --- a/src/music_kraken/utils/support_classes/download_result.py +++ b/src/music_kraken/utils/support_classes/download_result.py @@ -80,11 +80,11 @@ class DownloadResult: def __str__(self): if self.is_fatal_error: return self.error_message - head = f"{self.fail} from {self.total} downloads failed:\n" \ - f"successrate:\t{int(self.success_percentage * 100)}%\n" \ - f"failrate:\t{int(self.failure_percentage * 100)}%\n" \ - f"total size:\t{self.formated_size}\n" \ - f"skipped segments:\t{self.sponsor_segments}" \ + head = f"{self.fail} from {self.total} downloads failed:\n" \ + f"successrate:\t{int(self.success_percentage * 100)}%\n" \ + f"failrate:\t{int(self.failure_percentage * 100)}%\n" \ + f"total size:\t{self.formated_size}\n" \ + f"skipped segments:\t{self.sponsor_segments}\n" \ f"found on disc:\t{self.found_on_disk}" if not self.is_mild_failure: