Show HN: Recut automatically removes silence from videos – built with Tauri (getrecut.com)
Some back story: Recut is a tool I built to speed up my screencast editing workflow. It's like a lightweight single-purpose video editor. It chops out the pauses, with some knobs to tweak how closely it cuts and what it leaves in, and lets you get a live preview of what it'll look and sound like with the cuts applied. It can then export to a handful of other editors, nondestructively, so that you can use the full capabilities of a "real" video editor.
It was originally a native Mac app written in Swift, and people kept asking for a Windows version. I had learned Swift and macOS development to build it originally. So as a solo developer, I had some choices to make. Keep it Mac-only? Learn another whole language + UI framework, rebuild the app, and maintain two codebases? Rebuild the app with a cross-platform toolkit?
I'd had experience with Qt and C++ in years past, but I honestly didn't love the idea of getting back into C++ and dealing with the inevitable hard-to-debug segfaults. I'd had more recent experience as a web developer, but I was worried about performance bottlenecks. I actually started down the path of building Recut in Electron and Rust (using NAPI-RS for bindings) and it looked promising, but I was still worried about the bloat of Electron.
A few months in, I took a closer look at Tauri, and ported the whole app from Electron in a week or so. Most of the heavy lifting was already in Rust, and the UI stuff pretty much "just worked". The biggest change was the bindings between JS and Rust.
Working with Tauri has been nice. I especially like their "State" system, which gives you an easy way to keep app-wide state on the Rust side, and inject specific parts of it into functions as-needed. I also really like how easy it is to write a Rust function and expose it to JS. The process model feels a lot easier to work with compared to Electron's split between renderer and main and preload, where you have to pay the cost of passing messages between them lest you ruin the security. Tauri's message-passing has a decent amount of overhead too, but I dealt with that by avoiding sending large amounts of data between JS <-> Rust and it's been fine.
The Tauri folks on Discord were a big help too (shout out to Fabian for the help when I ran into weird edge cases). I think Tauri has a bright future! Definitely worth a look if you know web tech and want to make cross-platform apps.
124 comments
[ 2.1 ms ] story [ 202 ms ] threadhttps://imgur.com/43J7UYS, for instance?
Here's a video I did recently using a whole bunch of them (https://www.youtube.com/watch?v=pTDxbmQxS_0&t=25s)
I wonder if there's a way to change the colors or put an effect on the intermediary frames to add a pop or a flash of color to cover over the oddities?
I know for certain that there are still performance gains to be had, but I’m also confident that they’re 100% in my control - Tauri and the WebView aren’t the bottleneck. That was one of my big fears with Electron – what if something is slow as molasses and it’s just stuck that way? I haven’t run into a wall like that with Tauri yet and at this point I don’t expect I will.
I’m using Svelte and Tailwind (not Tailwind UI) so the UI is custom, plus or minus some of Tailwind’s defaults.
Did you notice any diff in UI speed with view being in JS/HTML/CSS? Response time seems nice in your video so I'm guessing negligible?
The big thing is to avoid blocking the UI thread, so if you’re calling into a Rust function that could take more than a couple milliseconds, marking that Rust function (aka Tauri command) as async will run it in a background thread and the UI won’t hiccup.
However, youtube premium might be the solution if you want to support your favorites channels without ads.
[0]https://addons.mozilla.org/en-US/firefox/addon/sponsorblock/
HN had some good discussions last year with alternatives: https://news.ycombinator.com/item?id=25641205
Second thought: Is anyone else really annoyed by the constant cuts in videos these days? I find it distracting at times and completely jarring in others. I've never made a video for consumption, so I could imagine there are a lot of "re-takes" + cutting out of "umms", but I just find it a bit sad that everything has to be SO clean-cut these days.
Much of YouTube is dealing with people who leave your video after a minute or two, so shorter is generally better.
I very much appreciate people who put the time into getting rid of the superfluous in their videos. One of my highest performing videos is a 26 second "how to" video, the majority of comments are "Thank you for not making this a 5 minute videos like the others on this topic". (Removing the riving knife from a DeWalt table saw, FYI).
I recently experimented going entirely the other way, probably went too much so. Can I teach using the Python Typer (CLI argument parsing) library in 60 seconds? Feedback from friends is "Man, that's DENSE!" https://youtu.be/1iO7wqnC7qw
Personally I think of the silence as a heuristic - it’s the gap between re-takes, so if I cut at those points and then delete the bad takes, it saves a ton of time.
This makes me think an interesting workflow to support might be something like, set the settings tight to get all the cuts, then delete the bad takes, then bring the pauses back.
If you can't give a 30-second spiel in one cut, then you keep trying until you do. Alternatively, you splice in some other graphic or video to hide when a cut happens.
In the beginning I remember it being maddeningly hard to even get 10 seconds out without messing it up. But then also, there’s a technique and a skill to getting the cuts to sound natural.
I’ve seen plenty of YouTubers who cut after every sentence and make it sound & look natural, but plenty more who cut the same amount and it looks jarring. Keeping your head in the same spot helps. Trying to speak one full thought at a time helps too.
The worst is when you get on a roll, get 30 seconds into your roll, and then completely lose it and can’t remember where to “roll back” to.
In video editing you mimic this by cutting away to other angles, or to illustrative shots. Right around the end of the first sentence I cut to a longer "two-shot" showing us talking. At "to get to this point" I cut to a head-and-shoulders shot of you nodding in agreement (a "noddy shot", done after my piece to camera, getting you to look at the right height to match my eyeline). On "you're looking away" I cut back to me, and then a shot of my PC on the bench with some editing software open (bonus points for having it showing an earlier shot from this). On "and your gaze", it's back to me.
What you were actually looking at was cutting back and forth wildly, showing you something different every five to ten seconds, but somehow you didn't even see it move.
I agree it's jarring but I understand why it often happens: it's easier and faster to fix a vocal mistake by backing up just a sentence or two and then re-record from there. So it's not always just removing the pauses; he/she actually fixed a speech mistake in that sentence and had to splice it in.
The alternative to avoid jarring cuts is to record longer takes of reading paragraph-length word counts without a mistake. This is much more difficult and time-consuming. So if you're trying to speak 10 good sentences and you flub sentence #10, you have to start all over at sentence #1 to maintain one continuous take. Otherwise, you'd have a jarring cut between sentence #9 and #10. E.g. you can see the bloopers outtakes at the end of each Technology Connections video to see that even reading from a script without mistakes is not easy.
But again, like longer reads, it takes more time/work. So a lot of channels just leave the raw jump cuts.
If there are any pauses I quickly lose interest and go on doing something else and forgetting I even started watching something.
It's not "clean-cut" though. Jump cuts in pieces to camera look absolutely shite.
If you want to cut a bit out for pacing or to remove an "uhm uh <cough> so uh" then you cut away to something else. Maybe a close-up of what you're talking about, or to another camera angle.
Just chopping a bit out so you hop about the screen looks amateurish as all hell.
Swift leans real hard into verbose method names, just like Objective C did, and Rust is pretty much the exact opposite there. When I was writing more Swift I got used to it, and actually started to like it. And now that I'm in Rust a lot, I like the brevity.
I think Rust nudges (forces?) me to write code that's architecturally better, with fewer interdependecies. It was hard to get used to though. In the beginning I kept trying to make structs that started threads, where the thread called methods on the struct, and that was just a recipe for big pain.
Swift, on the other hand, especially with the way the macOS and iOS frameworks are designed, relies a lot on MVC, delegates, and mutability, which gets hard to keep track of.
(I say this as someone who likes verbosity)
I was thinking more about the long method names which definitely do feel like they're carried over from ObjC. And then, a lot of those names are really more from the commonly-used frameworks than the language itself, so maybe it's not fair to say that "Swift" has those long names, but it does feel like the 99% use case for Swift is using those frameworks.
I think I agree that Swift felt like it needed less code to do a thing than ObjC would have, in a lot of cases.
My only idea so far was: some sort of app that generates very quiet noise so that it won't power save?
As a DaVinci Resolve user I'm amazed at how good the Smooth Cut transition is at hiding cuts if the head moved very little during the cut portion of the video. It might be worth exploring more and seeing if it would make sense as an optional flag.
I haven't played with Smooth Cut, I'll have to check that out. It sounds handy! Might be something I could just "turn on" in the XML file too, I'm not sure.
So, after installing the trial, I see that the app is dynamically linked to libav libraries. Which, for distribution, can only be licensed under LGPL or GPL v2.1 or 3, depending on configuration. This requires at the least that the libav source code used be made available. And if libav was compiled as GPL, then Recut would have to be GPL too. But I can't find any licensing info at the website or in the installer or the installed files.
It's using libav as you mention, and it's an LGPL build of libav.
Unfortunately, that purpose happens to be something that absolutely drives me up the wall. Few things cause me to close a video and outright block its creator faster or more vigorously than cutting out pauses between sentences and phrases. It's great that your demo video recognizes that to be a problem, but even after accounting for it it's still jarring - and let's face it, just about zero users of your software are gonna account for it.
What happened to the good old days of doing multiple takes and rehearsing?
In any case, nice work on it, and I hope your customers use this power responsibly and unnoticeably :)
How well does that work on a live presentation before an audience, do you think? Say, a preacher delivering a Sunday morning sermon? PyGoSwiftCon 2023 tech presentation? "Here's last Saturday's video, can you post that to $WEBSITE?" One does not always have the luxury of a retake.
In any case, I said "and rehearsing"; people can and do rehearse live presentations and sermons and other speeches. That's in fact a very common thing: write out what you're going to say (or pay someone to write it for you), rehearse it in front of friends or family or pets or your mirror, possibly even memorize it.
Doesn't seem any worse to me than watching at 2X speed, which I frequently elect to do.
https://beta.jumpcutter.pro/
The slowest parts are (1) loading up the audio to find silence and (2) if you decide to export an MP4, encoding that. Exporting an XML timeline is near-instantaneous.
I think at some point any sort of automation is bound to get something wrong and it'll likely never be perfect, so my goal is to add enough manual control that you're never just stuck with whatever the app decided.
Point is you'll still have to review manually the result anyway for under- and/or over-cuts.
[0] https://gist.github.com/vivekhaldar/92368f35da2d8bb8f12734d8... [1] https://www.youtube.com/c/vivekhaldar
My first stab at something before Recut was a Node script that did a similar sort of thing, just based on silence though, using ffmpeg's silencedetect to find silent parts and generating a cut list. And then as soon as it worked, I was like "well that's cool but I really want it to be interactive" and then... well it turned out that making a UI video editor was way harder than that script haha, but eventually Recut came to exist.
I'd like to be able to use komposition, which offered a bunch more nice features for screencast editing... https://github.com/owickstrom/komposition ...but it's bitrotted and isn't maintained any more.
Coolest thing you’ve got is “remind me about this when I’m back at my computer”.
Genius CTA
It's funny, that CTA doesn't actually seem to get many signups, but multiple people have said how cool it is! So I've left it up even though it doesn't seem to "work" all that well. Today for instance, there were 3 signups out of ~7.3k unique visits!
ffmpeg -i input.mkv -filter_complex "[0:a]silencedetect=n=-90dB:d=0.3[outa]" -map [outa] -f s16le -y /dev/null |& F='-aq 70 -v warning' perl -ne 'INIT { $ss=0; $se=0; } if (/silence_start: (\S+)/) { $ss=$1; $ctr+=1; printf "ffmpeg -nostdin -i input.mkv -ss %f -t %f $ENV{F} -y %03d.mkv\n", $se, ($ss-$se), $ctr; } if (/silence_end: (\S+)/) { $se=$1; } END { printf "ffmpeg -nostdin -i input.mkv -ss %f $ENV{F} -y %03d.mkv\n", $se, $ctr+1; }' | bash -x
My first attempt at this problem before Recut was basically this, but in Node, and creating an EDL file.
It works fine but the feedback loop is annoyingly long - run the script, import the result into an editor, listen back, realize the silence threshold was too high, try again... so that's what drove me to make an interactive version.