I quit my role as News Editor of How-To Geek last week. It was the best job I ever had, until the company was sold to Valnet in 2023, one year after I started. The goals slowly became completely detached from reality, and the abysmal technical stack made actual productivity a daily struggle. I tried my best to maintain high editorial standards, but I’ll let others decide if I sufficiently achieved that goal.
I have only been in the tech journalism/blogging industry for about nine years. Still, I feel like the ladder that I climbed up has been burned behind me. There are so many people in this industry who pushed me to be a better writer, a better researcher, and a better person. I wanted to carry that debt forward, but that’s difficult to do in an environment that prioritizes quantity over quality.
This industry has rapidly consolidated—three of the four publications I have worked at are now owned by Valnet. There are only a handful of companies left who will pay for a full-time tech reporter or editor in the United States at a living wage, and I applied at all of them many times over a period of ~2.5 years. I achieved a grand total of two tech reporter/editor interviews, plus one interview for a marketing job. I still had health insurance and rent money the entire time, though, which is a lot better than many other folks in this industry.
I have been persistently burnt out for the last 6-8 months because of this job. It made me miserable and jaded, and I know I dumped that miserable attitude onto others at times. I’m eternally thankful for my friends for putting up with that, and I will try my best to not be that person in the future.
There are still a lot of good people at How-To Geek, and other Valnet publications, and some good articles and videos—I hate the word “content,” sorry. However, I strongly believe that everything good coming out of Valnet happens despite of Valnet, not because of it. If you see a genuinely good article, it’s because someone wasn’t paid enough for it, or they worked overtime, or they went over their time budget for that one and won’t reach their output goals this month.
This week, I’m changing careers, and I’ll talk more about that soon. My own tech blog (not the one you're reading right now), tech history podcast, and software side projects are still going strong, so check those out.
I have officially ended development of Nexus Tools, my installer for ADB, Fastboot, and other Android system tools for Windows, Mac, and Linux. It's for a good reason, though: the alternatives are better and more accessible.
When I made the first version of Nexus Tools for Linux and Mac in 2013, Google did not provide ADB, Fastboot, and other common Android utilities as simple downloads. You had to install the Android SDK first, or download the binaries from somewhere else and add them to your system's path. Some Linux distributions had them available as a package, but they were often out of date. Nexus Tools turned the installation into a one-step process, using a Bash script and mirrored copies of Google's binaries.
Later versions added improved support for Chrome OS and the Windows Subsystem for Linux (at the time, Bash for Windows 10), udev rules installation to fix USB detection issues on Linux, fixes for different shell environments, and other small improvements. Nexus Tools was covered by MakeUseOf, XDA, Android Police, 9to5Google, Wccftech, Redmond Pie, and other outlets over the years. In 2021, I rewrote it in Dart and added support for Windows.
However, Nexus Tools gradually became unnecessary. In 2017, Google finally created an official download for ADB and Fastboot without the Android SDK, and Nexus Tools switched to that method shortly afterwards. That download also made it easy for other package managers to offer ADB and Fastboot, and keep them updated along with all your other installed software.
The easy availability of other methods, along with fewer breaking changes in new versions of Android, has contributed to Nexus Tools usage dropping over the years. Nexus Tools peaked at around 500 users per week in 2023, and now averages around 50 users per week.
Nexus Tools is cited in many guides and videos around Android modding and development, and I didn't want to break those resources. If you run one of the Nexus Tools installation scripts today, you will see instructions for installing ADB and Fastboot with another package manager, such as Homebrew, Winget, APT, or DNF. The Readme file in the GitHub repository contains the same instructions.
If you already have those applications installed on your system with Nexus Tools, the script will offer to delete those copies, so they don't conflict with the other methods. There are also standalone uninstall scripts for Mac, Linux, and Windows in the repository.
Nexus Tools had a good run, but it's turned into a package manager for one specific package, and it's just not needed at this point.
Nexus Tools statistics
As a final farewell, here are some fun statistics about Nexus Tools, using the data collected from November 2023 to February 2026 through Plausible Analytics.
Modern web browsers are increasingly focused on features beyond the core browsing experience, many of which just end up as distractions. Chrome gives you coupon codes while shopping. Microsoft Edge fills the New Tab page with clickbait garbage articles from MSN, and previously tried to sell you loans.
The generative AI era has made this even worse. Google's Gemini AI is now everywhere in Chrome, and the AI Search mode that told people to eat rocks and cook with glue is now prominently featured in the address bar. Edge also has countless Copilot AI integrations, and Firefox is getting an AI browsing mode. When these features aren't using cloud AI services, Chrome, Edge, and Firefox have their own local AI models that eat up system resources.
Call me old fashioned, but I want my web browser to be just be a browser. I don't want shopping integrations, or AI agents taking over my cursor, or local AI models running constantly in the background just to reshuffle my tabs. I shouldn't have to resort to Safari or half-working Firefox forks for that.
My solution is Just the Browser.
Making a better browser
Just the Browser helps you remove AI features, telemetry data reporting, sponsored content, product integrations, and other annoyances from desktop web browsers. It accomplishes this with group policy configurations—hidden settings provided by Google, Mozilla, and Microsoft for businesses and other large organizations. Those options are how IT departments can lock down certain features for computers at work or school, but now they can be a force for good.
You know that "AI kill switch" that Firefox will eventually add? It's already a hidden setting that Just the Browser can enable for you. It will also turn off all Gemini and AI Mode features in Chrome. In Microsoft Edge, it turns off all Copilot features, advertisements for Adobe Reader, articles and ads on the New Tab page, automatic data import from other browsers, and much more.
Importantly, all that functionality remains disabled, which isn't always the case with user-accessible settings. For example, Microsoft Edge likes to revert your New Tab page settings after a while, so you see those garbage MSN articles again. That does not happen with group policy settings.
Everyone has their own definition of "bloatware" and "spyware," so the default configurations are limited in scope. They don't go full minimalist, nor do they install extensions to boost privacy and security.
Just the Browser includes browser configurations for Windows, Linux, and macOS, along with guides for installing them. The documentation also explains each setting that is changed. The best part is the setup script, which can install or delete the configuration files for you in just a few clicks. They are regular Bash and PowerShell scripts, so they work on everything from x86 Fedora Linux to ARM Windows 11.
The entire project is open-source on GitHub, including the configuration files, documentation, scripts, and website. The configuration settings used by web browsers will change over time, and I'm hoping others will help me stay on top of changes and add support for more browsers.
Why not alternative browsers?
I know the most common response to this project will be "why not switch to [x] browser?" It's true that LibreWolf, SeaMonkey, fresh Chromium builds, and various other Firefox forks are closer to a minimal browsing experience. Vivaldi would also fit the bill after changing a few settings—as far as I know, it doesn't quietly turn features back on like Edge does.
However, most of those browsers have downsides. LibreWolf is one of the popular Firefox forks at the moment, but the project's own FAQ promises "no expectations" of continued support, and it doesn't have signed macOS builds. They don't always offer data synchronization with accounts or DRM support. When a zero-day security vulnerability is found in Chromium or Firefox, it can sometimes take a while to trickle down to the various forked browsers.
With the custom configurations in Just the Browser, you can keep using mainstream web browsers with all of their upsides—like fast updates, robust platform support, account synchronization support, and DRM video playback—but without many of the usual annoyances. The best of both worlds.
Try it out
You can visit justthebrowser.com to run the setup script, read through the documentation, and download the configuration files. I hope this will be a useful resource for years to come.
There's only a few hours left in 2025, so I figured now is a good time to share some of the movies, shows, games, books, and podcasts I enjoyed this year. I love seeing these lists from other people, but I've never done one except for a games list in 2023.
As a quick note, this list is not restricted to media released in 2025. I'm not counting movies or shows I rewatched, but anything else is fair game. I'll also avoid spoilers.
Movies
I watched a lot of movies this year, though much of it bordered on masochism, including many old James Bond films and a DCEU marathon. Not all of it was bad, though. Also, you can follow me on Letterboxd.
The Bad Guys 2 (2025): The Bad Guys is one of my favorite Dreamworks movies, and the sequel is also a lot of fun with fantastic animation.
Shin Godzilla (2016): This is "this meeting could have been an email" as a disaster film, and it works incredibly well. Godzilla is once again attacking Japan, but before the monster can be stopped, a small group has to push through endless layers of bureaucracy. It's a much different movie than Godzilla Minus One, which I also enjoyed a lot.
Coco (2017): This was one of the few Pixar movies I never saw when it was new, and it's absolutely one of my favorites from the studio. Coco is drop-dead gorgeous, has some fantastic music, and hit me directly in the feels just like Inside Out.
Pirates of Silicon Valley (1999): This is a biographical drama film made for TNT, depicting the rise of Microsoft and Apple from the 1970s up to 1997, primarily focusing on Bill Gates and Steve Jobs. This isn't a fantastic movie, but it was interesting to me as a retrospective made before Jobs or Gates hit their peaks in public life. It also (mostly) stays away from glorifying either person or the tech industry at large, and even though Noah Wyle's performance as Steve Jobs was great, John DiMaggio as Steve Ballmer is perhaps the most perfect casting of all time. I also discussed the movie in a Tech Tales episode.
One Battle After Another (2025): It's pretty difficult to make a smart political commentary about a moment that we're still living through, so I understand if One Battle After Another doesn't land with everyone. Even putting aside the film's central theme, though, I was on the figurative edge of my seat for nearly the entire runtime. I loved the "Hark! The Herald Angels Sing" scene.
TV Shows
Pretty much every show I watched this year was either a comfort rewatch (Star Trek: Deep Space 9, my beloved) or a miniseries.
The Pitt (S1, 2025): It's Noah Wyle again! I'm not really a medical drama guy, but The Pitt is absolutely fantastic. Each episode being one hour of a single emergency department shift at a hospital was a great idea, and the pacing from slow emotional scenes to fast-moving surgeries was executed perfectly. It's another great entry in the competence porn genre (that's a SFW link) and I can't wait for season 2 in January.
John Adams (2008): A miniseries about the United States' second president probably sounds boring, but HBO did a fantastic job with it. I am late to the Paul Giamatti fan club, but am now a proud member.
Chernobyl (2019): I watched most of this in one sitting. An incredible series from start to finish, depicting a somewhat-accurate version of the Chernobyl nuclear disaster from 1986.
From the Earth to the Moon (1998): I love the film Apollo 13, and From the Earth to the Moon is essentially an expanded version that covers the rest of the Apollo program. The episode quality was much more inconsistent than I had hoped, but if you're in the mood for some space exploration and American exceptionalism, it's worth a watch. Also, it has a great opening theme.
Books
I had a goal of reading more books this year, and I... did not do that. Maybe next year.
Forever Free (Joe Haldeman): I read The Forever War last year and loved it, so I continued onward to Haldeman's sequel. It's set after a centuries-long war in deep space, with the survivors of the original human race finding themselves bored with their new home and trying to fuck around with time travel. I didn't like this one nearly as much as the first book, but it was still interesting, and the setting of the last few chapters was amusing to me as a recovering Disney Adult.
Iron Curtain: The Crushing of Eastern Europe 1944-1956 (Anne Applebaum): This took me a long time to get through, but as someone who wasn't all that familiar with eastern Europe and the inner workings of the former Soviet Union, it was both incredibly interesting and depressing.
Games
This year I sold my Xbox Series X for a PlayStation 5, while my gaming PC remains mostly reserved for simulation games, Overwatch 2, and VR titles. Here's some stuff I played.
Astro Bot (2024): I haven't really played any 3D platforming games since Super Mario Odyssey, and Astro's Playroom and Astro Bot scratched that itch. The visuals, gameplay, and music in both titles are fantastic, but Astro Bot is a more complete experience.
Wolfenstein II: The New Colossus (2017): The setting of a Nazi-occupied America might not be fictional at this point, but I still had fun in my first complete playthrough of the Wolfenstein sequel. The levels and guns are fantastic, and I loved the heavy metal-ish soundtrack by Mick Gordon and Martin Stig Andersen.
Death Stranding Director's Cut (2021): This was my first Kojima game, and outside of a few segments that were more cumbersome than suspenseful, it's a fantastic game about rebuilding a broken world while babysitting, delivering packages, and driving your truck at unsafe vertical inclines. I have the sequel in hand, but want to finish Clair Obscur: Expedition 33 first.
VRChat: It's more of a social platform than a game, and I didn't start playing it in 2025, but I'm going to put it here anyway because I make the rules. Connecting with friendly folks and hopping through cool worlds in VRChat were great experiences for me throughout 2025. The jokes about it being 'the most expensive free game' are well-earned, though—I'm eyeing an upgrade to a Galaxy XR headset when the price drops a bit.
Ratchet & Clank (2016): I have no nostalgia for the Ratchet & Clank series, but I do want to play Rift Apart eventually, so I went through the 2016 series reboot earlier this month. It's a short and sweet platforming adventure through sci-fi worlds. Speaking of the Paul Giamatti fan club, he plays Chairman Drek in some of the cutscenes.
Podcasts
If I am wearing headphones while going for a walk or cleaning my apartment, one of these shows are most likely playing.
Well There's Your Problem: A fun, unapologetically leftist, and frequently-sidetracked show about engineering disasters throughout history. The Macy's Thanksgiving Day Parade episode absolutely killed me. Hosted by Justin Roczniak, November Kelly, Liam McAnderson, and occasionally more people. (link)
If Books Could Kill: A great show about how every airport book is insane, with occasional diversions to Eric Adams, bad op-eds from The New York Times, and general discourse about political media. Hosted by Michael Hobbes and Peter Shamshiri. (link)
Smosh Reads Reddit Stories: The perfect show for when I don't want to be alone with my thoughts, but also don't have the attention span for history or political topics. Funny and sometimes insane. Hosted by Shayne Topp and other Smosh members. (link)
Hey everyone! This is a quick public service announcement for anyone using ImageShare, my web app for sharing images and videos from low-end and legacy web browsers. ImageShare is still working and not going anywhere, but you may have to access it directly on more browsers moving forward.
I have received a few reports from people unable to load ImageShare on the original Nintendo 3DS and other platforms. I believe all of these reports are due to Google Search dropping support for many old browsers, which some people used for navigating to ImageShare. I can replicate this in Citra emulating the original 3DS web browser—my New 3DS XL can still load Google—and Reddit threads confirm the same issue for browsers like Internet Explorer 5.
ImageShare still works on all the same low-end and legacy web browsers, including the browser on all Nintendo 3DS and Wii U consoles. However, you may need to access it directly by typing http://theimageshare.com in your browser's address bar. If you have a 3DS or other device that can scan QR codes, you can also scan the code on the GitHub repository's main page for quicker access.
If you use ImageShare frequently, you should bookmark it for easy access, instead of using web searches or typing in the URL each time. I have no plans to change that domain or shut off the main web server, but you can also self-host ImageShare if you want.
Back in December, I released Peek - an extension for Google Chrome and Opera that allows you to preview links before you download them. After about two months of on-off work, I'm super excited to finally release Peek 2.0.
Here is the full release notes, and I'm pretty sure this is the longest list of changes in any update I've ever made for anything:
Now allows previews to 'pop-out' into new windows
Toolbar icon now shows number of previews on the page
Updated preview interface
Supports more Google Drive links
Improved performance
Changed minimum Chrome version to 47
Fixed bug where multiple popups were rendered for some files
Changed license to MIT
You can get Peek 2.0 from the Chrome Web Store right now, and the update is in the approval process for Opera users.
The new Cupertino: a Firefox theme for modern macOS
Back in 2024, I released a Firefox theme that more closely matched the color and design of the macOS operating system, called Cupertino. Apple is about to release macOS Tahoe 26 with a significant redesign, so I went back to the metaphorical drawing board to help Firefox fit in again. The new Cupertino theme is now available, and it was a lot more work than it looks!
The original theme was somewhat simple: I just used a color picker on macOS apps like Finder and Safari, and set those colors across the theme variables that Firefox supports. The incoming Liquid Glass redesign of macOS 26 posed two problems: Firefox cannot replicate the translucency effects that Apple is now using everywhere, and also Liquid Glass does not look good. So many interface elements across the operating system are difficult to read, complex to understand, or both.
The main feature here is the toolbar with rounded corners and a drop shadow, which sort of matches the new floating button groups in apps like Finder, System Settings, and Safari. This was achieved with Firefox's support for additional backgrounds in themes: the left curve is one image, the right curve is another image, and the middle section is repeated across the remainder of the screen.
I was inspired by the old CSS trick for creating rounded boxes before it was a browser-level feature, which required a background image for each corner or side of the box. Sometimes, you can't beat the classics. Each image in this theme is in SVG format, so it looks crisp on all monitor resolutions and display scaling settings.
The background colors also don't exactly match macOS, because Firefox applies a light filter over the toolbar for themes using a background image—it's more obvious in photo-based themes. This effect can't be turned off, so I corrected the colors the best I could and updated the rest of the theme to match the modified color values. Unlike the white-on-white interface elements seen in the new Finder and other Liquid Glass applications with minimal contrast, the Firefox window frame is a light gray and the toolbar is solid white.
The Cupertino theme still supports dark mode, with colors based on Safari and Apple Music, but there's no rounded toolbar. The light filter that Firefox applies over image backgrounds looks awful with darker backgrounds.
Firefox does allow some transparency in the search bar results, main overflow menu, and other elements, but without the fancy frosted glass-like translucency. I have this set to 97% opacity in the new Cupertino theme, because higher percentages make text more difficult to read—a problem in many applications using Liquid Glass proper.
The new theme strikes a decent balance between Apple's updated design, features allowed by Firefox themes, and the visual contrast required for easy web browser usage. Hopefully, Firefox will eventually add native support for Liquid Glass-like effects, but I'm happy to use this in the meantime.
You can install the new Cupertino theme from Firefox Add-ons, and the source code is on GitHub. If you want to go back to the older theme for any reason, I've created a separate listing that is awaiting approval from Mozilla.
I released my Link Cleaner web app in 2021 as a way to quickly remove tracking parameters, search queries, and other extra fluff from web links. It was mostly intended for phones and tablets, since editing URLs with a touchscreen keyboard is especially awful, but it was also helpful on desktop browsers.
Link Cleaner is now my most popular software project, with over 44K users and 90K links cleaned just in 2025. I've wanted to give it a proper design overhaul, especially for larger screens, and the big update is now complete.
New design
If you have used Link Cleaner, you know the interface was simple but (mostly) functional. The new version is not a massive change: it's just a lot of usability improvements and a more refined design.
The home page still has the same basic layout, but the URL text box is closer to the center of the screen (more like the Google or DuckDuckGo home pages). There's a new header that I can update with different backgrounds and text—right now it has a Pride Month theme.
The navigation bar has also been moved to the top of the screen, and more closely matches the design of the recent PhotoStack update. The navigation bar (and URL field, if you are on the main page) remain pinned to the top of the screen as you scroll down. The home page also has new explanations of Link Cleaner's core features.
The Bulk Mode page has also been slightly updated, with text fields that now use most of your available screen space. There are many other small changes, like the tab icon (favicon) being more readable in dark browser themes, and improved accessibility on all popup panels.
New features
The navigation bar's History button opens the new Clean History panel, showing all the links you have cleaned recently. This is more secure and (hopefully) more useful than the previous History page, since your links are not actually saved in storage. They're gone if you close the window or switch to another page.
The Install button opens the new Install panel, which can guide you through installing Link Cleaner as a web app, adding the Shortcut to your Apple devices, and using Link Cleaner in custom scripts and automations with the custom share URL. It also includes a new bookmarklet, which you can add to your browser's bookmarks toolbar to instantly get a cleaned URL for the current page in a Link Cleaner popup window.
Link Cleaner now uses the same text field for the URL input and cleaned link output, removing the need to click the back button each time. You just paste in the text field again, or press Enter/Return on your keyboard, to clean the link again. There's still a 'Clear' button for touchscreen devices, since selecting and removing all text is more difficult without a physical keyboard.
If you have a device with a physical keyboard, the merged text field means you can now paste a link with Ctrl+V/Cmd+V, then immediately press Ctrl+C/Cmd+V to copy the cleaned link. No reaching for the mouse or tabbing around required. This update removes the experimental option for automatic clipboard copy, since it was not reliable and difficult to test, and the new keyboard accessibility is a close enough replacement.
The share and copy buttons in Link Cleaner are mostly unchanged, but the QR code option now has a 'Save to Downloads' button. If your browser supports sharing files, you can also quickly share the QR code to another installed application. The QR codes are still generated locally in your web browser, for better privacy and offline support.
Importantly, this update does not remove any functionality, except the experimental automatic clipboard copy that didn't reliably work. If you have a script, bookmarklet, Apple Shortcut, or some other automation using Link Cleaner, it should still work exactly as it always did.
Try Link Cleaner
You can use Link Cleaner by visiting linkcleaner.app in your browser. The code is still open-source on GitHub.
Back in January, I said that I was working on a security and privacy checkup for all my currently-maintained software projects. That project is now complete, though some projects will have further updates to enhance user security. Here's a summary of what I changed.
Functional changes
Link Cleaner, my web app for removing tracking parameters and other junk from URLs, no longer has a History page with previously-cleaned links. The usage of that page was very low, and its role as an always-on activity log could be a minor privacy risk if a threat actor gained physical access to the browser or device. All of Link Cleaner's functionality still runs on-device without sending links anywhere.
I also removed the public Plausible Analytics page for Nexus Tools, my installer and updater for Android SDK Platform Tools. It was a cool way to show off how many people were using Nexus Tools on which platforms, and didn't show any personally-identifiable information, but it probably doesn't need to be public.
PhotoStack Classic, the version of PhotoStack intended for old web browsers, was using an outdated version of the JZip library that had some minor security issues and has been fixed. The regular PhotoStack web app was not vulnerable to that exploit.
I'm considering other functionality changes to improve privacy and security, like updates to embedded content in the Peek extension, but there aren't any more super pressing changes that I am aware of right now. Finally, I shut down the static web hosts for two old web apps, Planr and Rockwell, since they might have privacy or security issues and (to my knowledge) no one is using them.
Privacy policies
Most of the work here was creating detailed privacy policies for each project, explaining exactly what data is collected, if any data is transmitted to me, and the options for opting out of data collection/transmission. The privacy policy for each project is under PRIVACY.md on the GitHub repository, somewhere in the interface for web apps, and in the product listing for browser extensions.
You can check out the Nexus Tools privacy policy as an example. Most of them are very short, since none of my projects collect personally-identifiable information or function as commercial products.
Staying secure
My software projects are all open-source on GitHub, and I'm doing my best to keep them as private and secure as possible while still giving me basic analytics data for focused development. I don't want your private data.
If you like my software projects, consider joining the Patreon if you haven't already, which gets you access to my monthly work logs. You can also donate through PayPal or Cash App, but I don't have a way to grant access to rewards through those options. Donations and patrons help pay for hosting costs, the Plausible Analytics subscription, domain registrations, and other costs.
A security and privacy checkup for my software projects
Update: The checkup is now complete.
Over the next few weeks, I'll be going through all my web apps, browser extensions, tools, and other software projects for a privacy and security checkup. This includes PhotoStack, Link Cleaner, Nexus Tools, ImageShare, and everything else I currently maintain. I'll be evaluating all features for possible issues and making sure everything has a clearly-stated Privacy Policy. Further updates will be shared on my personal blog and Patreon feed.
I want to make something clear right now: I don't want to collect your personal data, and I'm doing as much as I can to protect the privacy of anyone using my software projects.
Most of my software projects do not involve sensitive user data at all. All my web apps use Plausible Analytics to collect anonymized usage data, instead of Google Analytics and other popular alternatives. For use cases where private data can be handled, such as editing photos in PhotoStack, no private data ever leaves the local device. The recent ImageShare update removed the use of third-party image hosts, and user uploads are deleted after a few minutes.
Browser extensions can often become security nightmares, but my extensions are set up to use as few permissions as possible. For example, Share to Mastodon doesn't require logging in with your Mastodon server or granting permissions for the server, because it uses the server's own share dialog in a regular browser window.
I'm not a cybersecurity expert, and none of my projects have been professionally vetted for security issues. That being said, I am following best practices as I understand them, and all my projects are open-source so they can be vetted by anyone. I have some changes in mind for some apps and extensions to make the default behaviors more secure and transparent.
If you are aware of a potential issue with any of my software projects, even if it's a tiny one, please contact me or join the Discord.
Earlier today, I got a weird email from Google Search Console, the service used for submitting domains and pages to Google's search index and tracking their performance. It said that someone had been added as an owner for the subdomain test.corbin.io, which is under the corbin.io domain that I own and have registered through Google.
I didn't add anyone as a property owner, so I decided to check the test.corbin.io domain. It loaded what seemed to be a landing page for a slot gambling website in Indonesia, with the page written in Indonesian and some Chinese in the HTML comments.
I definitely didn't set this up, and I didn't even remember what test.corbin.io was originally hosting. I checked my domain registrar for that domain, Hover, and the test subdomain was set as a CNAME record redirecting to corbindavenport.github.io.
I set up test.corbin.io last year to host the rewritten version of my personal website, before it was ready to replace my main website at corbin.io. My domain was already set up to use GitHub Pages, the static web hosting service, so I just made a CNAME record at that subdomain and set it as the custom domain for the test website's repository.
Here's what I think happened. When my new website was done a few months ago, I moved it to the root domain (corbin.io) but left the test domain pointing to GitHub. Someone else set test.corbin.io as the custom directory for GitHub Pages on their repository, and since that domain was already pointing to GitHub, no setup was required on my part. I assume once I removed that custom domain from my own repository, the lock was released and GitHub allowed someone else to claim it.
I'm not sure how long ago this was set up, and I probably wouldn't have caught it if the other person didn't try to set up as a Search Console property. As far as I can tell, none of my accounts were ever compromised, and I already had two-factor authentication enabled on both GitHub and Hover. I deleted the subdomain record in Hover and the website no longer works.
Learn from my mistake: check your domains and subdomains for possible hijacking, especially if they're pointing to GitHub, and remove GitHub from any domain records you aren't actively using. I have mirrored the website's HTML code to a GitHub Gist if anyone wants to do more digging.
The new ImageShare is the best way to share images and videos from low-end and legacy devices. It works on nearly every web browser that supports file uploads, and it has additional features for the Nintendo 3DS and Wii U.
I made the first version of ImageShare in 2020, as an alternative to Nintendo’s Image Share service for the Nintendo 3DS, and I eventually added better mobile and desktop support. Trying to keep it functional for old browsers, like the one on the 3DS, has been difficult and required numerous rewrites and quick-fix API migrations. This new v3.0 update is nearly a complete rewrite, intended to keep the web app functional for the foreseeable future.
ImageShare has now outlived the Nintendo-operated service that inspired it, and I’d like to continue that winning streak. At the same time, I hope this will be a useful tool for any old devices with a functional web browser, not just game consoles.
Send images and video instantly
ImageShare allows you to send any image or video file to another device. You can visit theimageshare.com in a web browser, select a file, then just press the Upload button. The uploaded file can be downloaded on another device by scanning the provided QR code, or you can type the provided shortlink in a web browser. The file is deleted from the server after a few minutes.
The file hosting is now handled entirely by the ImageShare server, instead of using Imgur or ImgBB, like earlier versions. The ability to upload files directly to popular hosting services with permanent hosting was great, but the Nintendo 3DS and other supported platforms can’t authenticate with sites like Imgur and ImgBB anymore, and unauthenticated uploads are either rate-limited or impractical. The QR codes are also now generated by ImageShare, instead of using a third-party API.
Thanks to this new architecture, ImageShare now supports most media formats, not just images. Scanning the QR code or visiting the link on another device starts the download immediately, as long as the browser allows it, saving you the step of right-clicking or holding down on the file to start the download.
ImageShare is also built with self-hosting in mind: it’s completely open-source, and you can run it on any PC, home server, or production web server with Docker. The new version is even easier to set up, since API keys for Imgur or ImgBB aren’t needed anymore.
Nintendo 3DS and Wii U support
ImageShare is still designed to work with unmodified Nintendo 3DS and Nintendo Wii U game consoles, using their built-in web browsers. Full support for the Wii U is new in this update.
When you upload a game screenshot or other saved image from the 3DS or Wii U, the game’s title is automatically added to the image’s EXIF metadata. The device model in the metadata is also saved as ‘Nintendo 3DS’ or ‘Nintendo Wii U’, and the device make is saved as ‘Nintendo’. That data makes the images searchable by platform and game title when they are imported into most photo library apps and services. For example, after copying a few Animal Crossing: New Leaf screenshots to my iPhone, I can search “animal crossing” in the Photos app later to see all of them.
This functionality is possible because images saved on Nintendo consoles contain a partial ID for the game they originated from. That ID is stored in the file name on Wii U consoles, and on 3DS consoles, it’s in the EXIF metadata. ImageShare extracts that game ID, matches it against hax0kartik’s 3dsdb and WiiUBrew’s title database, and then saves the matching game title back to the file before the file is downloaded.
Now that Nintendo’s own media upload service for the 3DS and Wii U is dead, ImageShare is (probably) the best way to transfer images and videos from those consoles to a phone or other modern device, where they can be easily backed up and shared online. No homebrew or taking out SD cards required.
ImageShare on everything else
ImageShare works on nearly every mobile and desktop web browser. I’ve tested it across modern browsers, older versions of Safari and Firefox, KaiOS feature phones, Windows Phone 10, and several versions of Internet Explorer and Netscape. The below image shows ImageShare working perfectly on Internet Explorer 5.0 for Mac, which was released 24 years ago. You’ve heard of progressive enhancement, now get ready for regressive enhancement.
Modern desktop and mobile web browsers get the fancy responsive layout, with drop shadows, two columns on larger screens, and automatic dark mode support. This works for most browsers with CSS3 media queries support, mostly in the 2010s and later, and it can shrink down to a minimal interface used for the Nintendo 3DS and other small mobile screens.
Older web browsers get a single-column layout, and some effects like rounded corners and drop shadows might not work. This is what you’ll get on old versions of Safari, Internet Explorer, and Firefox from around the early-2000s to early-2010s.
Finally, really old web browsers like Netscape 4.x get the plain HTML layout. ImageShare uses a fun web dev trick to prevent browsers with early and incomplete CSS1 implementations from trying (and failing) to load the more complex layout.
ImageShare still doesn’t use any client-side JavaScript (except to show a loading spinner after you click the Upload button), and HTTPS is optional, so it’s fast and looks great on many devices. The minimum requirement is just file upload support in the browser. For example, ImageShare doesn’t work on some old iPhone and iPod Touch models, because mobile Safari didn’t allow file uploads until iOS 6. The QR code also won’t work on browsers that don’t support PNG images, but most of the browsers affected by that also don’t allow file uploads.
Hello, Node
The new ImageShare is a near-complete rewrite, replacing the original PHP codebase with Node.js. I have never really liked working in PHP, so when faced with the problem of having to rework the app anyway, I figured now was a good time to finally change the technical foundation.
Node’s great ecosystem of libraries made the transition easy, and it allowed me to quickly add features that had been on the to-do list for ages. ImageShare is using Express and Multer to serve the web pages (which are dynamically generated) and static resources, as well as handling image uploads and downloads. The QR codes are created with the excellent node-qrcode library, and exifreader is used for checking image metadata. The only core functionality that isn’t handled in the server is writing game titles to image EXIF metadata. For that, the server spawns an ExifTool process.
ImageShare was already a multi-container Docker Compose application, with the app running in one container, Certbot from Let’s Encrypt in another container for generating and renewing the SSL certificate, and Nginx in another container for the reverse proxy. With this update, the PHP server was swapped for a Node server, and the rest remained relatively untouched. Hooray for modularity!
Try it out
You can use the new ImageShare by visiting theimageshare.com in your web browser, and the source code is available on GitHub. You can also bookmark it for easy access in the future. I’m hoping this will remain a valuable and useful service for years to come.
Earlier this year, I released Alt Text Creator, a browser extension that can generate alternative text for images by right-clicking them, using OpenAI's GPT-4 with Vision model. The new v1.2 update is now rolling out, with support for OpenAI's newer AI models and a new custom server option.
Alt Text Creator can now use OpenAI's latest GPT-4o Mini or GPT-4o AI models for processing images, which are faster and cheaper than the original GPT-4 with Vision model that the extension previously used (and will soon be deprecated by OpenAI). You should be able to generate alt text for several images with less than $0.01 in API billing. Alt Text Creator still uses an API key provided by the user, and uses the low resolution option, so it runs at the lowest possible cost with the user's own API billing.
This update also introduces the ability to use a custom server instead of OpenAI. The LM Studio desktop application now supports downloading AI models with vision abilities to run locally, and can enable a web server to interact with the AI model using an OpenAI-like API. Alt Text Creator can now connect to that server (and theoretically other similar API limitations), allowing you to create alt text entirely on-device without paying OpenAI for API access.
The feature is a bit complicated to set up, is slower than OpenAI's API (unless you have an incredibly powerful PC), and requires leaving LM Studio open, so I don't expect many people will use this option for now. I primarily tested it with the Llava 1.5 7B model on a 16GB M1 Mac Mini, and it was about half the speed of an OpenAI request (8 vs 4 seconds for one example) while having generally lower-quality results.
You can download Alt Text Creator for Chrome and Firefox, and the source code is on GitHub. I still want to look into support for other AI models, like Google's Gemini, and the option for the user to change the prompt, but I wanted to get these changes out soon before GPT-4 Vision was deprecated.
Today, my podcast Tech Tales is three years old. I've had a lot of fun making the show this past year, and it has continued to grow and improve.
There were eight Tech Tales episodes this past year, coming in at just under eight hours of runtime. There are now 55 episodes in total, just over 17,000 plays on audio platforms, and 230 subscribers on YouTube. That's more than double the YouTube subscribers than the show had a year ago, and almost double the amount of audio plays.
There was a pretty good mix of episodes this year, diving into the history of the Apple IIGS computer, Duke Nukem Forever, the CyanogenMod custom ROM, the Intellivision Amico console, Google AMP, and Apple's transition to Intel processors. There were also two Movie Club episodes to give me a break from history research: one for Tron and another for its sequel, Tron: Legacy. That last one now holds the record for longest Tech Tales episode at 1 hour and 21 minutes.
Tech Tales is still growing without any paid advertising, with only word of mouth, algorithmic recommendations through YouTube, and my own efforts on social media (primarily Mastodon). There were a few sudden boosts, like YouTube's algorithm pushing the Intellivision Amico episode to hundreds more people than usual, and a few episodes were shared on tech forums and sites by listeners.
The big behind-the-scenes shift this year was moving the production from Audacity to Apple Logic Pro, which has made it much easier for me to edit episodes and add chapter markers. The episodes sound better than ever, and the YouTube version now has a fun idle animation instead of a static image.
I also started my new newsletter and blog, The Spacebar, a few months after Tech Tales' second anniversary. I adapted some older Tech Tales episodes as new articles for The Spacebar, such as the story of the Eee PC and VisiCalc. I plan to do more of that in the future, and maybe more cross-promotion where it makes sense.
I don't have any grand plans for Tech Tales for the next year ahead, other than continuing to work on it when I have the time and interesting topics to discuss. The editing process is a lot less frustrating now, which helps!
In no particular order, I would like to thank Joe Fedewa, Katie Janzen, Lucas Bastos, Evan Hirsh, Cody Toombs, Zachary Wander, and Adam Conway for joining as guests this past year. I also want to thank everyone who has ever listened to the show, and especially the ones who have reached out to me.
You can listen to Tech Tales for free on YouTube or your favorite podcast app. Onward to year four!
I just finished making my new personal site, powered by the Eleventy static site generator, a custom template, and GitHub Actions. It’s fast, easy for me to maintain, and doesn’t cost me anything to host. Here’s how I made it.
My previous personal site was a static HTML site hosted on GitHub Pages, which I initially made in 2018 to replace my Blogger-based site (that’s a throwback!). I made the layout and site theme myself instead of using a heavier web framework, and I moved the blog section to Tumblr with a new blog.corbin.io domain. I later tried switching to WordPress managed hosting, but that costs more money, and I wasn’t a fan of most modern WordPress themes and how resource-heavy they were. WordPress is great for larger sites, but it was overkill for my simple personal site.
My ideal setup here would be a site that is easy to edit, gives me full control over the template, and (ideally) doesn’t require paid hosting. My first idea was moving the content to Markdown files, and then using GitHub’s Jekyll integration to generate a static site. Creating a Jekyll theme turned out to be a bit clunkier than I wanted, though, so I started looking at other static site generators.
I eventually discovered Eleventy, which doesn’t have the extensive feature set of Jekyll or some other static site generators, but it looked perfect for my project. It can generate sites from Markdown (or other data formats) using simple HTML templates, and I could keep using free GitHub Pages hosting. It’s also possible to create reusable widget components with contents, which can be filled in by the main Eleventy generation script. The official getting started guide was helpful.
The most clear way for me to talk about my process is just go through each of the files in the GitHub repository, so that’s what I’ll do!
The main pages
I wrote all the pages for the site, like the About page, in Markdown format. It’s mostly the same syntax that as GitHub, but with an added table at the top to define the page title, permalink, and template layout. This is a huge upgrade over my previous site, where I was writing the <head> and other shared elements in each page and tried to keep them synchronized.
Eleventy converts Markdown format to the equivalent standard HTML code when the site is generated. For example, “# Hello” becomes “<h1>Hello</h1>”. That makes styling the site with CSS in the layout template easy, and it’s great for accessibility. You can also put custom HTML content in the Markdown file and it will render as expected.
It’s much easier for me to make quick edits to Markdown files than raw HTML. I can even do it from the GitHub app on my phone.
The special pages
GitHub Pages allows you to create a custom 404 page, which appears to still work with custom site generators as long as the resulting file is called “404.md” or “404.html” in the main directory. I made one and set the permalink to “404.html” and it works as expected.
My earlier site had a few redirecting pages, mostly for blog posts that used to be on my main domain but were later moved to my blog. Those had to be in specific locations to work with my earlier site, cluttering up the site structure, but Eleventy gave me a much cleaner solution. I created a “redirects” folder for all of them, set the permalinks to the proper locations, and added an HTML redirect element to the Markdown file.
For example, I originally had a blog post at corbin.io/wikipedia-search-11. When I moved that blog post to my Tumblr blog, I had to create a redirect HTML file at that specific location (root/wikipedia-search-11/index.html), which then cluttered up the root directory of my code repository. With Eleventy, I can place the redirects anywhere I want and call the files anything I want. I made a page in my “redirects” directory with the permalink “wikipedia-search-11/index.html” and it worked exactly as expected.
The Node packages
Eleventy uses Node.js, so there’s a package.json file in the root directory that tells Node what packages are needed. Right now, my only dependencies are RSS parser (more on that later) and Eleventy. Running the setup command “npm install” installs those packages.
The layout theme
The layout theme is stored at _includes/layout.njk, though the file can be called anything. It contains everything around the main content, including the general HTML page structure, any links to JavaScript or CSS files, and so on.
My custom template is a minimalist one-column layout and some basic CSS. I went back and forth on possible site designs, including some more 90s-inspired layouts, but I ended up staying close to the old design. Some of the changes include a new navigation bar that changes size based on screen size (no hamburger menu!) and removing Google Fonts.
I also wanted to see if I could make my site render properly on older web browsers, because that’s a fun challenge. However, the Let’s Encrypt SSL certificate that GitHub sets up for my site uses the ISRG Root X1 root certificate, which isn’t available on most platforms and browsers released before the mid-2010s. Legacy web browsers can’t load the site in the first place, so there’s not much of a point in doing that testing. I did add some compatibility tweaks for earlier WebKit and Firefox browsers, though, and the site should work in Internet Explorer 8 and above.
The <head> section contains code for an Open Graph card, so linking any page on platforms like Slack, Facebook, Discord, and iMessage will create a rich preview. The image is set to my current Gravatar image, so if I decide to change my profile picture, it is automatically applied to my personal site at the same time as everything else connected to my Gravatar.
I also added link tags in the <head> for several RSS feeds, including the feed for my personal blog (which is on a Tumblr custom domain) and the RSS for my Tech Tales podcast. If someone puts my website into an RSS reader like Feedly or Inoreader, or they have a browser extension that shows any available RSS feeds, those feeds appear as subscription options.
Finally, I added verification code for the Mastodon social network as a hidden link at the bottom of the <body> section. That allows my site to appear as a verified link on my Mastodon profile.
The Eleventy script
The .eleventy.js file is where the magic happens: it’s the Node script that generates the site with all the custom configuration options. I added “passthroughs” for the media folder, robots.txt file, favicon file, and other resources that need to be copied to the generated site for everything to work.
This is also where I defined shortcodes that I use in some pages, which are reusable components that Eleventy can drop in during the generation process. For example, I have download buttons for browser extensions on my software page, and I didn’t want to manually define the same image and link structure over a dozen times. I defined a “downloadBtn” shortcode with arguments for the platform and URL, which generates a download link button with that data. I also made a shortcode for the HTML redirect for my redirect pages, and other functions I’m using on other pages.
I also created a “letterboxd” shortcode for displaying my recent Letterboxd reviews on my about page. You can use any Node code in this script, so I’m using the rss-parser Node library to download the RSS feed from my Letterboxd profile and parse it in HTML format with links. My custom “flickr” shortcode does the same for my recent Flickr images.
The GitHub Action
The final piece is the GitHub Action for building and deploying the website. It runs after each new commit and automatically once a day (so data used in the Letterboxd and Flickr shortcodes is fresh). The script checks out the repository code, installs all the NPM dependencies, runs Eleventy to generate the site, and then uploads the package to GitHub Pages.
With this integration, I can make changes to my site from anywhere, and then a minute or two later the changes are live on the site. The code repository isn’t even cluttered with the generated HTML files, since I added the “_site/” output directory to the gitignore file.
The end
I’m pretty happy with my new personal site. It’s fast to load, easy for me to edit from anywhere, and completely free to host. Since all the core content is server-side generated, it even works in text-based browsers like Lynx.
If you want to set up something similar, feel free to fork my site’s repository on GitHub.
How I added cross-platform chapters to the Tech Tales Podcast
I currently produce and edit the Tech Tales Podcast, and last month, I decided to finally try adding chapter markers to episodes. It turns out that chapter markers in podcasts is pretty complicated, especially if you want listeners to have the best possible experience across YouTube and popular podcast apps. I figured my process was interesting enough for a short blog post, and the steps explained here might help other people.
Audio podcasts are usually distributed as MP3 or MP4 audio files. The show name, episode title, artwork, description, and other data can be encoded in the file using ID3 metadata, though most podcast apps and services now take that data from the show's RSS feed or another source.
Chapter markers can also be encoded in the file using ID3 metadata, with each chapter having a title and timestamp. When Apple added support for podcasts to iTunes and iPod players in 2005, it included support for "enhanced podcasts," which could include per-chapter artwork and web links. Apple still supports chapter-specific artwork in Apple Podcasts, but the links feature seems to have vanished at some point, and per-chapter artwork doesn't seem to be well-supported outside of Apple's software.
I currently edit Tech Tales episodes with Apple's Logic Pro, and I use the markers feature to set each chapter. Audacity has a similar "labels" feature.
Logic Pro only seems to save the markers as chapter metadata when exporting as a PCM/WAV file, not when I select MP3. It's also a bit complicated to export as a mono channel MP3, especially if the project tracks have stereo channels.
MP3 Chapter Data
My solution for the audio version of the podcast is to export as WAV from Logic Pro, then use the free and open-source FFMPEG tool to create a mono-channel 128kbps MP3 file with the chapter data intact.
The extra step is annoying, but it does give me an MP3 file with the exact desired settings and the chapter data encoded in the file. When I re-encoded an earlier episode with those settings and uploaded it, the chapter markers showed up as expected in Apple Podcasts and Pocket Casts.
There were still two problems. First, there's a video version I upload to the Tech Tales YouTube channel, and that needs chapter markers. Second, I discovered Spotify wasn't showing the chapter markers from the MP3 file, even when other players did. It turned out both problems had the same solution.
YouTube and Spotify Support
YouTube supports video chapters, which have to be added as time stamps and titles somewhere in the video description. YouTube gives you some wiggle room with the formatting: the timestamps can be anywhere in the description, and the hour isn't necessary for videos under one hour (e.g. you can have 18:30 instead of 00:18:30). I've also seen different styles for separating the timestamp from the chapter title. For example, a GamersNexus video about Intel Arc Drivers uses a dash surrounded by spaces, while other videos just put a single space between the timestamp and the title.
Spotify supports a few different methods of adding chapters to podcast episodes, but none of them are MP3 encoding, which explains why the chapters weren't showing up. The easiest method, and the only one accessible to me while using SoundCloud as a host, is adding timestamps to the episode description. The format is similar to YouTube, but with a few additional requirements. There must be at least three chapters, and the first one must start at zero seconds (00:00).
Logic Pro can't export markers to a text file, and I didn't really want to type them out each time I published an episode. The best solution ended up involving two different tools. First, I use FFPROBE (a media analysis tool usually included with FFMPEG) to read chapter data from that original WAV file and convert it to JSON format.
That gives me a text file with all the chapter data, including detailed start and end times and the titles, in JSON format. That's not the correct format for YouTube and Spotify, but it can be easily read by other tools. As far as I can tell, FFPROBE on its own can't create the format I need.
The next step is using JQ to write the chapters with time stamps to a text file, using the data provided in the JSON file. I actually used Microsoft Copilot to help me write the command, because I'm not too familiar with JQ's options.
This creates a text file called chapters.txt with the time stamps and titles in the exact required format. Success!
When I copy and paste that into the audio episode description, the chapters appear as expected in the Spotify desktop and mobile applications, and pasting the text into the YouTube video description adds the correct chapter markers to the video player.
You can see it working on the latest Tech Tales episode on Spotify and YouTube. I didn't expect chapters support to be so annoying, but I'm glad to have a mostly-automated solution.
Doing It Yourself
I created a bash script file to run all three commands at once on my Mac, and then save the final audio MP3 and chapters text file to the Desktop. You can see it on GitHub.
You need FFMPEG/FFPROBE and JQ installed for the commands to work. Since I'm on a Mac, I installed the Homebrew package manager, then ran the below command to install both packages.
brew install jq ffmpeg
I hope this helps anyone else having similar issues with podcast chapters!
Shutting down the Wii Shop Channel Music browser extension
I released a browser extension in 2020 that played the Wii Shop Channel music in the background when you visited Amazon, Best Buy, and other online stores. I released a major update in 2022, and I've been working on a rewritten version, but I have now decided to discontinue the browser extension.
The Wii Shop browser extension needed to be significantly rewritten to comply with Google's Manifest V3 extension policies, which will go into effect in a few months. On top of that, Firefox has not implemented the same changes, so the extension would need a much more complex codebase to handle both web browsers.
More importantly, Nintendo has been increasingly litigious against unauthorized use of its intellectual property. I believe the browser extension's use of Nintendo's images and music falls under fair use, but I don't have lawyer money to defend that, and I'm no longer comfortable with one of my side projects being a potential target for Nintendo (potentially taking out my other work as collateral damage).
The Wii Shop Channel Music browser extension is now discontinued, and I have deleted the GitHub repository containing the code. I am aware there are forks and other mirrors of the project online, but I will not be working on them. The browser extensions are still available, and they will soon be updated to turn off all functionality and include a link to this blog post.
The list of shopping sites used by the extension will remain available, and nothing is changing with my ImageShare web app or other projects. I had fun working on it, and I especially enjoyed the occasional reviews from users saying it was the greatest invention of all time, but I think now is a great time to say farewell.
"But a thing isn't beautiful because it lasts." - Vision
Corbin Davenport @corbindavenport - Tumblr Blog | Tumgag