Copy name and URL of all the opened tabs of the frontmost Arc Browser window

Hi, I would like to create a macro that will copy all of the Name and URL of the frontmost Arc Browser window, so I can paste the results in Apple Notes or another software

I was able to write this script to get the name and url of the active tab of the Arc front window

tell application "Arc"
	
	set theTitle to title of active tab of front window
	
	
	set theUrl to URL of active tab of front window
	
	set the clipboard to "[" & theTitle & "]
(" & theUrl & ")"
end tell

Unfortunately, with my really limited Applescript knowledge I can't go any further.
How can I modify this script to get the names and url of all the tabs of the Arc frontmost window, skipping the pinned tabs?

To test in Script Editor, set the language selector drop-down at top left
to JavaScript (rather than AppleScript):

Expand disclosure triangle to view JS source
(() => {
    "use strict";

    ObjC.import("AppKit");

    // main IO()
    const main = () => {
        const allTabs = Application("Arc").windows.tabs;

        return copyText(
            zipWith(
                title => url => `[${title}](${url})`
                // title => url => [title, url]
            )(
                allTabs.title()
            )(
                allTabs.url()
            )
            .join("\n")
        );
    };

    // --------------------- GENERIC ---------------------

    // zipWith :: (a -> a -> b) -> [a] -> [b]
    const zipWith = f =>
        // A list with the length of the shorter of
        // xs and ys, defined by zipping with a
        // custom function, rather than with the
        // default tuple constructor.
        xs => ys => xs.slice(
            0, Math.min(xs.length, ys.length)
        )
        .map((x, i) => f(x)(ys[i]));


    // copyText :: String -> IO String
    const copyText = s => {
        const pb = $.NSPasteboard.generalPasteboard;

        return (
            pb.clearContents,
            pb.setStringForType(
                $(s),
                $.NSPasteboardTypeString
            ),
            s
        );
    };

    return main();
})();

Copies a Markdown link list, with labels and urls, to the plain text clipboard.

1 Like

For a version which copies in tab-delimited (rather than Markdown) format:

edit the function applied by zipWith to:

title => url => `${title}\t${url})`
1 Like

Or to restrict the harvest to the tabs of the front window:

Expand disclosure triangle to view JS source
(() => {
    "use strict";

    ObjC.import("AppKit");

    // main IO()
    const main = () => {
        const
            allTabs = Application("Arc")
            .windows.at(0).tabs;

        return copyText(
            zipWith(
                title => url => `[${title}](${url})`
                // title => url => [title, url]
            )(
                allTabs.title()
            )(
                allTabs.url()
            )
            .join("\n")
        );
    };

    // --------------------- GENERIC ---------------------

    // zipWith :: (a -> a -> b) -> [a] -> [b]
    const zipWith = f =>
        // A list with the length of the shorter of
        // xs and ys, defined by zipping with a
        // custom function, rather than with the
        // default tuple constructor.
        xs => ys => xs.slice(
            0, Math.min(xs.length, ys.length)
        )
        .map((x, i) => f(x)(ys[i]));


    // copyText :: String -> IO String
    const copyText = s => {
        const pb = $.NSPasteboard.generalPasteboard;

        return (
            pb.clearContents,
            pb.setStringForType(
                $(s),
                $.NSPasteboardTypeString
            ),
            s
        );
    };

    return main();
})();
1 Like

Thanks a lot @ComplexPoint !
Your last example is exactly what I need, I just wold like to divide the Page Title and the Url with a line break to have better clarity when I paste the text.

PS to restrict your harvest to unpinned tabs on the front window you would need a .where or .whose clause:

Expand disclosure triangle to view JS source
(() => {
    "use strict";

    const main = () => {
        const
            frontWindowUnpinnedTabs = Application("Arc")
            .windows.at(0)
            .tabs.where({location: "unpinned"});

        return zipWith(
            title => url => `${title}\t${url}`
        )(
            frontWindowUnpinnedTabs.title()
        )(
            frontWindowUnpinnedTabs.url()
        )
        .join("\n");
    };

    // --------------------- GENERIC ---------------------

    // zipWith :: (a -> a -> b) -> [a] -> [b]
    const zipWith = f =>
    // A list with the length of the shorter of
    // xs and ys, defined by zipping with a
    // custom function, rather than with the
    // default tuple constructor.
        xs => ys => xs.slice(
            0, Math.min(xs.length, ys.length)
        )
        .map((x, i) => f(x)(ys[i]));

    return main();
})();
1 Like

Thanks again @ComplexPoint , but this time when I run the script the result doesn't get copied on the clipboard like it was before

If you look at the earlier versions, you will see how to wrap the expression in copyText

Thanks a lot @ComplexPoint with your help I was able to get two scripts, one copies all the tabs and the other only the unpinned ones and there's a carriage return between tab name and URL

1 Like