#14 The process to get an app into Google Play is… byzantine

🏗️First, of course, you actually got to build your app. Then you register at the Google Play Console (and fork over $25). Then you provide your name, contact details, etc. and then the fun starts: You need official ID (drivers license, passport), proof of residence (“Meldezettel” in Austria), proof that you own an Android device, install the Google Play Console App on that device, and verify your contact phone number. ...

July 14, 2025

#13 "Token used too early" — the weirdest Google Sign-In error.

I’ve had my ups and downs with “Sign in with Google”: ⬆️It’s simple and works well on the web ⬇️It’s a complete hassle inside a hosted WebView in a native mobile app But here’s something really funny: I local clock is ahead of Google's — sometimes by as little as a few milliseconds – the sign in call will fail with “Token used too early.” 🤯 ✅ Solution: resync your system clock (in my case, my MacBook with Apple's time server). ...

July 13, 2025

#12 WebView ↔ Native app communication is easier than you think.

Even without relying on the utilities provided by Capacitor, you can easily pass data back and forth between your web app and its native counterpart: ➡️In JavaScript / TypeScript you can register global functions on the window object. The native code can call these via executeJavaScript() on the WebView. ➡️In the other direction, the native code can register a JavaScript interface on the WebView: webView.addJavascriptInterface(new Object() { @JavascriptInterface public void onSessionId(String value) { SaveUrlHandler.instance.setSessionId(value); } @JavascriptInterface public void closeApp() { MainActivity.this.finish(); } }, "Android"); which the JavaScript / TypeScript code can call whenever it wants: ...

July 12, 2025

#10 Running text-to-speech in the #Cloud is harder than you would think (part three)

So, after finally setting up a dedicated virtual machine (VM) to run my text-to-speech workloads and wiring up all the build and deployment scripts, I got a bit excited. Could I reduce the TTS latency even further if the VM had GPU power? In theory: Yes. In practice: Google doesn't give you access to their GPUs straight away. There’s a special quota setting for VM instances with GPUs, and by default that’s set to zero. As a regular user, you cannot increase this without contacting Google Cloud Support. ...

July 10, 2025

#9 Running text-to-speech in the #Cloud is harder than you would think (part two)

Do you remember when I mentioned the difficulty of running 🐸 CoquiTTS in the cloud yesterday? My first experiment was to run it directly in my Cloud Run backend service. In theory, this could have worked, but you'll never guess why it failed in practice. x86 CPUs. Really. Like the ones we had in our computers in the 90s. How did I figure this out? After taking a horribly long time to start up, the TTS service failed with a message saying that it was running on an 'incompatible' CPU architecture. Specifically, 32-bit x86 CPUs. ...

July 9, 2025

#8 Running text-to-speech in the #Cloud is harder than you would think (part one)

For the podcast automation feature that I’m planning for a future version of poketto.me, I’ve been experimenting with various text-to-speech solutions. The easiest and highest-quality approach would have been the ElevenLabs API. However, considering the “throwaway” nature of these audio files – most of which would only be listened to once by one person – and the cost structure that this would introduce, I desperately need a cheaper approach. The Python library 🐸 CoquiTTS is pretty awesome: There are many different models to choose from, ranging from 'super low latency' to 'high quality' (including voice cloning). Therefore, poketto.me users could choose from many different voices, and from a commercial perspective, I could set different price points for different levels of quality and latency. However, they all require significant computing power to function. ...

July 8, 2025

#7 Refactoring “legacy” code? Let the AI handle it!

For reasons outlined in yesterday's post, I had to switch poketto.me from #CloudSQL (MySQL) to a completely different database architecture: Firebase 🔥 At that stage, the Python backend code base wasn’t huge, but it was already fairly substantial. It included CRUD operations for several entities, as well as some basic lookup logic. Rewriting the whole thing would have taken me at least half a day. Instead, I asked my good friend #Claude to take care of things. And, to my surprise, the result worked straight away! 🎁The “dorp in” replacement generated by the AI immediately passed my unit tests, and also the chatbot’s instructions for how to set up and configure #Firebase were actually useful. ...

July 7, 2025

#6 CloudSQL is prohibitively expensive (at least for small projects)

When I started setting up the cloud infrastructure for poketto.me, I didn’t give much thought to costs. I thought it was such a small project that it just wouldn’t matter. I launched a #CloudSQL (MySQL) database with pretty much the default settings and was quite happy with it – until I checked the billing dashboard a couple of days later and realised that I was already spending almost €4 per day on the database alone. 120 euros per month just for a few MySQL tables? That couldn’t be right. ...

July 6, 2025

#5 There’s no “npx cap remove” 🤦‍♂️

#Capacitor comes with a user-friendly command line interface. To add a new mobile platform to your project, simply run “npx cap add [android | ios]”. And to remove one? Exactly — you guessed it: 'npx cap remove...' But: That command isn’t implemented – for understandable reasons. The interesting thing is, though, that it's "plausible" that it would be there, right?. So it's not surprising that #Claude insists it exists. This once again highlights a major issue with LLMs that I just can’t shut up about: Just because what the chatbot says sounds 'plausible' doesn't mean it's correct. In the case of AI-assisted coding, that’s not such a big deal – you, the developer, will eventually realise that the AI was wrong. But what about the many other use cases where we blindly trust the AI and put whatever it says into action? 🤔 ...

July 5, 2025

#4 Multi-threaded webservers in Python: A rabbit hole you don’t want to get into.

Put simply, serving web requests properly in Python is not easy. poketto.me uses a fairly basic off-the-shelf stack (#Flask as a web framework and #SocketIO for websocket communication), and you would never guess the issues you could encounter with it. For starters, Flask comes with a built-in web server (“werkzeug”), which is convenient for development, but absolutely not for production (it even warns you in bright red). 🧵It runs on a single thread – I'm not kidding. This means it can only handle one web request at a time. If that request involves any actual work, such as extracting web content, it cannot handle any other requests at the same time. ...

July 4, 2025