Atola recently released MultiDrive, a freeware drive utility for 64-bit versions of Windows 10/11 & 2019/2022/2025.
Pros:
Cons:
❧ 2025-08-07
DVD rips often include VobSub (dvdsub) subtitles, image-based (bitmap) tracks1 that aren't supported in MP4 containers. Rather than extracting and OCRing (which can be slow and error-prone), burn them directly into the MP4 with ffmpeg:
Identify the subtitle stream:
Use ffprobe
to confirm that the MKV contains VobSub (dvd_subtitle
) subtitles:
ffprobe -v error -select_streams s -show_entries stream=index,codec_name:stream_tags=language -of csv=p=0 foo.mkv
3,dvd_subtitle,eng
Stream 3 is dvd_subtitle (VobSub), in English.
Convert & burn-in with ffmpeg:
This command burns in the bitmap subtitles, retains all audio, preserves chapters, and encodes the video using Apple's hardware-accelerated hevc_videotoolbox
:
ffmpeg -i foo.mkv \
-filter_complex "[0:v][0:s:0]overlay,format=nv12[v]" \
-map "[v]" \
-map 0:a \
-map_chapters 0 \
-c:v hevc_videotoolbox -b:v 6000k -tag:v hvc1 \
-c:a copy \
-movflags +faststart \
foo.mp4
Flag exegesis
-filter_complex "[0:v][0:s:0]overlay,format=nv12[v]"
defines a filtergraph to burn in subtitles and prepare the video for encoding:
[0:v]
selects the video stream from input 0.
[0:s:0]
selects the first subtitle stream from input 0.
overlay
burns the subtitle onto the video frame-by-frame.
format=nv12
sets a pixel format compatible with hardware encoders like videotoolbox
.
[v]
names the final video stream for later mapping.
-map "[v]"
maps the filtered (burned-in subtitle) video stream ([v]
) to the output.
-map 0:a
includes all audio streams from input 0.
-map_chapters 0
preserves chapter metadata from the source MKV.
-c:v hevc_videotoolbox
uses Apple silicon's hardware-accelerated HEVC (H.265) encoder.
-b:v 6000k
sets bitrate to match 480p DVD quality, close to typical on-disc MPEG-2 rates.
-tag:v hvc1
ensures compatibility with Apple players (QuickTime, Safari, iOS) by setting the correct codec identifier.
-c:a copy
copies audio tracks without re-encoding.
-movflags +faststart
moves metadata to the beginning of the file for faster playback or streaming.
Footnote
Blu-ray subtitles use PGS, an image-based format like VobSub that's also best burned in for MP4 compatibility and to skip OCR. ↩
❧ 2025-08-06
Restores "Recent Documents" to the MacDown Dock icon in Sequoia and drops the Rosetta 2 dependency (macOS 27 will be the last to fully support it). Install Xcode and brew then run:
#!/bin/bash
set -euo pipefail
echo
"Installing dependencies..."
brew install ruby@3.2
# Add Ruby and gem binaries to PATH (avoids duplicate lines in ~/.zshrc)
echo
"Configuring Ruby path..."
LINE='export PATH="/opt/homebrew/opt/ruby@3.2/bin:/opt/homebrew/lib/ruby/gems/3.2.0/bin:$PATH"'
grep -Fxq "$LINE" ~/.zshrc || echo "$LINE" >> ~/.zshrc
export PATH="/opt/homebrew/opt/ruby@3.2/bin:/opt/homebrew/lib/ruby/gems/3.2.0/bin:$PATH"
# Uninstall any outdated Bundler versions
echo
"Cleaning bundler..."
[ -d /opt/homebrew/lib/ruby/gems/3.2.0 ] && gem uninstall -aIx bundler || true
echo
"Installing bundler and CocoaPods..."
gem install bundler cocoapods
echo
"Cloning MacDown..."
git clone --recurse-submodules https://github.com/MacDownApp/macdown
cd macdown
# The next 4 commands are only necessary if you want the last official pre-release version, 0.8.0d71 (1079)
# rather than the default 0.8.0d32 (1111) version:
git checkout v0.8.0d71
git submodule update --init --recursive
# Work around broken Slovak localization file in v0.8.0d71
echo
"Replacing broken Slovak localization file..."
echo '"DUMMY_KEY" = "DUMMY_VALUE";' > MacDown/Localization/sk.lproj/Localizable.strings
echo
"Removing outdated Gemfile.lock..."
rm -f Gemfile.lock
echo
"Installing Ruby dependencies..."
bundle install
echo
"Installing CocoaPods dependencies..."
ruby -e 'require "logger"; exec "pod", *ARGV' install
echo
"Building PEG Markdown parser..."
make -C Dependency/peg-markdown-highlight -j$(sysctl -n hw.ncpu)
echo
"Opening Xcode..."
open MacDown.xcworkspace
cat <<EOF
Setup complete.
When Xcode opens, press Cmd+B to build; find MacDown.app via
Product > Show Build Folder in Finder > Products/Debug
EOF
Notes
Inspired and informed by Daniil-Gusev's guide.
Tested on a clean macOS 15.6 Sequoia install with Xcode 16.4.
If copied to another Mac, "'MacDown.app' is damaged and can’t be opened. You should move it to the Trash." may appear on first launch; resolve via xattr -rc /Applications/MacDown.app
.
See also:
❧ 2025-08-06
stat foo.sparsebundle
..."Aug 2 07:53:48 2025" "Feb 23 09:09:25 2022" "Aug 2 07:53:10 2025" "May 7 08:30:24 2014"...
Access (atime
): Last time file was read (not always updated on APFS or recent macOS versions).
Modify (mtime
): Last time file content was modified. This is what "Date Modified" in Finder usually shows.
Change (ctime
): Last time file metadata changed (e.g., permissions, ownership, even renaming the file).
Birth (btime
): File creation date — what Finder calls "Created".
❧ 2025-08-06
Mail in macOS has long suffered from a bug that can generate thousands of near-duplicate Gmail drafts (the simplest workaround is switching draft storage from server to local).
Selecting more than 50 drafts in the Gmail web interface via "Select all x messages in Drafts" disables the "Discard drafts" option, making large-scale deletion tedious.
A faster alternative is using Google Apps Script. While script executions are limited to 6 minutes, the following API-based method can delete thousands of drafts in seconds:
Go to https://script.google.com → New project
Paste and save the following script:
function deleteAllDrafts_FinalPaginated() {
try {
let allMessageIds = [];
let pageToken;
let pageCount = 0;
// 1. Loop through all pages of drafts to get every ID.
do {
const response = Gmail.Users.Drafts.list('me', {
maxResults: 500, // Fetch up to 500 per page for speed
pageToken: pageToken
});
if (response.drafts && response.drafts.length > 0) {
const messageIdsOnPage = response.drafts.map(draft => draft.message.id);
allMessageIds = allMessageIds.concat(messageIdsOnPage);
pageCount++;
}
// Get the token for the next page. If there isn't one, the loop will end.
pageToken = response.nextPageToken;
} while (pageToken);
const totalDrafts = allMessageIds.length;
if (totalDrafts === 0) {
Logger.log("No drafts to delete.");
return;
}
Logger.log("Found " + totalDrafts + " drafts across " + pageCount + " page(s). Processing in batches...");
// 2. Process the complete list of IDs in chunks.
const batchSize = 100;
for (let i = 0; i < totalDrafts; i += batchSize) {
const chunk = allMessageIds.slice(i, i + batchSize);
const request = { ids: chunk };
Gmail.Users.Messages.batchDelete(request, 'me');
Logger.log("Deleted batch: " + (i + 1) + " through " + Math.min(i + batchSize, totalDrafts));
}
Logger.log("Successfully initiated deletion of all " + totalDrafts + " drafts.");
} catch (e) {
Logger.log("Error deleting drafts: " + e.name + " - " + e.message);
}
}
In the left-hand menu, click + next to Services
Select Gmail API → Add
Click Run
During testing, used this script to quickly generate 105 drafts:
function createTestDrafts() {
for (var i = 1; i <= 105; i++) {
var subject = "Test Draft " + i;
var body = "This is test draft number " + i + ".\nGenerated for batch deletion testing.";
var recipient = Session.getActiveUser().getEmail();
GmailApp.createDraft(recipient, subject, body);
}
Logger.log("105 test drafts created.");
}
❧ 2025-08-06
Title | Trigger | Price | Size | Notes |
AutoBlink 2.1.1 | time/camera | $9.99 (3-day free trial) | 2MB | App Privacy: "Data Not Collected" |
Blinks 1.7 | time | $4.99 | 2.5MB | App Privacy: "Data Not Collected" |
SightKick 1.0.64 | time/camera | free | 3.7MB | "Data Not Linked to You: Health & Fitness, Usage Data, Identifiers, Diagnostics" |
eyeREST 0.2.0 | camera | free | 25.5MB | "Data Not Linked to You: Location, Usage Data, Identifiers, Diagnostics" |
Eyeblink 3.7.4 | time/camera | free | 27.8MB | Windows version also available |
ScreenBlink 1.0.0 | time/camera | open source | 390.7MB | Windows version also available |
❧ 2025-08-03
The Links page, fallow since 2006, has been resurrected as a stream of periodic headlines. Not enough to justify an RSS feed, but an occasional scroll may surface something of interest.
This Python script make posting fairly frictionless while allowing for editing of existing entries:
❧ 2025-07-30
OrbStack - "Say goodbye to slow, clunky containers and VMs"
Apple Container - "A tool for creating and running Linux containers using lightweight virtual machines on a Mac. It is written in Swift, and optimized for Apple silicon."
❧ 2025-07-26
Apple's serial number lookup page was down today, first with a looping GIF saying "We'll be back. We're busy updating our support tools and will be back soon." in 19 different languages and later with a page simply stating "We are unable to complete your request at this time."
Needing to identify a Mac but unwilling to use a third-party web service, retrieved the serial number via dmidecode -s system-serial-number
in GParted Live then searched OpenCore's modelinfo_autogen.h for the last 3 characters (8QR), which corresponded to "MacBook (13-inch, Aluminum, Late 2008)".
While the model identifier can be obtained via dmidecode -s system-product-name
(in this case "MacBook5,1" which Mactracker also reports as "MacBook (13-inch, Aluminum, Late 2008)"), some identifiers like "MacBook5,2" correspond to multiple models ("MacBook (13-inch, Early 2009)" and "MacBook (13-inch, Mid 2009)").
Note that Apple replaced structured serial numbers with randomized ones in 2021:
❧ 2025-07-12
Searching for a Brother laser printer on OfficeDepot.com in Safari while not signed in, the HL-L2405W was priced at $134.99 on iOS and $148.49 on macOS, a $13.50 difference at the same time and store location.
❧ 2025-07-08