Exporting and importing Youtube channel subscriptions with AppleScript

Posted  

I have a Google Account that I have been using for the past 16 years. That account is the one I use to watch stuff on Youtube, and I watch a ton of good content on Youtube. As mentioned in another post, I’m about to start a Youtube channel for my bookish things, and the popular wisdom is that you should do your Youtube channel using a separate account.

My problem is quite simple. I want my new Youtube account to be subscribed to many of the channels that my main Google account is currently subscribed to. This way, I can comment on these channels as “Andre Should Be Writing” instead of “Andre Garzia” which are different accounts.

Unfortunately, Youtube does not provide an easy way to extract a subscription list from their site. Well, if you know me, you probably thinking: He’s going to craft a stupid script to do it!, and yes I did.

It ended up being easier than the acquiring the TBR from The Storygraph which is another script I’ve shown here in the past. The tricky bit is manipulating the stupid Web UI from Youtube to open the disclosure triangle that says “Show more” thus loading all the subscriptions on the list (the default is to show 5 or so channels).

That was tricky because Youtube is using some crazy generator to build that UI. There are more than 100 <a id="endpoint"> in there. Yes, you read that right, they’re reusing IDs. And I thought I was the one doing bad practices…

Anyway, I’m having to do some stupid queries to find that button, clicking it, and then scrapping all the subscriptions. By the end of that script, you’ll have a JSON on your Desktop (edit the path in the source) with an array of subscriptions.

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

-- pass a string, list, record or number, and either a path to save the result to, or missing value to have it returned as text
-- from: https://forum.latenightsw.com/t/applescript-record-to-json/668/2
-- maybe adding another command changes the damn md5 code and things get better
on convertASToJSON:someASThing saveTo:posixPath
        --convert to JSON data
        set {theData, theError} to current application's NSJSONSerialization's dataWithJSONObject:someASThing options:0 |error|:(reference)
        if theData is missing value then error (theError's localizedDescription() as text) number -10000
        if posixPath is missing value then -- return string
                -- convert data to a UTF8 string
                set someString to current application's NSString's alloc()'s initWithData:theData encoding:(current application's NSUTF8StringEncoding)
                return someString as text
        else
                -- write data to file
                set theResult to theData's writeToFile:posixPath atomically:true
                return theResult as boolean -- returns false if save failed
        end if
end convertASToJSON:saveTo:


tell application "Safari"
        activate
        log "starting"
        make new document with properties {URL:"https://www.youtube.com/feed/subscriptions"}
        delay 2

        -- expand the "show more" subscriptions toggle.
        do JavaScript "document.querySelectorAll(\"[title~='more']\")[1].click()" in document 1
        delay 3

        -- get all subscribed channels.
        set subscriptions to do JavaScript "subscriptions = Array.from(document.querySelectorAll('#endpoint')).filter(e => e.href.indexOf('/c/') !== -1 || e.href.indexOf('/user/') !== -1).map(e=>{return {name:e.title, url: e.href}})" in document 1
        log subscriptions

        -- save subscriptions to desktop.
        my convertASToJSON:subscriptions saveTo:("/Users/no-my-real-user/Desktop/yt_subscriptions.json")

        log "ended"

        close document 1
end tell

The saved JSON looks like this:

[
 { "name": "Reedsy", "url": "https://www.youtube.com/c/Reedsy" },
    {
        "name": "ShaelinWrites",
        "url": "https://www.youtube.com/c/ShaelinWrites"
    },
    { "name": "JetPens", "url": "https://www.youtube.com/c/JetPensOfficial" },
    {
        "name": "Captured in Words",
        "url": "https://www.youtube.com/c/CapturedInWords"
    },
    {
        "name": "The Film Theorists",
        "url": "https://www.youtube.com/c/FilmTheorists"
    }
]

Once the JSON in the Desktop folder, one can edit it to remove any channel they don’t want to migrate between accounts (or even add new ones if they know the URL).

Sign out of Youtube, Sign-in with your secondary account, and run this other script:

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

tell application "Safari"


        set theFile to choose file

        set theJSONData to current application's NSData's dataWithContentsOfFile:(theFile's POSIX path)
        set theJSON to current application's NSJSONSerialization's JSONObjectWithData:theJSONData options:0 |error|:(missing value)

        activate
        log "starting"

        repeat with i from 1 to count of theJSON
                set c to item i of theJSON as record

                log "Checking " & |name| of c

                make new document with properties {URL:|url| of c}
                delay 3

                do JavaScript "document.querySelectorAll(\"[aria-label~=Subscribe]\")[0].click()" in document 1

                delay 2

                close document 1
        end repeat
end tell

This will subscribe to all channels in the JSON file of your choice. I just used these two scripts to copy 118 subscriptions between accounts.

Be aware that I don’t vouch for these scripts. They worked for me, but they’ll stop working if Youtube changes their HTML.

Did you enjoyed reading this content? Want to support me?

You can buy me a coffee at ko-fi.

Comments? Questions? Feedback?

You can reach out to me on Twitter, or Mastodon, Secure Scuttlebutt, or through WebMentions.

Mentions