Repos / hi.imnhan.com / 1fc757ca43
commit 1fc757ca432180f3a6937f981abd045b4e690a4c
Author: Bùi Thành Nhân <hi@imnhan.com>
Date:   Wed Jun 10 11:09:17 2020 +0700

    gflick episode 2

diff --git a/content/images/gflick_01_mobile.png b/content/images/gflick_01_mobile.png
new file mode 100644
index 0000000..82b8651
Binary files /dev/null and b/content/images/gflick_01_mobile.png differ
diff --git a/content/posts/streaming-videos-from-google-drive.md b/content/posts/streaming-videos-from-google-drive.md
new file mode 100644
index 0000000..672c245
--- /dev/null
+++ b/content/posts/streaming-videos-from-google-drive.md
@@ -0,0 +1,117 @@
+Title: Streaming videos from Google Drive - 2nd attempt
+Date: 2020-06-10 08:25
+Category: side projects
+
+**TL;DR:** I improved the Google Drive video streaming experience mentioned in
+an [earlier blog post][1]. It now works like this on an Android phone with
+mpv-android installed:
+
+<video controls>
+  <source src="https://junk.imnhan.com/gflick-phone-demo.mp4" type="video/mp4">
+</video>
+
+The longer version follows.
+
+[Previously][1] I was writing a proxy of sorts that adapted Google Drive's
+"bearer token" auth to the more widely supported "basic auth" so I could watch
+movies. I was stuck at the point where desktop video players could stream just
+fine while their android ports would do nothing.
+
+Turns out it was a TLS issue: I configured nginx to use TLSv1.3 which is the
+latest and greatest, but mpv/vlc on android came bundled with older TLS
+libraries which only supported up to v1.2. This led me to another surprise: the
+nginx config generated by [Mozilla's SSL Configuration Generator][2], while
+advertised to support older TLSes (in either `Intermediate` or `Old` mode),
+didn't actually work in practice. [SSL tests][3] always reported that the only
+working SSL/TLS protocol was TLSv1.3.
+
+> The issue was pinpointed thanks to reading the android device's logcat
+> output. Did you know that in order to read logcat you only need to install
+> some [8-megabyte package][7] instead of the whole android studio behemoth? I
+> do now!
+
+As luck would have it, [Caddy v2][4] was recently released and they even
+provided a Debian repo! I had used Caddy v1 in the past but my impression was
+that despite their pitch of a "download and run" experience, actual [extra
+work][5] was required - it was straightforward and well-documented, but it was
+still extra busywork. This combined with the hassle of having to compile my own
+binary bounced me back to nginx. Both of these issues have been addressed in
+v2, so there's really no reason to keep wrestling with nginx + certbot anymore.
+
+> On that note, to this day I still haven't figured out how to make the
+> nginx/certbot combo play nice with ansible. Problem is, certbot's nginx
+> plugin wants to mutate the nginx config file itself, so the nginx configs
+> before vs after certbot runs are decidedly different. This requires
+> ridiculous gymnastics to mold into an ansible play - and don't even get me
+> started on multi-site setups. A [Caddyfile][6], on the other hand, simply
+> gets out of your way.
+
+Now that TLS is settled, I also made some changes to the usage flow:
+
+### Authentication
+
+The authentication responsibility has been moved from nginx/caddy to the python
+application itself to enable more fine-grained control:
+
+Every route, except for the video-serving `/v/*`, requires a user_token cookie.
+If it doesn't exist, redirect to `/login`, which will let user submit a
+password in order to get the user token back. User token is a 128-byte string
+that's regenerated every time the python script restarts. I should probably
+write a janitor script to periodically regenerate it instead.
+
+When user navigates to a video, a unique 128-byte slug is generated just for it
+and the video can now be directly streamed at `/v/<slug>`, with no
+authentication required. Currently slugs older than 1 day are wiped on python
+application startup, but then, like user token, I should probably stop relying
+on the script restarting to do cleanup operations.
+
+With this setup I can freely share the `/v/<slug>` url to other people without
+leaking any auth credentials, and they eventually expire too. There's tuning to
+be done for expiration mechanisms but the foundations are there.
+
+### Aesthetics
+
+The web interface has been revamped to make it easier for <strike>fat-fingered
+people on $current_year's trendy stupidly thin</strike> phones. Also present
+are folder icons and thumbnails, so it finally gives me everything I want from
+Google Drive's web UI and nothing that I don't. Fun fact: it works on
+[NetSurf][8] too (but then again why wouldn't it?).
+
+![gflick screenshot](/images/gflick_01_mobile.png)
+
+
+## What's the catch?
+
+**Client device is solely responsible for decoding the raw file.** This is both
+a blessing and a curse: We are guaranteed original quality but if the file was
+encoded with newer codecs (h265, av1, etc.) we're stuck with inefficient
+software decoding and some devices are just too weak to do so smoothly. My
+Amazon Fire HD 10 tablet suffers greatly when playing 1080p 10bit anime.
+Curiously, my crappy Mi A3 phone yields better performance, although stutters
+still happen here and there. More modest h264 movies play flawlessly, for what
+it's worth.
+
+**This is a proof of concept and the codebase quality reflects that.** I'm in
+the middle of cleaning it up for pypi friendliness and xdg compliance, but
+currently stuck when porting from std's http server to bottlepy. The current
+dirty codebase is working fine for me so I'm in no hurry though...
+
+
+## In conclusion
+
+I'm happy with how things turned out: I have [zero-maintenance unlimited cloud
+storage][9] for movies and an effortless streaming experience that requires
+virtually no client-side setup - just install a browser and streaming-capable
+video player, then everything works out of the box. This is _almost_ as
+convenient as Netflix, but without the stupid quality restriction on
+non-sanctioned devices. I probably need to upgrade to a beefier tablet though.
+
+[1]: /posts/towards-an-acceptable-video-playing-experience/
+[2]: https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1d&guideline=5.4
+[3]: https://www.ssllabs.com/ssltest/
+[4]: https://caddyserver.com/v2
+[5]: https://github.com/caddyserver/caddy/tree/v1.0.4/dist/init/linux-systemd
+[6]: https://github.com/nhanb/gflick/blob/4dd3dbdbdfe8de66337ed0a2fe420dd0e1d72f39/caddy/gflick
+[7]: https://pkgs.org/search/?q=android-tools
+[8]: https://www.netsurf-browser.org/
+[9]: https://drive.google.com/
diff --git a/content/posts/towards-an-acceptable-video-playing-experience.md b/content/posts/towards-an-acceptable-video-playing-experience.md
index 780d20d..bcdc081 100644
--- a/content/posts/towards-an-acceptable-video-playing-experience.md
+++ b/content/posts/towards-an-acceptable-video-playing-experience.md
@@ -126,6 +126,10 @@ ## Other failed attempts
 
 Also both of those required setting up each client device. Not ideal.
 
+### Update June 10, 2020
+
+The sequel is out: [Streaming videos from Google Drive - 2nd attempt][8]
+
 [1]: https://kipalog.com/posts/Cac-web-phim-da-giam-99-99--chi-phi-bang-google-drive-nhu-the-nao
 [2]: https://help.netflix.com/en/node/23742
 [3]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range
@@ -133,3 +137,4 @@ ## Other failed attempts
 [5]: https://github.com/nhanb/gflick
 [6]: https://github.com/nhanb/mpv-gdrive
 [7]: https://github.com/nhanb/drivein
+[8]: /posts/streaming-videos-from-google-drive-2nd-attempt/
diff --git a/motherfucking-pelican-theme b/motherfucking-pelican-theme
index ddf30d5..587cef4 160000
--- a/motherfucking-pelican-theme
+++ b/motherfucking-pelican-theme
@@ -1 +1 @@
-Subproject commit ddf30d526f639bedeee809873e90577e5eeb054b
+Subproject commit 587cef4348e2839ed2e6729f6747edf1a9716a30