In Firefox you can combine JS bookmarklets, keywords and params to do something like this:

javascript:(function(){
    var args = '%s'.split(' ');
    alert(args);
})();

Useful example:

javascript:(function(){
    var args = '%s'.split(' ');
    var subreddit = args[0];
    var search = args[1];
    document.location.href = "https://www.reddit.com/r/" + subreddit + "/search/?q=" + search + "&include_over_18=on&restrict_sr=on&t=all&sort=new";
})();

Bookmarklet format:

javascript:(function() {var args = '%s'.split(' ');var subreddit = args[0];var search = args[1];document.location.href = "https://www.reddit.com/r/" + subreddit + "/search/?q=" + search + "&include_over_18=on&restrict_sr=on&t=all&sort=new";})();

If you assign the keyword redditsearch to that bookmarklet, you can type redditsearch PixelArt zelda on the firefox navbar and you will be reditected to the Reddit search for ‘zelda’ on r/PixelArt.

In general this makes the navbar a very powerful command line in which you can add any command with multiple params.


It seems Mozilla has plans to get rid of this feature, see the ticket Migrate keyword bookmarks into about:preferences managed Search Engines. The good news is that the last comment, besides mine asking them not to remove this functionality, is from some years ago. I hope they change their mind, or forget about it…


TIP: If you don’t want to remember the param order, you can also ask for them with a prompt if no arguments are specified:

javascript:(function(){
    var args = '%s'.split(' ');
    var subreddit = args[0] != "" ? args[0] : prompt("Enter the subbreddit:");
    if (!subreddit) return;
    var search = args.length > 1 ? args[1] : prompt("Enter the text to search:");
    if (!search) return;
    document.location.href = "https://www.reddit.com/r/" + subreddit + "/search/?q=" + search + "&include_over_18=on&restrict_sr=on&t=all&sort=new";
})();

Bookmarklet format:

javascript:(function(){ var args = '%s'.split(' '); var subreddit = args[0] != "" ? args[0] : prompt("Enter the subbreddit:"); if (!subreddit) return; var search = args.length > 1 ? args[1] : prompt("Enter the text to search:"); if (!search) return; document.location.href = "https://www.reddit.com/r/" + subreddit + "/search/?q=" + search + "&include_over_18=on&restrict_sr=on&t=all&sort=new"; })();

Sorry for the reddit examples, this was posted originally on r/firefox some time ago and adapting them to lemmy seemed a bit too much work :P.

  • CrulOP
    link
    fedilink
    arrow-up
    7
    ·
    1 year ago

    I must admit that I’ve only used the multiple-param part in very few cases, but the main “bookmarklet keyword with param” is very useful, some examples I have:

    • Custom searches: lemmy communities, lemmy content
    • Get the link to a page with markdown format: [title or custom text](https://url…)
    • Post image or URL to a subreddit (I need to migrate this one for lemmy)
    • zeus ⁧ ⁧ ∽↯∼
      link
      fedilink
      English
      arrow-up
      2
      arrow-down
      1
      ·
      1 year ago

      oh crul it’s you!

      i don’t suppose you could share some of those? i just had a quick look, but the lemmy search syntax is different to reddit - the communities’ ids are in the url, so the reddit method doesn’t work unless i memorise the id №… (i wish the lemmy devs weren’t so obsessed with numbers)

      • CrulOP
        link
        fedilink
        arrow-up
        4
        ·
        edit-2
        1 year ago

        the communities’ ids are in the url, so the reddit method doesn’t work unless i memorise the id №.

        Yeah… that’s why I didn’t tried that yet. I’m waiting a bit to see what frontend options are.

        The good news is that mlmym uses the community name for posting and searches:

        To make it work with community ids, I planned to have something like the “subreddit shorcuts” from the “post to reddit” bookmarklet (see below). Not ideal, but better than nothing.

        i don’t suppose you could share some of those?

        Sure, here there are. I realized that a couple of them are not really bookmarklets, but simple bookmarks with the %s param. You need to add a keyword and use it with keyword string to be searched.

        lemmy all search

        https://lemm.ee/search?q=%s&type=All&listingType=All&page=1&sort=TopAll

        lemmy community search

        https://lemm.ee/search?q=%s&type=Communities&listingType=All&page=1&sort=TopAll

        get link in markdown

        Execute it without param (e.g.: link) to get [title](url)
        Execute it with a param (link text to display) to get [text to display](url)
        It will show the result in a prompt and you can copy from there. The prompt itself has no effect, it doesn’t matter how you close it.

        pretty printed code
        (function() {
            var title = ("%s" || document.title)
                .replace("[", "\\[")
                .replace("]", "\\]");
        
            prompt("Title:", `[${title}](${document.location.href})`);
        })()
        

        One liner:

        javascript:(function() {var title = ("%s" || document.title).replace("[", "\\[").replace("]", "\\]");prompt("Title:", `[${title}](${document.location.href})`);})()
        

        I also have one to get just the title of a page, but I leave that as an exercise to the reader :D. It’s very easy to modify the link one.

        post to reddit

        Use it with the subreddit name (e.g.: post CassetteFuturism) or the subreddit shortcut (e.g.: post cf).
        If executed with no param, it will show a list of “shortcuts” and will ask you to select one.

        The shortcuts are in the `subKeys``dictionary. That’s the trick that could be used to assign the community ids from the community names (or custom shortcuts). Not practical for a random commmunity, but manageable for the most common ones.

        pretty printed code
        function() {
            var subKeys = {
                cf: 'CassetteFuturism',
                it: 'ImaginaryTechnology',
                iv: 'ImaginaryVehicles',
                ap: 'ApocalypsePorn',
                ss: 'Simon_Stalenhag',
                sw: 'spainwave',
                sk: 'sketches',
            };
            var subreddit = '%s';
            if (!subreddit) {
                var promptText = "Type subreddit:";
                for (var shortcut in subKeys) promptText += `\n- ${shortcut}: ${subKeys[shortcut]}`;
                subreddit = prompt(promptText);
            }
            if (!subreddit) return;
            if (subKeys[subreddit]) subreddit = subKeys[subreddit];
            var title = document.title;
            var url = encodeURIComponent(document.location.href);
            window.open(`https://www.reddit.com/r/${subreddit}/submit?url=${url}&title=${title}`);
        })()
        

        One liner:

        javascript:(function() {var subKeys = {cf: 'CassetteFuturism',it: 'ImaginaryTechnology',iv: 'ImaginaryVehicles',ap: 'ApocalypsePorn',ss: 'Simon_Stalenhag',sw: 'spainwave',sk: 'sketches',};var subreddit = '%s';if (!subreddit) {var promptText = "Type subreddit:";for (var shortcut in subKeys) promptText += `\n- ${shortcut}: ${subKeys[shortcut]}`;subreddit = prompt(promptText);}if (!subreddit) return;if (subKeys[subreddit]) subreddit = subKeys[subreddit];var title = document.title;var url = encodeURIComponent(document.location.href);window.open(`https://www.reddit.com/r/${subreddit}/submit?url=${url}&title=${title}`);})()
        

        (…continues on next comment?)

        • CrulOP
          link
          fedilink
          arrow-up
          2
          ·
          edit-2
          1 year ago

          (… continues from previous comment, I was getting an error when I tried to post all in the same comment)

          post image to reddit

          I don’t recommend this one, I haven’t used in a while and it doesn’t work great with most sites.

          It should works very similar to the previous one, but looking for images on the page. It also writes my usual “Source: [title](url) blablabla” comment for the most common sites.

          The result is a huge mess and very fragile. I post it more as an example of how you could do some things.

          pretty printed code
          javascript: (function(clipboard) {
              var subKeys = {
                  cf: 'CassetteFuturism',
                  cm: 'cybermonk',
                  dp: 'decopunk',
                  it: 'ImaginaryTechnology',
                  iso: 'isometric',
                  iv: 'ImaginaryVehicles',
                  ap: 'ApocalypsePorn',
                  ss: 'Simon_Stalenhag',
                  sw: 'spainwave',
                  sk: 'sketches',
              };
              var args = '%s'.split(' ');
              var subreddit = args[0];
              if (!subreddit) {
                  var promptText = "Type subreddit:";
                  for (var shortcut in subKeys) promptText += `\n- ${shortcut}: ${subKeys[shortcut]}`;
                  subreddit = prompt(promptText);
              }
              if (!subreddit) return;
              if (subKeys[subreddit]) subreddit = subKeys[subreddit];
              var data = getData();
              if (!data) return;
              data.url = encodeURIComponent(data.url);
              window.open(`https://www.reddit.com/r/${subreddit}/submit?url=${data.url}&title=${data.title}`);
              if (!data.comment) return;
              if (clipboard) clipboard.writeText(data.comment);
              showComment(data.comment);
          
              function getData() {
                  var imgs;
                  var title = document.title;
                  var comment = "";
                  var isArtStation = document.location.host.endsWith("artstation.com");
                  var isFlickr = document.location.host.endsWith("flickr.com");
                  var isDeviantArt = document.location.host.endsWith("deviantart.com");
                  if (isArtStation) {
                      imgs = [...document.querySelectorAll(".project-assets-list picture img")];
                      if (!imgs.length) {
                          imgs = [...document.querySelectorAll(".project-assets img")];
                      }
                  } else if (isFlickr) {
                      imgs = document.getElementsByClassName("zoom-large");
                      if (!imgs.length) {
                          alert("No large zoom image found.");
                      }
                  } else if (isDeviantArt) {
                      var deviantArtImgRegex = /\/w_\d+,h_\d+/;
                      imgs = [...document.querySelectorAll(".ReactModalPortal img")].filter(img => !(deviantArtImgRegex.exec(img.src)));
                      if (!imgs.length) {
                          alert("No large zoom image found.");
                      }
                  } else {
                      imgs = document.getElementsByTagName("img");
                  }
                  if (!imgs.length) return;
                  var imgIdx = undefined;
                  if (imgs.length > 1) {
                      if (args.length > 1) imgIdx = parseInt(args[1]);
                      if (imgIdx === undefined || isNaN(imgIdx) || imgIdx < 1 || imgIdx > imgs.length) {
                          numberImgs();
                          imgIdx = parseInt(prompt(`There are ${imgs.length} images, select index:`, 1));
                      }
                      if (isNaN(imgIdx) || imgIdx < 1 || imgIdx > imgs.length) return;
                      url = imgs[imgIdx - 1].src;
                  } else {
                      url = imgs[0].src;
                  }
                  if (isArtStation) {
                      var data = getArtStationData(imgs);
                      title = data.title;
                      comment = data.comment;
                  } else if (isFlickr) {
                      var data = getFlickrData();
                      title = data.title;
                      comment = data.comment;
                  } else if (isDeviantArt) {
                      var data = getDevianArtData();
                      title = data.title;
                      comment = data.comment;
                  }
                  return {
                      title: title,
                      url: url,
                      comment: comment
                  };
              }
          
              function getArtStationData(imgs) {
                  var title = document.querySelector(".project-sidebar-inner h1");
                  if (!title) title = document.querySelector(".artwork-info-container h1");
                  if (!title) return;
                  var author = document.querySelector(".project-author-name a");
                  if (!author) author = document.querySelector(".artist-name-and-headline .name a");
                  if (!author) return;
                  var withMoreImages = imgs.length > 1 ? " **with more images**" : "";
                  var comment = `Source${withMoreImages}: [${title.innerText} (by ${author.innerText} - ArtStation)](${document.location.href})`;
                  var desc = document.querySelector(".project-description p:first-child");
                  if (!desc) desc = document.querySelector("#project-description p:first-child");
                  if (desc) comment += formatRedditCommentQuote(desc.innerText);
                  return {
                      title: `${title.innerText} (by ${author.innerText})`,
                      comment: comment
                  };
              }
          
              function getFlickrData() {
                  var author = document.getElementsByClassName("owner-name")[0].innerText;
                  var title = document.title.substr(0, document.title.length - 9);
                  if (title.indexOf(author) < 0) {
                      title += ` (${author})`;
                  }
                  var comment = `Source: [${title} (Flickr)](${document.location.href})`;
                  var desc = document.querySelector(".title-desc-block h1");
                  if (!desc) desc = document.querySelector(".title-desc-block h2");
                  if (desc) comment += formatRedditCommentQuote(desc.innerText);
                  return {
                      title: title,
                      comment: comment
                  };
              }
          
              function getDevianArtData() {
                  var userLinkElems = document.querySelectorAll("a.user-link");
                  if (userLinkElems.length < 2) return;
                  var title = document.querySelector('h1[data-hook="deviation_title"]');
                  if (!title) return;
                  var comment = `Source: [${title.innerText} (by ${userLinkElems[1].innerText} - DeviantArt)](${document.location.href})`;
                  var desc = document.querySelector(".legacy-journal");
                  if (desc) comment += formatRedditCommentQuote(desc.innerText);
                  return {
                      title: `${title.innerText} (${userLinkElems[1].innerText})`,
                      comment: comment
                  };
              }
          
              function showComment(comment) {
                  var inpt = document.getElementById("source-code");
                  if (!inpt) {
                      inpt = document.createElement("textarea");
                      inpt.id = "source-code";
                      inpt.style.position = "fixed";
                      inpt.style.color = "black";
                      inpt.style.top = "72px";
                      inpt.style.width = "720px";
                      inpt.style.height = "120px";
                      inpt.style.zIndex = "99999";
                      inpt.style.lineHeight = "normal";
                      inpt.ondblclick = () => inpt.select();
                      document.body.appendChild(inpt);
                  };
                  inpt.value = comment;
                  inpt.focus();
                  inpt.select();
              }
          
              function formatRedditCommentQuote(quote) {
                  while (quote.indexOf("\n\n") >= 0) quote = quote.replaceAll("\n\n", "\n");
                  return `: \r\n> ${quote.replaceAll("\n", "  \n")}`;
              }
          
              function numberImgs() {
                  var imgs;
                  var isArtStation = document.location.host.endsWith("artstation.com");
                  if (isArtStation) {
                      imgs = [...document.querySelectorAll(".project-assets-list picture img")].concat([...document.querySelectorAll(".project-assets img")]);
                  } else {
                      imgs = document.getElementsByTagName("img");
                  }
                  for (var img = 0; img < imgs.length; img++) {
                      var parent = imgs[img].parentElement;
                      if (!parent) continue;
                      var numberDiv = document.createElement("div");
                      numberDiv.innerHTML = 1 + img;
                      numberDiv.style.position = "absolute";
                      numberDiv.style.padding = "2px 9px 2px 6px";
                      numberDiv.style.background = "rgba(255, 0, 0, 0.5)";
                      numberDiv.style.zIndex = "9999";
                      parent.prepend(numberDiv);
                  }
              }
          })(navigator.clipboard)
          

          (one-liner missing because I’m still getting an error)

          EDIT: Yeah, lemmy doesn’t like a single line with >5000 characters, hehe. Anyway, I don’t recommend using this last one.

            • CrulOP
              link
              fedilink
              arrow-up
              2
              ·
              1 year ago

              Yep… sadly (AFAIK) reusing code in bookmarklets is not a thing to make it more mantainable.

        • zeus ⁧ ⁧ ∽↯∼
          link
          fedilink
          English
          arrow-up
          2
          arrow-down
          1
          ·
          edit-2
          1 year ago

          bless you crul, you are my absolute favourite lemming. shame that user tags aren’t a feature yet so i notice when i run into you. i also see you have good taste in subreddits, too

          these are great - particularly the markdown one - that never would have crossed my mind, but i’m going to try to remember to use it from now on

          i wish i could move to mlmym, but it’s just not as featureful as either lemmy-ui or reddit+res

          • CrulOP
            link
            fedilink
            arrow-up
            2
            ·
            edit-2
            1 year ago

            ^_^ Thanks for the kind words. I Like meeting nice people here.

            shame that user tags aren’t a feature yet so i notice when i run into you

            It’s a bit cumbersome to use extensively, but this works for me in the default UI (with a Stylus-alike add on):

            a[href="/u/username"] {
              background: red;
              color: white !important;
            }
            

            For mlmym you need to change a[href="/u/username"] with a[href="/lemm.ee/u/username"].

            i wish i could move to mlmym, but it’s just not as featureful as either lemmy-ui or reddit+res

            Yeah, lemmy is very work-in-progress. I’m also eager for it to be more mature. But as I’m not actively helping with the coding, I can’t complain :).

            And, sadly, mlmym deveopment is a bit slow right now. I hope it’s because summer holidays and such. But if it doesn’t catch up in the near future, I will have to move to other options. That’s why I’m not investing too much time right now in my toolchain. I still don’t know what to commit to.

            • zeus ⁧ ⁧ ∽↯∼
              link
              fedilink
              English
              arrow-up
              2
              arrow-down
              1
              ·
              edit-2
              1 year ago

              that’s also a great idea, i’ll see if i can find a way to cram that into µblock. thank you for the idea


              edit: for anyone who wants to do a similar thing, here is the syntax for a µblock filter:

              /(lemm.ee|mlmym.org)/##body a[href*="/lemm.ee/u/Crul"]::after:style(content:"awesome";color:tomato!important;border:1px solid currentColor;border-radius:var(--bs-border-radius, 0.375rem);padding-inline:0.5ch;margin-left:0.5ch;)

              the regex at the beginning is so it should work on both lemm.ee & mlmym; Crul is the username to be replaced; awesome is the tag content; tomato can be any colour but it’s a nice muted red; the *= is so it works with mlmym’s url prefix, and federation suffices (e.g. /u/Crul@lemm.ee); the radius var should be lemmy-ui native but it falls back to 0.375em if the var is not found

              (also i made it look a little prettier / more native)


              i’ll have a look at the mlmym github, see if there’s anything simple i can do; i’ve never used docker, but perhaps i can figure it out

              (also by the way your little ^_^ doesn’t work on the default ui, it makes a superscript underscore)

              • CrulOP
                link
                fedilink
                arrow-up
                2
                ·
                edit-2
                1 year ago

                I just realized that you can also add text tags with the ::after pseudo-element:

                a[href="/u/username"]::after {
                  content: " [TAG]";
                }
                

                also by the way your little ^_^ doesn’t work

                Thanks, fixed!