console.systems

How to remove all YouTube Shorts from watch history

Sunday, May 5, 2024

Unlike any other solution out there that simply hide the shorts, this one will actually remove shorts from watch history since beginning of time.

By the nature of ever changing YouTube, this solution is likely to break whenever YouTube changes. Check the comments in case someone already posted a fix.

WARNING: I do not take responsibility if something happens to your account, as Google may not like such activity. If you have a billion of shorts watched, removing all may take several hours. So it’s good to take a break once in a while. It is safe to close the page or the browser at any moment and continue later. Also, watch your RAM consumption, loading too much of the watch history may gradually eat all the RAM.

Go to youtube.com/feed/history, then open browser console (usually F12) and put:

(async function() {
  while (window.innerHeight + window.scrollY < document.documentElement.scrollHeight) {
    let days = Array.from(document.querySelectorAll('#contents > .ytd-reel-shelf-renderer'));
    for (let i = 0; i < days.length; ++i) {
      let day = days[i];
      day.scrollIntoView({behavior: 'smooth', block: 'start'});

      let rightArrowButton = day.querySelector('#right-arrow > ytd-button-renderer');
      while (rightArrowButton.checkVisibility()) {
        rightArrowButton.click();
        await new Promise(resolve => setTimeout(resolve, 100));
      }

      let videos = Array.from(day.querySelectorAll('ytd-reel-item-renderer'));
      for (let j = 0; j < videos.length; ++j) {
        console.log(`day ${i + 1}/${days.length} | video ${j + 1}/${videos.length}`);

        while (true) {
          var menuButton = videos[j].querySelector('#button[aria-label="Action menu"]');
          if (!menuButton) {
            console.log('waiting for menu...');
            await new Promise(resolve => setTimeout(resolve, 1000));
          } else {
            break;
          }
        }

        if (!menuButton.checkVisibility()) {
          continue;
        }
        menuButton.click();
        await new Promise(resolve => setTimeout(resolve, 100));

        let removeButton = Array.from(document.querySelectorAll('.style-scope.ytd-menu-service-item-renderer')).
          find(el => el.textContent === 'Remove from watch history');
        if (removeButton.checkVisibility()) {
          removeButton.click();
        }
        await new Promise(resolve => setTimeout(resolve, 100));
      }
      day.remove();
    }

    window.scrollTo(0, document.documentElement.scrollHeight);
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
  console.log('done');
})();

This will go through every visible short on the page, click the three dots menu and then click “Remove from watch history”. After processing all visible shorts, it will scroll the page for more. Once it reaches the end of the history, it will just stop.

How to install Intune in Debian 12

Tuesday, March 26, 2024

See 2026 UPDATE.

I wish I didn’t have to use this abomination of a software from MicroSlop, but I have to. After spending countless hours (and even more in 2026) I had to document this, at least for my own sake.

Common misconceptions

General steps

  1. Create and install a dummy openjdk-11-jre package (see 2026 UPDATE).
  2. sudo apt install msopenjdk-11 (comes from MicroSlop’s repository, which you added at the previous step).
  3. Symlink openjdk-11-jdk to msopenjdk-11:
    ln -s \
      /usr/lib/jvm/msopenjdk-11-amd64 \
      /usr/lib/jvm/java-11-openjdk-amd64
    
  4. update-alternatives --config java and select the one that points to msopenjdk-11.
  5. Follow Ubuntu 22.04 instructions to install Intune.
  6. Finally run intune-portal.

Troubleshooting

Keyring Troubleshooting

This chapter is also 2026 updated.

To be totally safe, we will create a new keyring setup. You will have to figure out yourself how to merge it later with the old one, or check if someone already commented on it.

  1. Install seahorse (unless already installed):
    sudo apt install seahorse
    
  2. Move your old keyring setup somewhere else, e.g. rename it to keyrings~:
    mv -v ~/.local/share/keyrings{,~}
    
  3. Restart gnome-keyring-daemon (this will also recreate the keyring directory in ~/.local/share/keyrings):
    systemctl --user restart gnome-keyring-daemon.service
    
  4. Re-login, to avoid any running application to try access a not-yet-ready keyring.

  5. Start seahorse. In the UI click the plus button “+”, then select “Password keyring”, name it “Default”, optionally set the password (previously blank password was fine but I’m 100% sure anymore, check if someone already commented on it), finally click “Create”. Right click the “Default” keyring in the side bar and select “Set as default”.

  6. Now start intune-portal and try to enroll again.

2026 UPDATE

Pretty much the old guide still applies with one correction: intune-portal now has a hard dependency on openjdk-11-jre package. Workaround is to create a dummy package:

  1. Install equivs:
    sudo apt install equivs
    
  2. Create package description template:
    mkdir dummy-openjdk-11-jre
    cd dummy-openjdk-11-jre
    equivs-control openjdk-11-jre
    
  3. Edit openjdk-11-jre file and replace all the content with following:
    Package: openjdk-11-jre
    Version: 11.999
    Provides: openjdk-11-jre
    
  4. Create a .deb package:
    equivs-build openjdk-11-jre
    
  5. Install the newly created package:
    sudo dpkg -i ./openjdk-11-jre_11.999_all.deb
    

Now you can install intune-portal normally.

Merge Git repositories, preserving chronological order of commits

Wednesday, May 22, 2019

Sometimes you want to split a huge monorepo into multiple smaller repositories, like if you were migrating from Subversion. What if you want to do the opposite? I did.

I had a set of tiny git repositories that describe how to build Debian packages in OpenSuse Build Service. The repositories had similar directory structure and even the commits in each repository were alike. Eventually I thought that merging all repositories into a single monorepo would be more efficient.

I started searching if somebody had already achieved something like this. I found few attempts but they all differ in a way how the history is preserved.

Basically all the solutions I found merge repositories with --allow-unrelated-histories option. It allows merging branches that don’t share common ancestor commits. But in result the history of each repository is trapped inside merge commits. Here is how it would look for two repositories:

     A  B  C  D       W  X  Y  Z
     •--•--•--•   +   •--•--•--•

                  |
                  v
     A  B  C  D       W  X  Y  Z
     •--•--•--•   +   •--•--•--•
    /                /
•--•-------------•--•-------------•

Which is inconvenient if you still want to reorder or squash some consequent commits across multiple repositories. This is how I wanted the commits, ordered chronologically:

A  W  B  C  X  Y  Z  D
•--•--•--•--•--•--•--•

Here is the approach I went with:

mkdir -p ~/merge-attempt/repos
cd ~/merge-attempt/repos
git clone git@githost:user/repo1
...
git clone git@githost:user/repo9
cd repos
for R in *; do
  pushd $R
  git format-patch --root --src-prefix=a/$R/ --dst-prefix=b/$R/
  for P in *.patch; do
    grep '^Date: ' $P | \
      sed 's/^Date: \(.*\)/\1/' | \
      date -Iseconds -f - | \
      sed 's/[:+]/-/g' | \
      xargs -I{} mv $P {}.patch
  done
  mv *.patch ../..
  popd
done

Here --src-prefix and --dst-prefix arguments allow us to preconfigure the patches, so when applied, the files would be created in subdirectories named according to original repository.

We should get something like this:

2018-09-23T23-42-02-03-00.patch
2018-12-10T13-51-56-02-00.patch
2019-04-16T20-05-20-03-00.patch
2019-04-16T20-25-31-03-00.patch
2019-04-16T20-35-56-03-00.patch
2019-04-16T20-38-16-03-00.patch
2019-04-16T20-49-06-03-00.patch
mkdir -p ~/merge-attempt/monorepo
cd ~/merge-attempt/monorepo
git init .
git am ../*.patch
git filter-branch --env-filter 'export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"'

And that would be it.

How to disable Power Button in Openbox and Debian 8 Jessie

Sunday, October 9, 2016

This is something that was bothering me for quite a while. Rarely but I happened to press accidentally the power button and shut down my computer, loosing all unsaved work. These few times I tried to search for solution, it never worked. After another undesired power off I decided to sit down and fix it.

Why I never managed to get it working properly is due to the combination of systemd and Openbox. Both are capable to set what the special buttons like power or sleep do. So fixing it in the either one kept the button misbehaving. And the trick was to configure it in both places.

Let’s first disable the button in Openbox. Edit ~/.config/openbox/rc.xml and find the XF86PowerOff piece and comment it out by wrapping it between <!-- and -->:

<!--
<keybind key="XF86PowerOff">
  <action name="Execute">
    <command>systemctl poweroff</command>
  </action>
</keybind>
-->

Reload the Openbox config file:

$ openbox --reconfigure

Time for the systemd part. Open /etc/systemd/logind.conf and find the line with HandlePowerKey in it. By default the value for the power button handler is poweroff. Remove the preceding # symbol and change the value to ignore:

HandlePowerKey=ignore

Lastly, restart logind:

$ sudo systemctl restart systemd-logind

And we’re done. Now the power button is harmless. Of course it will continue working to power on the computer or wake it up from the sleep.

P.S. In case something doesn’t work, check the logs ( -f for real time update):

$ sudo journalctl -f

How to remove all SoundCloud likes at once

Friday, September 30, 2016

How so there is no way to track which tracks I listened? There are various “SoundCloud History” browser extensions, but every other streaming service has that (I know only YouTube) out of the box.

UPDATE Nov 2016: It took only few years of whining to get Listening history. Good job SoundCloud!

So my workaround is to use the Like button. I basically like every track in my stream I listened. And to keep it clean and tidy once in a while I remove all the likes to start fresh. Yet even removing all the likes at once is not possible. I just love the tech support answer:

You can’t do that. Hope that helps.

Helps a lot!

Go to soundcloud.com/you/likes, then open browser console (usually F12) and put:

(async function() {
    while (true) {
        var a = Array.from(document.querySelectorAll(".sc-button-like[title='Unlike']"));
        if (a.length == 0)
            break;
        a.forEach(button => button.click());
        // wait 2 seconds before more tracks get loaded:
        await new Promise(resolve => setTimeout(resolve, 2000));
    }
})();

What it does is that it goes through every Unlike button and clicks it. It may take a while if you have many likes.

WARNING: Snap, SoundCloud decided to disable my Liking abilities for who knows how long:

We’ve noticed a high volume of liking coming from your account and we would like to ask that you slow down. If your account is performing many more actions when compared to most others, it loses the human touch. Remember that there is a fine line between promoting yourself and bombarding other users with notifications. We want our community to remain a genuine, positive place for members to interact, so remember to stick to our Community Guidelines. You can continue liking again in 5 hours. The more you hit these limits, the longer the block will last.

Older Posts ->