ackoujens / youtube-subcriptions-watch-later

Adds unwatched videos from your YouTube subscriptions page to the "Watch later" playlist
3 stars 1 forks source link

Script stopped adding video's #3

Open ackoujens opened 6 years ago

ackoujens commented 6 years ago

A recent change in the YouTube layout broke the script. Probably caused by element names being altered.

ackoujens commented 6 years ago

Consulted YouTube API for a more robust solution: https://developers.google.com/youtube/v3/docs/playlistItems/insert

Current script is a hacky solution of adding items to Watch Later playlist. Using the YouTube API may prevent future breaking of the userscript. When using the script for the first time, users are presented with a prompt to authorize.

smartfonreddit commented 6 years ago

This is the only script of a kind. I hope to see a version that works with the Material redesign. Youtube has changed names such as "ytd-thumbnail-overlay-toggle-button-renderer".

Viscrimson commented 6 years ago

Seems to be working for me. I have seen no gaps in Subs vs. Watch Later

smartfonreddit commented 6 years ago

I installed the script, opened the Sub and Watch Later pages. There are about two dozen unwatched videos on Subs. The script added an "eye" icon next to the YouTube's upload button. When I hover the mouse to click it, the icon disappears, but the button is still there because the mouse cursor turns into a hand icon. When I click on the now-invisible eye icon, and stay on the page for a minute to let the script do its job, nothing actually happens. Refreshing the Watch Later doesn't show the new videos.

[YT-SP] Starting Script subscriptions:219:16 [YT-SP] Attaching DOM listener subscriptions:194:20 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://googleads.g.doubleclick.net/pagead/id. (Reason: CORS request did not succeed). [YT-SP] Running check for subcription videos subscriptions:165:18 [YT-SP] Running check for subcription videos subscriptions:165:18 [YT-SP] Running check for subcription videos subscriptions:165:18 [YT-SP] Running check for subcription videos subscriptions:165:18 [YT-SP] Running check for subcription videos subscriptions:165:18 [YT-SP] Running check for subcription videos subscriptions:165:18

Viscrimson commented 6 years ago

What browser or app? Do you have plugins on chrome or anything?

smartfonreddit commented 6 years ago

Firefox Beta and Chrome Stable with Violentmonkey extension. No other extensions. The YouTube is using the new Material design.

ackoujens commented 6 years ago

@viscrimson Are you still running the old Youtube layout perhaps?

ackoujens commented 6 years ago

Look I'm positive the hacky way I made this script will keep on breaking. I'll make a second branch to test the YouTube API to do this properly.

Viscrimson commented 6 years ago

Oh perhaps so. I didn't even know there was a new layout.

Viscrimson commented 6 years ago

Hacky or not it has been brilliant in my book.

Stoux commented 6 years ago

Consulted YouTube API for a more robust solution: https://developers.google.com/youtube/v3/docs/playlistItems/insert

I've attempted this but to no avail, it doesn't allow you to modify or view the private lists ('WL': Watch Later & 'WH': Watch History). I noticed that some videos didn't show up in my subscription feed, so I figured I would build a backend thingy that would just poll all the channels for recent uploads and add them to my Watch Later list. They removed the ability to do that on Sept. 15, 2016.

https://developers.google.com/youtube/v3/revision_history#september-15-2016

In addition, requests to retrieve playlist details (playlists.list) or playlist items (playlistItems.list) for a channel's watch history or watch later playlist now return empty lists. This behavior is true for the new values, HL and WL, as well as for any watch history or watch later playlist IDs that your API Client may have already stored.

Such a shame.

ackoujens commented 6 years ago

@Stoux Indeed it is. Have been trying now to repair my script the hacky way I originally made it. Problem is that the only button I'm able to use gets hidden when not being hovered over. (I assume that is a change that broke the script entirely)

Triggering a mouseover doesn't seem to work on any element I've tried so far. Was hoping to keep it in a hovered state and try to click the WL button that way.

The pop up menu (using the triple dots button) isn't directly tied to a specific video. Guess I can rule that one out too.

Really loved it when it worked out. Remember nagging for this kind of functionality every since I've started watching YouTube back in the day.

And not a single fuck was given at YT HQ.

Stoux commented 5 years ago

@ackoujens Yeh, came across that same problem. Been wanting to attempt a WebExtension for a while so figured now would be good time after coming across your userscript. Original scope was exactly the same as your script but kept expanding the scope like a horrible client and eventually figured it wasn't worth the effort 🙈.

Anyway, if you really want to get it working again you could do the following. This includes making use of the Javascript variables in the window, so if you're sandboxed you'll have to use something like unsafeWindow (UserScripts?) or window.wrappedJSObject (WebExts).


The call

That (hidden) button triggers the YT app to make a call to their playlist modification endpoint. POST: https://www.youtube.com/service_ajax?name=playlistEditEndpoint

{
    // sej being the actual content, JSONified
    sej: JSON.stringify({
        "clickTrackingParams": '<VALUE>', // A tracking param that they use
        "commandMetadata": {
            "webCommandMetadata": {
                "url": "\/service_ajax",
                "sendPost": true
            }
        },
        "playlistEditEndpoint": {
            "playlistId": "WL",
            "actions": [
                {
                    "addedVideoId": '<VALUE>', // YT Identifier
                    "action": "ACTION_ADD_VIDEO"
                }
                // ,
                // {
                //     "action": "ACTION_REMOVE_VIDEO_BY_VIDEO_ID",
                //     "removedVideoId": "<VALUE>"
                // }
            ]
        }
    }),
    csn: '<VALUE>', // A nonce (short for Client Screen Nonce)
    session_token: '<VALUE>' // A token
};

Acquiring those values Both the csn and the session_token can be fetched from the global YT config variable in the window.

function getOriginalWindow() {
    return window; // window.wrappedJSObject;
}

const ytConfig = getOriginalWindow().yt.config_;
const csn = ytConfig['client-screen-nonce'];
const sessionToken = ytConfig['XSRF_TOKEN'];

The videoId and clickTrackingParams can be aqquired from the videos themselves:

let videos = getOriginalWindow().document.getElementsByTagName('ytd-grid-video-renderer');
for(let video of videos) {
    let videoData = video['__data__']['data'];
    console.log(videoData['videoId']);
    console.log(videoData['trackingParams']);
}

It ain't pretty; but it works. The other option is to trigger the function in the Angular block but that was obfuscation & scoping hell so gave up on that idea fairly quick.