cho.sh
2,244 notes
Liked on XI made a mistake. When Jack and I decided to organize this $100K Hackathon, my biggest concern was cheating. Unlike a regular hackathon, everyone participates from home. And because the winner is whoever makes the most PROFIT (not revenue), there are so many ways to manipulate the numbers. So I added a $99 entry fee. One thing I’ve learned from building businesses is that people tend to be more committed when they pay for something. I thought it would filter out spam, attract serious builders, and make the competition fairer for everyone. But I completely missed the other side. 3 years ago, I was a living with my apps. Today, I’m financially free. My life changed so much that somewhere along the way, I lost perspective on what $99 means to someone else. For someone in India, someone struggling to pay their bills, or someone trying to make their first dollar online, $99 can be a lot of money. And those are exactly the people I want to help! I’ve spent years sharing what I’ve learned, reviewing random people’s landing pages, and organizing free meetups around the world. Not because there’s money to make, but because I genuinely love seeing people build things and succeed. And somehow, I was so focused on keeping cheaters out that I didn’t realize I was also keeping genuine builders out. That’s my mistake. So I’ve decided to make the $100K Hackathon completely FREE :) Everyone who already paid got a full refund. I’m still worried about cheating. That problem hasn’t disappeared, and Jack and I will have to figure out better ways to verify profits and keep the leaderboard fair. But that’s our problem to solve. Thank you to everyone who shared their thoughts. Sometimes you need people to remind you of things you’ve forgotten. I genuinely hope this hackathon changes someone’s life. ❤️Liked on XIt’s time to bring back Cafe CursorPosted on Xyo @pendev i can't live share edit a .pen file? it's the most needed featurePosted on XI'm coining a word "Agentsplaining" Agents condescendingly assuming the user don't know fuck and repeating the obviousReplied on X@jayhxmo @raycast Hard to explain. It's the small detailsPosted on X@raycast iOS keyboard is insanely good. Might resub Raycast pro just cuz of thisReplied on X@ishuagra02 I saw a theory that F5.2 is a post train of 5.1, but O5.5 is a distillation of F5.5(unreleased new pretrain) and thats why O5.5 > F5.2Liked on X@anaclumos don't know what is actually improved 👀Posted on Xam i the only one underimpressed with 5.2 fableReplied on X@bvvst great minds think alike https://t.co/YRFWhb1mcOLiked on XClaude Fable 5.2 is out and it's the perfect time to run this god-level prompt on your codebase: "I want you to audit our codebase, is anything here unnecessary, overly complicated in our current setup, or based on weak assumptions? Challenge them. - What can be deleted entirely? - What can be simplified now that unnecessary pieces are gone? Then make the changes. Prefer deleting over simplifying, simplifying over optimizing, and optimizing over automating. This product is being used by thousands of customers, do not cut any corners." This prompt is one I run often and leads to the best results.Replied on X@akshayadinesh19 @bot can we please BYOM for botsLiked on XTo be fair, the Chinese models have a much lower refusal rateLiked on XF*CK IT, im creating a library of AI slop indicators. my feed is full of taste larpers. stay tuned https://t.co/5Muv8nQRm3Liked on XJENSEN! THATS NOT WHAT WE MEANT BY CHINESE MODELS!!!!!!!Liked on Xmy parents had to declare bankruptcy when I was a kid, so they had every reason to pressure me towards a more stable career path instead, they were so patient with me, even as i failed startup after startup for years so getting to tell my mom that everything turned out okay was a really special moment :) for those who can't read Korean, her first message roughly translates to: "Really!!! Congratulations my son. So much :') Thank you God!" i know I've been posting about my exit for like a week now, but it really is a big deal for me and my family! i'll share more about how this all happened and some tactical advice later this week, but for now i'm just riding out all the emotions to quote my mom, thank you God!!!!Liked on X@thefarmers_Dog it stands for Egg GzampleLiked on X🦍 Introducing Memorilla: memory as a modality for LLMs Memorilla turns everything a frozen LLM needs to remember into just 16 memory embeddings ⚡ It uses up to 4,212× fewer tokens and is 27× faster than full context inference while more accurate 🎯 Pushes the Pareto frontier over RAG and agentic memory in personalization, long-document and knowledge QA A thread 🧵:Liked on XThere's a huge product opportunity downstream of Tailscale etc too. At @tldraw we've started designing for "high trust networks" and it's been a beautiful thing. 1. Features that would be a nightmare on the internet are okay on my computer and mostly okay on private networks. Websites that execute user-generated scripts, control production systems, allow for users to send desktop notifications, spend tokens, or directly prompt my agent. Crazy stuff that would only make sense if everyone was in a committed polycule. 2. When everyone on the server can be trusted to have _external_ reasons for good behavior (eg keeping their job, or maintaining friends, family, church, mafia org), the software can be designed in a default social way. Most apps default to isolation, low horizontal visibility, highly restricted collaboration. Makes sense if the social contracts are inside of the app, but if you can trust that they live outside of the app then you can get wild. Example being small group chat names as an emergent comedy phenomenon because anyone in the group can change the name. 3. This can work for commercial products, too, not just internal stuff. Security matters more than ever but the way we've seen that manifest is that more companies are more confident in their own solutions than anything we could provide, to the point where owning data and access is a better value proposition than having it managed. Always has been true for big companies but now even small companies can get a good secure network set up pretty easily, and the hooks we need to build are easy enough. tldraw offline got us started down this road (and shout out to @pendev for first introducing me to the idea of desktop + mcp). We've been bringing that product to private networks and it's been exciting to see how much we can get away with. Keep an eye outReplied on X@saradu birds eye viewLiked on XApplications close in 2 days!! If you have a cool bio idea, and $5-10k will go a long way for you, please apply!!! https://t.co/NCvmrNC53cLiked on XWe've been early adopters of Rust since 2018 and a lot of our infra, voice tech, and even some of the current client is already Rust, the holy grail was getting the whole client there. That means Electron goes away, and so does React Native, mobile keeps native UI but shares app code with desktop via Rust. We hope to get it into testing with users soon™. (And it's not Tauri, it's GPUI, so good guess everyone.) Alright, back to staring at the WoW Forever login screen.Reposted on XOh boy. https://t.co/X7SSskGuGvLiked on XRIP .si domain squatters
YouTube Comment Language Filter

YouTube Comment Language Filter

Warning

Over a year old. May be outdated

Note

This is my own analysis, and there's no way to verify it unless YouTube releases its source code. Keep that in mind while reading.

YouTube, a strange video platform where a Korean singer sings a Korean song on a Korean broadcast, but there are no Korean comments

YouTube has no way to view comments by language. This is the story of building "YouTube Comment Language Filter" through its alpha, beta, and general release.

0. The idea

One day, out of frustration and curiosity, I decided to look at how YouTube's comment HTML is put together. After poking at a bunch of values in the console, I wrote a JavaScript file that removes every comment without Korean characters. My past experience with a project called HangulBreak.py about Hangul and Unicode conventions was helpful.

🧼 The first filter script. It removes YouTube comments that don't contain Hangul. It's also stored in the first commit of the GitHub repository.

js
var commentList = document.getElementsByTagName("ytd-comment-thread-renderer");
var comment;

function containsUnicode(str, startUnicode, endUnicode) {
  for (var i = 0; i < str.length; i++) {
    if (
      startUnicode.charCodeAt(0) <= str.charCodeAt(i) &&
      str.charCodeAt(i) <= endUnicode.charCodeAt(0)
    ) {
      return true;
    }
  }
  return false;
}

for (var x = 0; x < commentList.length; x++) {
  comment =
    commentList[x].childNodes[1].childNodes[1].childNodes[3].childNodes[3]
      .innerText;
  if (containsUnicode(comment, "가", "힣")) {
    // comment = "한글임 \n" + comment;
  } else {
    // console.log(typeof commentList[x]);
    commentList[x].parentNode.removeChild(commentList[x]);
  }
}

for (var x = 0; x < commentList.length; x++) {
  console.log(
    commentList[x].childNodes[1].childNodes[1].childNodes[3].childNodes[1]
      .innerText,
  );
  // The author's name and date of creation are concatenated together. "Name\nDate Created"

  console.log(
    commentList[x].childNodes[1].childNodes[1].childNodes[3].childNodes[3]
      .innerText,
  );
  // Comment!
}
// End of code

/* Notes: This is initial code, and while it works in some cases.
 * there are a number of errors and performance issues.
 * The code, which has been debugged and improved, is uploaded to GitHub.
 */

At this point, I thought I could grow this code into a project. However, there were a few problems with this script.

  • First, I had to paste the code from the console, which made it difficult and inconvenient for others to use.
  • It didn't rerun on its own, so I had to re-run it in the console whenever the comments reloaded.
  • Since it could only filter out Korean characters, it was very limited in use, and it was slow to run.

Fixing these became the obvious next goal. A Chrome extension seemed like the easiest place to start.

  • Edge and Whale are also Chromium-based, and Firefox add-ons can be created as Chrome extensions.
  • Safari doesn't play YouTube 4K videos, so many Safari users also use Chromium to view YouTube.
  • Internet Explorer has lost support for YouTube.

I also wanted people who aren't great with computers to use it easily, so it had to sit between the video and the comments, "just like YouTube does," where you'd naturally move your cursor from the video down to the comments. So I didn't want a Chrome extension popup. I wanted the menu built right into the YouTube page.

We have a spy in our midst...

Now the goal was concrete.

  • This Chrome extension would insert a language control interface between the video and the comments.
  • The interface will allow all comments to be filtered automatically. It will continue to work even when more comments are loaded.
  • It should be scalable so that adding new languages is not a major challenge.
  • It should be reasonably fast.

See also: versioning

Everyone numbers versions differently. In this post I'll use the following.

  • First digit is a major update.
  • First decimal is a feature, second decimal is a bug fix.
  • Third decimal is a store re-upload with no code change.
NameVersionDescription
Alpha0.1+Minimal functionality, released to a small number of people for feedback
Beta0.9+Most of the original concept implemented, distributed to a large number of people for feedback
Official1+Continuous improvement, distributed to anyone with feedback

1. Alpha versions should be released as soon as possible

An alpha (or more precisely, a Minimum Viable Product) needs at least the basics working. Specifically, it had to

  1. refilter automatically on every new load,
  2. let you see the full comments again anytime, and
  3. install in one click.

The first question was, "How do we make it happen automatically?".

Method 1. Time-based autoplay

For people who just turn on a video and watch it, rerunning the filter on a timer wastes performance. But if the gap between runs is too long, reading comments gets annoying. It was the first option I thought of, and the first one I threw out.

Method 2. Detect YouTube's loading icon

YouTube's loading icon

When I checked, the <can-show-more> tag appeared and disappeared under the comment whenever the loading icon appeared, so I thought I could catch the moment when YouTube's obfuscated javascript code inserted the <can-show-more> tag and re-run the filter accordingly.

But I think I had that idea because I forgot what obfuscation means... After a few hours of struggle, I gave up

Method 3. MutationObserver

Then I discovered MutationObserver in JavaScript. The idea is to set a target to observe and a config to observe, and then run a callback function when a change occurs that meets the config. I used the YouTube comment HTML as the target and made it react to changes in the childNodes and attributes in the HTML. Just as we wanted, it was re-run every time the comment loaded. Problem solved.

Performance tanked, though. console.log was firing tens of thousands of times, so I deleted it and things got usable. To speed things up a bit, instead of testing the language of the comment each time, I wrapped the comment with display:none; and recorded the result in an HTML tag. When I clicked the button to view the full comment, it would remove the display:none;, and when I ran it again, it would only use the tags I had recorded. Solution 2. (I didn't realize this until later, but it wasn't a complete solution. This way of utilizing annotations didn't improve speed much and created more problems. See YouTube's SPA-ness during beta #2.)

Next three days went to learning how Chrome extensions are structured and porting the code over, mostly from the official docs, Stack Overflow, and a Udemy course. Solution 3.

Finish the alpha version

User review of the alpha version. "Slow performance, but it works" is an accurate description of the alpha version

We started development on March 6, 2020, and finished the first alpha version on March 11. We shared the alpha with a small group of testers and spent about a week collecting user reviews and researching improvements and bugs.

Screenshot from the alpha version. The alpha version had a button to switch between Korean and full comments

2. Beta version

We found and improved several problems in the alpha version.

① YouTube's Lazy Loading Issue

YouTube loads content lazily. Lazy loading refers to the practice of waiting and fetching information when it's needed, rather than loading everything at once. Lazy loading is usually applied to large images, but YouTube has taken it a step further and lazily loads the HTML itself! (I don't know if that's accurate, but that's what I saw at the time of development).

When you first land on a video page, the HTML for the comment interface doesn't exist. When the user starts scrolling to view the comments, a gray loading icon appears and loads the comment HTML. (Why? Because it saves querying the comment DB. Seems like a clever solution.) Since the comment HTML doesn't exist at the document_end of the extension, the extension throws an error and exits shortly after.

Lazy Loading on YouTube

Solution.

Lazy loading kept me from seeing the comments themselves, but I could still stick the filter menu into the comment box and it worked fine. Luckily the comment box showed up soon after the page loaded (at document_end), so if the comment HTML wasn't there yet, I had it rescan for the comment box Xpath every 0.5 seconds.

This may seem a bit puzzling, as I had previously ruled out retrying at regular intervals as a waste of computation. In the previous case, the timer would loop indefinitely because it was re-checking the comments after a certain amount of time, whereas in this case, it only retries until the comments window loads. In practice, this workaround terminates normally after one or two retries. If it takes longer than that, your internet is too slow to view YouTube itself.

Bypassing YouTube's Lazy Loading

Then came the follow-up bugs. Because I wasn't very good with JavaScript, I didn't know how to efficiently retry certain functions after a certain amount of time. YouTube would sometimes load infinitely when accessed by video URL or directly from search results. It turned out that we needed to make the JS retry after a certain amount of time, but by making it wait for a certain amount of time, we were preventing other JS from running. This bug can also be found in GitHub Issue #4 and was finally fixed in v1.1.4. (The bug showed up about once in 20 times, and it was harder to reproduce the error situation than to find the bug in the error situation.)

② YouTube's HTML component recycling issue

For a Chrome extension to get into a website and change things, you have to list every address it'll touch in manifest.json. Initially, I used https://*.youtube.com/watch* because I thought it would only need to run on the video page. However, I ran into a problem when I tried to access the video from the YouTube home screen.

YouTube reuses a lot of components from HTML. If you've ever watched a YouTube video and pressed the i button to launch the miniplayer, you'll recognize this. YouTube doesn't actually take you to the video page, it just (1) covers the existing screen, (2) puts a new page on top, and (3) replaces the address in the web address bar. So naturally, when you press the i button to open the miniplayer, you'll see the same window you saw before playing the video.

Widening the pattern to https://*.youtube.com/* made it worse. Now the menu got injected in wrong places, even on pages with no comment box.

Apparently the Chrome extension only checks the domain when a new page is loaded

Also, on video pages, even if the filter menu was inserted correctly, if you navigated to another video with the filter enabled, it would sometimes filter the "current video's comments" based on the "previous video's comment language". This also seemed to be caused by YouTube's recycling of the comment component. I mentioned earlier that I was jotting down the results in the comment HTML to speed things up, but this also scrambled the results and made the error bigger.

Solution

The extension watches which site you're on. If the domain is YouTube, it gets ready to add the filter, then checks the domain each time by hand and only adds the filter on youtube.com/watch.

YouTube is a SPA

In this case, we need the "Can read user's history" permission when installing the extension. For this reason, I've included a note about the permissions used in the corresponding commit and installation completion page. As you can see from the GitHub open source, the browsing history is not sent externally.

I also set it up so that when you navigate to a new page with filters on, it will (1) reset all filters and filter results, (2) reload the comments on the new page, and (3) wait.

Sometimes the problem would reappear. However, this seems to be more of a YouTube bug. Even without this extension, YouTube's web commenting system is notoriously buggy, with incorrect comments appearing and comments on videos getting mixed up. In this case, a refresh should fix it.

③ Speed issues

In the alpha the filter was really slow, and just deleting every console.log sped it up a lot. As long as the filter runs faster than people read comments, it's usable, so fixing the problems above came first. Later I found this problem too.

js
for (var comment of commentList) {
  if (comment.id === "") {
    var commentString =
      comment.childNodes[1].childNodes[1].childNodes[1].childNodes[3]
        .childNodes[3].childNodes[1].innerText;
    if (containsSelectedLang(commentString)) {
      comment.id = "contains-SelectedLang";
    } else {
      comment.id = "no-SelectedLang";
    }
  }
  if (comment.id === "no-SelectedLang") {
    comment.style = "display: none";
  }
}

The comment address in commentString doesn't currently work because it has changed several times with YouTube's updates.

Solution...?

We still haven't fully fixed it. For now, in v1.2 we switched to script names instead of language names, to make it clearer that this thing tells scripts apart. The plan is to add a natural language processing module in the end. But Chrome extension policy means using one would take tearing up a good chunk of the code, so I'm still looking into it.

3. Full version

The full version had no speed or feature improvements to the filter itself. It was all usability. A settings window to hide unused languages, a landing page that opens right after install, a short bug-report guide, and a redone promo image.

You might think this is a pointless task, but it works wonders for attracting more users than expected

I did a small experiment a while back, and the difference between the number of people who came in with and without the promo image was about 4x.

Finally, I ported the Chrome extension to Firefox as an add-on. Write-up in (original post).

Overall thoughts on v1

My goal in releasing v1 was to create a deliverable that I could use without thinking about it. If an extension breaks along the way and you start to care about it, it ruins the fun of watching YouTube.

But the current v1 doesn't break the fun. I can just use it without thinking about it and it works fine. (It just all... works!)

Review from a friend who has been using it since the beta version

In addition, the original purpose of finding Korean comments works almost flawlessly. After all, Korean comments will have at least one Hangul character in them.

In the future

I'm working on v2. The most popular feedback on v1 was "more styles" and "better language detection". A fundamental problem with Chrome extensions is that it is very complicated to add external files or modules from within the Chrome extension itself. Using the npm library is also cumbersome. The solution is to use something called Webpack, which requires a significant rewrite of the code. Still, I can think of a lot of fun ways to use it, so I'm working on v2 in my spare time.

There's also talk that YouTube is experimenting with the percentage of foreigners viewing Korean videos by deliberately pushing Korean comments down in the comment rankings, so I don't think this project will ever end.

That's why the title says Part 1. Someday, if v2 is completed, or if something happens that deserves to be remembered, you'll see part 2 of this post.

Backlinks3