I had been trying to seek an ideal portable device that could be used to draft posts, watch videos, and code. I tried to use my Macbook for this, but it was too heavy for portable use.
I considered several solutions, but all were canceled by myself, for example:
GDP Win: I don’t have any interest in Windows. Furthermore, the keyboard is too small. Calluses must be at my fingertips if I use this to draft posts and code. Besides these, the price is not ideal either 🥹
DevTerm: Linux, 1 point gotten. But the screen is too small for long-time use. It seems the battery life is also not good enough.
PinePhone: This Linux phone equipped with its official keyboard kit is similar to DevTerm. It could be flashed to an Android phone if it was not good enough. According to the announcement of Pine, the product is not mature enough and is aimed at Linux developers with extensive knowledge of embedded systems and experience with mobile Linux. That is to say that we may face many unknown and unpredictable issues. I don’t refuse to troubleshoot, but don’t want to do that for my daily portable devices.
When I was lost in the options, one word popped into my mind: ChromeOS. Before, my understanding of ChromeOS was just its Chrome-based mechanism, which meant we could only access web pages and run web applications on it. And its lightweight also brings high cost-effectiveness. After a thorough go-through on this, I found its functionality and usability were both significantly improved. So I finally decided to get one. Actually, I will not share the functionalities and features of ChromeOS and Chromebook because Google’s official sites introduce these better. Instead, I will share more about the surprise I experienced during my initial experience of ChromeOS.
Deep Integration of Three Operation Systems
Currently, Chrome not only supports web pages, web Apps, and PWAs, which are Progressive Web Apps, but also supports Android Apps and Linux Apps. And it is not simply running an Android simulator and a Debian simulator on ChromeOS. Overall, the experience is similar to the Coherence Mode of Parallels Desktop. We can run Chrome browser, web Apps, PWAs, Android Apps, and Linux Apps as native Apps simultaneously without managing three separate desktops of three OSs or rebooting.
As the screenshot above shows, we can see Google Play running in the upper left corner and Kodi in the bottom right corner, both Android Apps. We can also see LibreOffice running in the bottom left corner. In the upper right corner and the middle of the left side, we can see ChromeOS built-in Chrome browser and the PWA of Outlook. Except for the UI differences caused by the system toolkits of three operation systems and permission differences caused by the sandboxes, there are no other significant differences when switching across different types of Apps.
Android App Streaming
If the phone paired to a Chromebook is running Android 13 or above, the Apps running on the phone can be streamed to ChromeOS. This streaming of Android App is not casting but as a native App running on the Chromebook like the screenshot above. Actually, the running App is not installed on this Chromebook.
Global Extension Support
I keep trying to improve my English, including English reading. Recently, I have found a way of reading called Bionic Reading, and it can enhance reading effectiveness.
So, I started to use Jiffy Reader, an extension to automatically show the chosen web pages in the Bionic Reading mode. I hope there will be a tool that globally shows as much content in the Bionic Reading mode as possible on the macOS level, but obviously, it is nearly impossible.
But, on ChromeOS, most Apps are web pages, web Apps, and PWAs; However, Android Apps and Linux Apps only form a tiny part. The former part of Apps are all running on top of Chrome; therefore, in a nutshell, nearly all the Chrome extensions work for this part, including Jiffy Reader. I enable the Bionic Reading mode for Outlook, so we can find the bold letters in the Outlook Home, View, and Help menu items shown on the ChromeOS desktop screenshot above.
In this case, we can use our favorite extensions outside web browsers now 😂
Seamless Mode Switch
ChromeOS supports tablet mode and laptop mode. The tablet mode is called Touch UI Layout, similar to an Android tablet or Android phone; certainly, laptop mode is like a laptop. There is a configuration that makes Chromebook automatically switch between laptop mode and tablet mode seamlessly based on whether it connects to a mouse or a touchpad.
As shown above, I bought a detachable Chromebook. Whenever I attach or detach the covered keyboard, the Chromebook can switch back and forth seamlessly. It is pretty convenient.
That is all. I will keep digging and will share more surprises that I meet. 😁
Days ago, I found a very interesting userscript on Appinn.com. All Chinese characters on web pages can be annotated with Pinyin by enabling this userscript on web-browser such as Chrome, Firefox, etc.
Actually, anyone that understands Pinyin will be able to pronounce any Chinese characters annotated with Pinyin.
Since several of my foreign colleagues are learning Chinese and Mandarin, I think it will not be a bad idea to share with them this userscript. But it is not easy for them to use this userscript because not only the README file but the menu and comments of this userscript are also written in Chinese. So I am drafting this post to introduce how to use this.
To enable a userscript, we have to install a browser extension to run userscripts on websites; quite a few ways of installing them are listed here.
This script is hosted with GreasyFork. We can install it after we install one of the extensions above and restart the browser to take effect.
If the extension we installed was Tampermonkey, we could see this menu after clicking the extension icon of Tampermonkey.
But the menu is definitely not user-friendly to Chinese learners. Only the title is in English, but all the menu items are still in Chinese, not to mention this is not in Simplified Chinese but Traditional Chinese, which is harder for Chinese learners.
Let me explain the four items one by one.
繁簡切換: This item helps you to switch the Chinese character between Simplified Chinese and Traditional Chinese. If you cannot figure out which one is Simplified Chinese, remember that mainly the version of Chinese with fewer strokes is Simplified Chinese.
顯示拼音: This item is the most significant one for Mandarin learners. This item can annotate all the Chinese characters with Pinyin as below.
個性設定: We can ignore this one.
此站禁用: If the automatic switch between Simplified Chinese and Traditional Chinese is enabled with one of the submenus of the above item, we can turn off the switch for the domain of the currently active web page.
Here is a brief introduction to this script. Hope this script can help some Chinese and Mandarin learners.
WeChat could connect me to nearly all my friends and relatives in China. But now, I have to install several IMs to ensure that I can connect to all of my new friends because of the different countries they are staying in, their different kinds of concerns, and their different habits of using instant messaging services (IM). Besides WeChat, I have WhatsApp, Telegram, Signal, Line, Google Chat, and Linkedin on my phone. Although Telegram is my favorite, I have to switch between these IMs, and this really gives me a headache.
There are definitely several all-in-one IMs, but they are not ideal enough because they are all implemented in the ways below.
Integrated all the browser versions of the IMs with HTML frame tags. It is alright on a Laptop, but facing these terrible UIs, that only suit big screens, on phones is a nightmare.
Unpacked all the traffics of the browser versions of the IMs and packed them again into prettier and higher-integrated UI. Frankly speaking, I was worried about the potential data security issues, which would destroy the privacy protection guaranteed by these IMs’ end-to-end encryption (E2EE).
However, I heard about a service called Beeper that really gave me some hope.
According to the official introduction, this service really meets all my imagination about an all-in-one IM. So I signed it up, but was defeated by the reality.
After several months, more than 100000 guys are still waiting before me, which is really hopeless. Then I noticed that Beeper is built based on Matrix, so why don’t I deploy this by myself?
After going through a little, I was totally impressed by Matrix:
Supports bridging. Matrix can exchange data and messages with other IMs such as WhatsApp, Telegram, Signal, etc.
Supports E2EE. The E2EE algorithm is open-source and verified by many application scenarios, such as Signal.
Open-source. Matrix is open-source and supports self-host. Not only Matrix itself but all the bridging services are also open-source. Although E2EE is relatively enough, if self-host is possible, zero-access encryption can be totally ensured, and man-in-the-middle attacks can be relatively blocked.
Let’s roll!
Deploy Matrix Service
There are at least 6 open-source implementations of Matrix, and I finally prefer using Synapse because this is the only server of Matrix implemented by the Matrix core team.
Welcome to the documentation repository for Synapse, a Matrix homeserver implementation developed by the matrix.org core team.
Introduction to Synapse @ https://github.com/matrix-org/synapse
I decided to deploy with Docker, as mentioned in the official documentation, to make it easy to maintain. I can say that the official documentation is pretty good, but we still need to face several issues before successfully deploying it.
Before deploying, we need to confirm the domain name of Matrix first. Let’s assume it is homeserver.mymatrixhost.com. Now we can start deploying, and I don’t think I need to introduce how to install Docker here.
Configuration of Matrix
Firstly, a configuration file needs to be generated with the following command:
SYNAPSE_SERVER_NAME (Mandatory): the domain name the service uses. It should be homeserver.mymatrixhost.com, as we assumed.
SYNAPSE_REPORT_STATS (Mandatory): Whether to report anonymous statics. I choose no.
/data: the default folder of Synapse’s configuration. As per the command above, it is /data.
Suppose we set synapse-data as the folder of the data source and the Docker is running under the default configuration. In that case, we will see a file named homeserver.yaml in the folder of /var/lib/docker/volumes/synapse-data/_data after executing this command. This is the configuration file of the Matrix service as below.
# Configuration file for Synapse.## This is a YAML file: see [1] for a quick introduction. Note in particular# that *indentation is important*: all the elements of a list or dictionary# should have the same indentation.## [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html## For more information on how to configure Synapse, including a complete accounting of# each option, go to docs/usage/configuration/config_documentation.md or# https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.htmlserver_name:"homeserver.mymatrixhost.com"pid_file:/data/homeserver.pidlisteners:-port:8008tls:falsetype:httpx_forwarded:trueresources:-names:[client,federation]compress:falsedatabase:name:sqlite3args:database:/data/homeserver.dblog_config:"/data/homeserver.mymatrixhost.com.log.config"media_store_path:/data/media_storeregistration_shared_secret:"bzxSPVVwhHMiSs6b6YRBKreN-i^W^2tCUmS^4r~Hr:_ew,Alkb"report_stats:falsemacaroon_secret_key:"J1kYVZ~+fixo*RI@K5,~W-LoL#lMr0ZVJg.nFN,=MT_bYpk@JJ"form_secret:"2zXL_q~hI1nF^m#yBumaIvY9dFU~j9uiFO0bGR5Rgc-U5gf6@2"signing_key_path:"/data/homeserver.mymatrixhost.com.signing.key"trusted_key_servers:-server_name:"matrix.org"# vim:ft=yamlCode language:YAML(yaml)
Most of the items can be set as default. But I will still explain several important items.
if HTTPS needs to be enabled, tls should be set to true. But I don’t recommend it because:
It is relatively troublesome to configure certificates directly for applications in containers.
It is easier to test our service if it serves with HTTP.
There are a few solutions that provide service externally with HTTPS and also retain HTTP. For example, with the help of a reverse proxy, as mentioned in the official documentation. This is also the solution I prefer. Regarding to the possible security issue caused by HTTP, we can block all the inbound traffic to Port 8008 with a firewall and test the HTTP service locally through Port 8008.
Synapse supports PostgreSQL and SQLite, and I prefer SQLite for easier deployment because this Matrix service is only for self-use. And because we set the default /data as the configuration folder, the path of the configuration file is /data/homeserver.db.
Next,
Run Matrix
Besides the Synapse, we also need to run the bridging components, which will run in separated containers. So it is essential to set up the network bridge before we run the Matrix so that the services can find each other at the domain name that is the same as its container name.
As above, we name the Matrix’s container with –name synapse, so that we can operate this container by claiming the name instead of the container ID. We also link the container to the network bridge synapse-net with –net synapse-net so that the services in other containers can contact this at the domain name that is synapse.
With the command above, we can go through the latest 100 lines of logs to check the status of the service. Because it is for self-use, we have not made any complicated changes to the configuration; it is pretty easy to make Matrix run. Before blocking all the inbound traffic to Port 8008 with a firewall, we can access http://{IP_of_Host_You_Deploy_the_Service}/_matrix/static/ to check Matrix. If good, it will show as below.
We can also use this command docker network inspect synpase-net to check the network status of the containers linking to the network bridge synapse-net.
Enable HTTPS: Reverse Proxy
I am unfamiliar with Apache2, but I simplified the deployment using DigitalOcean‘s 1-Click LAMP Droplet. In this case, I used Apache2 to set up the reverse proxy. And now, I am using Apache2 to introduce the reverse proxy setup.
Firstly, we must add the configuration below to /etc/apache2/sites-available/000-default-le-ssl.conf.
Actually, I really met a weird issue when setting up the reverse proxy. If I restarted the Apache2 service without enabling the headers or proxy modules, Apache2 failed to start and threw an error telling me I should enable the specific module. But Apache2 succeeded in starting without enabling the proxy_http module. However, when accessing the service through the port of the reverse proxy, the error below would be thrown.
AH01144: No protocol handler was valid for the URL /_matrix/static (scheme 'http'). If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.Code language:JavaScript(javascript)
The mod_proxy mentioned in the error message really confused me until I found a comment of an answer with many thumb-ups on StackOverflow. It made me know that I also needed to enable the proxy_http module besides the proxy modules.
I am not familiar with Apache2. If anyone knows why the error message is so weird, Kindly explain, please.
Next, we must obtain an SSL certificate and bind a domain name. Please let me skip introducing this part here. Once done, we can access https://homeserver.mymatrixhost.com/_matrix/static/. If everything is good, we can get the page below again.
Now there is one last step to get Matrix ready for production: blocking the inbound traffic to Port 8008 for insecure HTTP access.
Verify with a Client
Since HTTPS is available, we can officially start to use the Matrix service now. Two more steps must be done before we use it: Administrator account and client.
Create an Administrator Account
With the command below, we can create an administrator account.
Please remember the -a parameter. If not, the account created will not be an administrator account.
Connect to Matrix with a Client
Matrix is open source, so we can find many Matrix clients on this page. After I tried Element and FluffyChat, I preferred FluffyChat.
Now we can try logging in. When logging in, do ensure to update the server from Matrix.org to homeserver.mymatrixhost.com, the Matrix service we deployed, and key in the username and password of the administrator account we created in the previous step.
Theoretically, our client will successfully help us log in the Matrix service.
Now we can start with the most exciting part. Let’s make Matrix an all-in-one E2EE IM.
Deploy the Bridges
Let’s start with WhatsApp and Telegram, the most popular IMs first. Similar to the deployment of Synapse, I also deployed the bridges with Docker, as the official documentation mentioned.
Deploy the Bridge to WhatsApp
WhatsApp Configuration
Firstly, we must execute mkdir mautrix-whatsapp && cd mautrix-whatsapp to create a folder to put the configuration files in. Then use docker run --rm -v `pwd`:/data:z dock.mau.dev/mautrix/whatsapp:latest to generate the configuration. After that, we will see config.yaml in the mautrix-whatsapp folder.
We can use default values for most items, so here I will only introduce several items that need altered values.
homeserver:# The address that this appservice can use to connect to the homeserver.address:http://synapse:8008# The domain of the homeserver (also known as server_name, used for MXIDs, etc).domain:homeserver.mymatrixhost.com# What software is the homeserver running?# Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here.software:standard# The URL to push real-time bridge status to.# If set, the bridge will make POST requests to this URL whenever a user's whatsapp connection state changes.# The bridge will use the appservice as_token to authorize requests.status_endpoint:null# Endpoint for reporting per-message status.message_send_checkpoint_endpoint:null# Does the homeserver support https://github.com/matrix-org/matrix-spec-proposals/pull/2246?async_media:false# Application service host/registration related details.# Changing these values requires regeneration of the registration.appservice:# The address that the homeserver can use to connect to this appservice.address:http://mautrix-whatsapp:29318Code language:YAML(yaml)
Not sure whether you still remember that we created a network bridge called synapse–net that lets containers use the container name as the domain name to contact each other.
The address item of the homeserver above is to claim the Synapse service we deployed. All the containers are running on the same host, and the bridge to WhatsApp can access through Port 8008 to access the insecure service of HTTP, so we set the address to http://synapse:8008. Besides, the address of appservice should be set to http://mautrix-whatsapp:29318, and the domain should be set to homeserver.mymatrixhost.com.
# Database config.database:# The database type. "sqlite3-fk-wal" and "postgres" are supported.type:sqlite3-fk-wal# The database URI.# SQLite: A raw file path is supported, but `file:<path>?_txlock=immediate` is recommended.# https://github.com/mattn/go-sqlite3#connection-string# Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable# To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresqluri:file:///data/db.db?_txlock=immediateCode language:YAML(yaml)
Although this bridge also supports PostgreSQL, I still prefer SQLite for self-host and easy maintenance. If encountering the error regarding to failed DB initiation when starting this bridge, executing touch db.db to create an empty DB file can solve this.
# End-to-bridge encryption support options.## See https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html for more info.encryption:# Allow encryption, work in group chat rooms with e2ee enabledallow:true# Default to encryption, force-enable encryption in all portals the bridge creates# This will cause the bridge bot to be in private chats for the encryption to work properly.default:trueCode language:YAML(yaml)
allow (Mandatory): Set this to true so that all the sessions bridged by this service can be E2EE enabled.
default (Mandatory): Set this to true so that all the sessions bridged by this service will be E2EE enabled by default.
At last, we need to confirm the permission configuration, and matrixadmin is the administrator account we created.
Register the AppService
The configuration file is done, and we can start to generate the AppService registration file now. Let’s rerun the following command.
docker run --rm -v `pwd`:/data:z dock.mau.dev/mautrix/whatsapp:latestCode language:Bash(bash)
One new file named registration.yaml will be in the configuration folder, and we need to move this file to the Synapse configuration folder and rename it to a recognizable name.
We can see the other registered AppService related to Telegram and will explain this.
Start the Bridge to WhatsApp
Since we set http://mautrix-whatsapp:29318 as the address of appservice, name the container as mautrix-whatsapp, and link it to synapse-net, we start it with the following command.
After starting the bridge and restarting the Synapse, the bridge will work. To initial the bridge service, we need to add @whatsappbot:homeserver.mymatrixhost.com into the client’s contact list, such as FluffyChat, and send login to it. In this case, the whatsappbot will initiate the session to log in WhatsApp. The whole process is similar to logging in the browser version of WhatsApp. I think this bridge is a wrap of the browser version of WhatsApp.
Now, the bridge is starting to deliver the WhatsApp sessions to FluffyChat via Matrix. And we can check on the bridge to Telegram.
Deploy the Bridge to Telegram
Telegram Configuration
The deployment is similar to deploying the bridge to WhatsApp. Create the configuration folder and generate the configuration file.
mkdir mautrix-telegram && cd mautrix-telegram.
docker run --rm -v `pwd`:/data:z dock.mau.dev/mautrix/telegram:latestCode language:Bash(bash)
Also, we need to update the addresses of Matrix and the bridge to Telegram.
# Homeserver detailshomeserver:# The address that this appservice can use to connect to the homeserver.address:http://synapse:8008# The domain of the homeserver (for MXIDs, etc).domain:homeserver.mymatrixhost.com# Whether or not to verify the SSL certificate of the homeserver.# Only applies if address starts with https://verify_ssl:false# What software is the homeserver running?# Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here.software:standard# Number of retries for all HTTP requests if the homeserver isn't reachable.http_retry_count:4# The URL to push real-time bridge status to.# If set, the bridge will make POST requests to this URL whenever a user's Telegram connection state changes.# The bridge will use the appservice as_token to authorize requests.status_endpoint:# Endpoint for reporting per-message status.message_send_checkpoint_endpoint:# Whether asynchronous uploads via MSC2246 should be enabled for media.# Requires a media repo that supports MSC2246.async_media:false# Application service host/registration related details# Changing these values requires regeneration of the registration.appservice:# The address that the homeserver can use to connect to this appservice.address:http://mautrix-telegram:29317Code language:YAML(yaml)
Choose SQLite as the database as well.
# The full URI to the database. SQLite and Postgres are supported.# Format examples:# SQLite: sqlite:///filename.db# Postgres: postgres://username:password@hostname/dbnamedatabase:sqlite://db.dbCode language:YAML(yaml)
E2EE configuration.
# End-to-bridge encryption support options.## See https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html for more info.encryption:# Allow encryption, work in group chat rooms with e2ee enabledallow:true# Default to encryption, force-enable encryption in all portals the bridge creates# This will cause the bridge bot to be in private chats for the encryption to work properly.default:trueCode language:YAML(yaml)
Besides all the above, we also need to apply for the API Key of Telegram. I believe this bridge is a wrap of a series of Telegram APIs.
telegram:
# Get your own API keys at https://my.telegram.org/apps
api_id: 10000001
api_hash: 123abcdefghijklmnopqrstuvwxyz123
# (Optional) Create your own bot at https://t.me/BotFather
bot_token: disabledCode language:PHP(php)
Obviously, the Key above is fabricated as an example. We must access the Telegram App creation page to apply for the API Key. When applying, ensure that the URL should be the domain name of your Matrix service, homeserver.mymatrixhost.com we assumed.
Register the AppService
The same as registering the bridge to WhatsApp.
docker run --rm -v `pwd`:/data:z dock.mau.dev/mautrix/telegram:latest
cp registration.yaml /var/lib/docker/volumes/synapse-data/_data/mautrix-telegram-registration.yamlCode language:Bash(bash)
Since we set http://mautrix-telegram:29317 as the address of appservice, name the container as mautrix-telegram, and link it to synapse-net, we start it with the following command.
After starting the bridge and restarting the Synapse, the bridge will work. To initial the bridge service, we need to add @telegrambot:homeserver.mymatrixhost.com into the client’s contact list, such as FluffyChat, and send login to it. In this case, the telegrambot will initiate the session to log in Telegram. The whole process is similar to logging in Telegram.
Now, the bridge is starting to deliver the Telegram sessions to FluffyChat.
All-in-One E2EE IM Service
It took me nearly two days to adapt to FluffyChat and Matrix. Now I have turned off WhatsApp and Telegram notifications and used FlullyChat and self-host Matrix to handle my daily IM needs.
At last, do not forget to use the firewall to block the inbound traffic to Port 29317 and 29218 being listened to by the bridges.
Got the budget on my birthday, and the Black Friday deal was not bad, so I finally got a new toy: the reMarkable 2. 😂
reMarkable 2
Before I got this tablet, several guys recommended this to me, and what finally convinced me to buy it was no more than its extreme paper-like writing, thinness, lightness, design, etc. But after I experienced this reMarkable 2, I found its usefulness and customizability were totally beyond my expectation. The most surprising thing is that reMarkable OS is based on Linux and the manufacturer generously exposes the SSH port and root password.
During the year-end holiday, I went through this tablet a lot and would take notes with this post.
Functionality Completeness
Language Issues
The reMarkable 2 does not support non-Latin characters, so CJK (Chinese, Japanese, and Korean) characters are displayed as squares, as below.
Squares
One compromised solution is to use PDF only if possible, but we still need to ensure that all the necessary fonts are embedded in the PDF documents. If any CJK characters apply fonts not embedded in the documents, they will still be displayed as squares.
Luckily, the OS of reMarkable is based on Linux, and the SSH and the root password are available, so we can easily install the CJK fonts. Take this page as a reference for installing the RMPKG.
And the Noto Sans font can support CJK characters now.
Type Diversity
The reMarkable 2 only natively supports PDF and EPUB, but more is needed. Toltec, this community-maintained repository of free software for the reMarkable tablet, helps. With Toltec, we can install KOReader into reMarkable 2. Thanks to the powerful format compatibility, we can read documents in almost all major formats with the reMarkable 2.
## Use opkg to install remux and koreader after installing the Toltec
opkg update
opkg upgrade
# remux# Launcher that supports multi-tasking applications
opkg install remux
# KOReader# Ebook reader supporting PDF, DjVu, EPUB, FB2, and many more formats
opkg install koreaderCode language:Bash(bash)
There is one thing that needs to be highlighted. The shelves of the reMarkable and KOReader do not share; we can surely use cloud storage to solve this. I will share this later. Before installing the Toltec, please ensure that the current Toltec release can support the OS version of your reMarkable tablet.
The Toltec repository includes lots of exciting software. Take your time to go through it if you are interested.
Article Management and Document Management
The reMarkable provides a browser extension. With this extension, users can convert web pages into EPUB documents and put them on the reMarkable’s shelf with one click. It is really convenient, but it is hard for me to get used to it.
The format of the EPUB document content converted by the extension looks strange.
Years of using Pocket as a read-it-later application make me not plan to switch to reMarkable. And I don’t want to put all my saved web pages on the reMarkable’s shelf.
So I started automating pushing the saved pages from Pocket to reMarkable, and I recalled n8n, an open workflow automation platform.
I heard about n8n before, and I tried this time and found it was really convenient. I deployed n8n on the NAS, then created this workflow quickly. You may see that the UI of workflow on n8n is really visual and user-friendly.
Pocket 2 Google Drive
I use a scheduler to trigger the workflow below.
Get the saved timestamp of the last run, and retrieve the pages saved after the last run. The API for retrieving the saved pages has an optional parameter: since. With this parameter, Pocket will only return items modified since the given UNIX timestamp.
If the list is not empty, the workflow will use the OneSimpleAPI to convert the web pages into PDF documents and upload them to Google Drive one by one.
Update the saved timestamp to present.
The above workflow nodes of OneSimpleAPI and Google Drive are natively supported by the n8n and are very easy to call.
These tips may reduce some of the confusion when you are creating a similar workflow:
The since parameter of Pocket API uses the last modified time as a reference. If you would like to push some outdated saved pages to Google Drive, you just need to make a slight change to them, such as tag modification and resaving it again, and these pages will be pushed to Google Drive.
When you trigger a deletion of a saved page, Pocket will update the status of this page to 2 before the page is totally removed. So please ensure all the saves whose status is 2 will be filtered out to prevent unnecessary uploading.
The Google Drive node supports two authentication methods: OAuth 2 and ServiceAccount. OAuth 2 requires that your callback URL contains a domain name other than an IP. For security, my NAS blocks all direct external access and only allows VPN access, so I have not bound my NAS to any domain name. So anyone whose NAS is in the same situation as mine, please prefer ServiceAccount. Primarily the service account is not your Gmail account, so please grant the R/O permission to the Google Drive folder of your reMarkable documents to the service account.
Permissions Granted to Service Account
Actually, I can directly push the documents onto the reMarkable shelf, but I don’t think this is a good idea. The limitation of documents’ count on the reMarkable shelf can help me focus more on the current readings before I pick new readings from Google Drive. I will not let too many documents mess up my reMarkable shelf.
As I mentioned, the shelves of KOReader and reMarkable 2 don’t share, so using Google Drive to store my pending readings can make the shelves tidier. It is also easy for KOReader and reMarkable 2 to retrieve the documents wirelessly.
Publication management
Ages before, I started to use Calibre to manage publications, such as novels, books, comics, papers, etc. Then I moved the library of Calibre to NAS and ran Calibre Web in a Docker container so that I could manage the publications from any device.
Calibre Web is not an official product of Calibre, and there is more than one fork on GitHub. I prefer the image managed by linuxserver.io. If you have never used Calibre before deploying Calibre Web, you will need a new library file (metadata.db) to initiate the configuration. You can install Calibre to create a library or download it from here.
Besides the publication management via web UI, Calibre Web also supports the OPDS catalog.
The Open Publication Distribution System (OPDS) Catalog format is a syndication format for electronic publications based on Atom and HTTP. OPDS Catalogs enable the aggregation, distribution, discovery, and acquisition of electronic publications.
OPDS Catalogs use existing or emergent open standards and conventions, with a priority on simplicity.
OPDS Catalog 1.2
In this way, I can search for publications from the OPDS catalog.
If items exist, the OPDS catalog will send an XML containing publication information, including book names and links, as a response.
<?xml version="1.0" encoding="UTF-8"?><feedxmlns="http://www.w3.org/2005/Atom"xmlns:dc="http://purl.org/dc/terms/"xmlns:dcterms="http://purl.org/dc/terms/"><id>urn:uuid:2853dacf-ed79-42f5-8e8a-a7bb3d1ae6a2</id><updated>2022-12-29T16:23:55+00:00</updated><linkrel="self"href="/opds/search/root cause?"type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/><linkrel="start"href="/opds"type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/><linkrel="up"href="/opds"type="application/atom+xml;profile=opds-catalog;type=feed;kind=navigation"/><linkrel="search"href="/opds/osd"type="application/opensearchdescription+xml"/><linktype="application/atom+xml"rel="search"title="Search"href="/opds/search/{searchTerms}" /><title>Calibre-Web</title><author><name>Calibre-Web</name><uri>https://github.com/janeczku/calibre-web</uri></author><entry><title>Root Cause Analysis Handbook</title><id>urn:uuid:06a66a9a-59d4-415b-a472-a413b8cf923d</id><updated>2022-12-22T07:56:20+00:00</updated><author><name>ABS Consulting</name></author><publisher><name>Rothstein Publishing</name></publisher><dcterms:language>eng</dcterms:language><categoryscheme="http://www.bisg.org/standards/bisac_subject/index.html"term="Business & Economics"label="Business & Economics"/><summary>Are you trying to improve performance, but find that the same problems keep getting in the way? Safety, health, environmental quality, reliability, production, and security are at stake. You need the long-term planning that will keep the same issues from recurring. Root Cause Analysis Handbook: A Guide to Effective Incident Investigation is a powerful tool that gives you a detailed step-by-step process for learning from experience. Reach for this handbook any time you need field-tested advice for investigating, categorizing, reporting and trending, and ultimately eliminating the root causes of incidents. It includes step-by-step instructions, checklists, and forms for performing an analysis and enables users to effectively incorporate the methodology and apply it to a variety of situations. Using the structured techniques in the Root Cause Analysis Handbook, you will: Understand why root causes are important. Identify and define inherent problems. Collect data for problem-solving. Analyze data for root causes. Generate practical recommendations. The third edition of this global classic is the most comprehensive, all-in-one package of book, downloadable resources, color-coded RCA map, and licensed access to online resources currently available for Root Cause Analysis (RCA). Called by users "the best resource on the subject" and "in a league of its own." Based on globally successful, proprietary methodology developed by ABS Consulting, an international firm with 50 years' experience in 35 countries. Root Cause Analysis Handbook is widely used in corporate training programs and college courses all over the world. If you are responsible for quality, reliability, safety, and/or risk management, you'll want this comprehensive and practical resource at your fingertips. The book has also been selected by the American Society for Quality (ASQ) and the Risk and Insurance Society (RIMS) as a "must have" for their members.</summary><linktype="image/jpeg"href="/opds/cover/30"rel="http://opds-spec.org/image"/><linktype="image/jpeg"href="/opds/cover/30"rel="http://opds-spec.org/image/thumbnail"/><linkrel="http://opds-spec.org/acquisition"href="/opds/download/30/pdf/"length="24812876"mtime="2022-12-22T07:56:20+00:00"type="application/pdf"/></entry></feed>Code language:HTML, XML(xml)
Based on this, I created the workflow below to upload the document I need to Google Drive automatically.
Search for the book and upload the needed books to Google Drive.
I use the Webhook node to pass the query string to the OPDS catalog to search for the publications.
Others
There are many functionalities worth going through on reMarkable, such as templates. I am amazed by the completion of reMarkable’s support for PDF, especially the support for the internal links. Many E-ink tablets almost don’t support internal links in PDF documents. Even to support some significant internal links such as tables of contents, they compromise toggle a menu to help users locate the pages instead of jumping during the document reading.
So we can generate templates with reCalendar. This template can help us plan and summarize in a year-month-day dimension. To prevent loading too long, the timespan of the preview below is only two months. You can also tweak the template by adding special dates, modifying the timespan, etc., with reCalendar.
As a former CS student and an ITer, the computer has become an inevitable part of my life. And also how to well manage the computers and peripherals is always a changing problem.
Why does this problem keep changing?
Environments Decide the Requirements
When I was in university, what I could control was just a tiny desk in the dormitory. So at that moment, I hoped all the peripherals would be slim and wireless so I could quickly put the mouse and keyboard into the drawer without unplugging the cable.
I have to say that if we forget to turn off the mouse and keyboard, the receiver drains the battery really fast 😂. There was no Bluetooth then, and the early versions of Bluetooth were unsuitable for data transmission between computers and peripherals.
One Wireless Mouse and Its Receiver
Looking at the HUGE CRT and chassis, having a laptop became my dream then. In this way, I could take it everywhere. Especially during summer and winter vacations, I could take it home 🤭.
CRT and Chassis
After graduating, nearly all my computers are laptops. And due to Apple, most manufacturers are simplifying the ports on the laptop, so I have to make sure most of the peripherals should support Bluetooth. Then, due to the need for confidentiality at work, I had to ensure all Bluetooth devices could memorize multiple pairs to separate my personal laptop and office laptop so that I could conveniently switch one set of peripherals between my personal laptop and office laptop.
Is Wireless Always More Convenient than Wiredness?
However, due to the requirements of my employer and myself, my device management has become incredibly complicated 🤦. I need to ensure one set of peripherals can switch smoothly across four laptops and one chassis. Obviously, Bluetooth is unable to handle this.
By the way, owning five laptops is not weird. When I was working on a mobile project at my former former company, I had more than ten cellphones, several tablets, and four computers, but of course, nearly all of them did not belong to me but my employer. At that moment, there was no cloud testing platform for mobile projects, so all the tests needed to be processed on local devices.
Let’s get back to the main topic. Luckily most of the peripherals I had were dual mode, which means supporting cable and Bluetooth; this made me figure out a compromised solution. I connected the keyboard, mouse, and display to one multiport adaptor, and I could easily switch this adaptor from the currently connected computer to another chosen one. Since the COVID situation is not so intense, I sometimes need to go to the office. When I need to go to the office, I can unplug the display and put the laptop into my backpack with the adaptor, keyboard, and mouse.
Days ago, one question popped up in my mind. If a device named HDMI switch can switch the video sources smoothly, why is there not a device that can help us conveniently switch the peripherals across the computers? Then I found it, and it is KVM Switch. This KVM is not a Kernel-based Virtual Machine; it is the abbreviation of Keyboard, Video, and Mouse.
A KVM switch (with KVM being an abbreviation for “keyboard, video, and mouse”) is a hardware device that allows a user to control multiple computers from one or more sets of keyboards, video monitors, and mice.
From Wikipedia
KVM Switch Diagram
This switch really saved my life. I don’t need to leverage more than one set of peripherals to cover all my computers or don’t need to plug in and out whenever I switch across my laptops. This switch also makes my desktop tidier, although it is still not quite tidy.
Choose the Suitable KVM Switch
The type of KVM switches varies and is not easy to choose. If you want one, keep an eye on the tech specs, especially the HDMI part.
Confirm the number of devices you would like to switch across.
The type of USB ports. Due to the velocity gap between USB 1 and USB 2, consider it based on your own devices, such as whether you have external high-capacity storage devices or others.
The type of HDMI ports. If you have devices supporting HDMI and Dolby Vision, such as Apple TV and Xbox Series X, please check whether your chosen KVM switch supports this. And HDR has several types of video formats, such as HDR, HDR 10, HDR 10+. The same as audio, its encoding varies.
High resolution and refresh rates are pretty important for video and game enthusiasts.
And also, hot-swapping affects the user experiences a lot.
Hopefully, this small talk can help guys with multiple computers a little.
Statement in advance: this post includes personal account security and credential management, but it is just casual writing that includes some of my boring dailies. 😂 So please kindly do not regard this as a knowledge post.
Obviously, the Internet is becoming an inevitable part of our lives, and accounts are also becoming an unavoidable part of the Internet. Actually, long before, except for the service featuring individuals such as forum, game, E-mail, and game, we could utilize most Internet service providers (ISPs) without an account. The ISPs could use a tiny browser cookie to hold all the anonymous and temporary personalized contents. And at that moment, the ISPs didn’t desire much to dig personal information. 🤣 It was pretty easy to memorize all the credentials because nearly all the credentials are one combination of user name and password or random combinations of several user names and passwords. With the rapid development of the Internet and the growing desire for personal information, we need to create more and more accounts for signing up the ISPs. The more personal information the accounts include, the more cybercriminals target our accounts. So the ISPs issued many restrictions on passwords, and our old-school way didn’t work as well as before.
The password needs updating periodically. – More backup passwords can handle this.
The new password should not be the same as the several previously used passwords. – Fine! Let us prepare several passwords for rotation.
Simple passwords are not allowed. – Cool. It seems we need to prepare several complicated passwords.
The new password should not be the same as all the previously used passwords. – Are you kidding me?
Due to the above, this kind of conversation always happens between my wife and me.
My wife: I need to use XXXX for YYYY.
Myself: You need to signup before using XXXX for YYYY
My wife: Let me check.
One thousand years later…
My wife: It shows that I have already signed up for this before, but I cannot recall the password.
I helped her to retrieve the account and set a new password, then asked her again and again not to forget again. I was definitely sure that she would forget it again.
My wife: How do you memorize so many user names and passwords?
Myself: I cannot recall passwords either, even sometimes can’t recall the usernames…
My wife: So, how do you log in?
Myself: With the help of the password management tool.
My wife: It sounds complicated… Will try when I have time.
Myself 😓 …
This kind of conversation always happens periodically.
As more and more accounts need managing, I really cannot do that without a password management tool now. But I did manage with the rotation of several passwords for a long while because the password management tool was tough to use before:
It couldn’t sync between devices. I should manage all the accounts on a specific device which I called the primary device. Then exported the accounts from the primary device and imported them into other devices. It seems pretty ridiculous in this period when everything can be clouded, but I really did this for quite a long while.
It was not platform-crossed. At that moment, due to the unstable market distribution of web browsers and mobile operating systems, there seem several colossal mountains between Microsoft, Google, and Apple. And it was really hard to seek software that can be compatible with Mac, Linux, Windows, Android, and iOS, also compatible with Chrome and Internet Explorer. Not to mention finding a platform-crossed password management tool.
Terrible user interaction (UI). It was not bad on PC because the tool could automatically fill in the user name and password via a browser extension. But when using it on a cellphone, it was really a nightmare. Can you imagine that the password management tool could only automatically fill in the user name and password when accessing the website with its built-in browser? I was the one that could not stand the build-in browser, so I had to use the copy-and-paste way to input the user name and password from the password management tool. Not to mention that some webmasters forbid copying and pasting on password textbox.
So after I had tried the password management tool for a short while, I reverted to the old-school way of password rotation.
Reading till here, I believe that some guys may wonder why this guy used so many different browsers and operating systems. Not for complicated reasons:
At that moment, my office laptop is Mac. And my personal laptop is running Ubuntu and also Windows due to game compatibility.
Due to the on-call policy, I brought one office cellphone and one personal cellphone. One was an iPhone, and the other one was an Android phone.
Firefox is my favorite web browser, but before, I mostly used Chrome on Mac and Windows, and I used Chromium on Linux. But there are several unavoidable sites, such as bank sites and government sites, that only support disgusting Internet Explorer 6, so sometimes I still had to switch to IE.
Personal Credential Management
Since Chromium is getting more completed and the Firefox is more popular than before, most applications provide extensions for Chrome and Firefox. More and more of them also provide for Edge. Thanks to the Autofill and Accessibility of Android, and the AutoFill Passwords setting of iOS, I completely rushed to the password management tool again. After trying several options, Bitwarden is my final choice because:
It can sync between devices, so I can manage all the accounts on any device.
It provides extensions for Chrome, Chromium, Firefox, and Safari. This totally meets my requirements.
It supports both iOS and Android.
Even though some ISPs leaked the accounts, different passwords for different accounts can significantly prevent credential stuffing.
The free version is good enough.
With the help of the password management tool, when I sign up for an ISP, I can use the password generator to create a complicated password instead of figuring it out by myself. I usually tick all the options to make sure the generated password can meet all the requirements of different ISPs.
Password generator of Bitwarden
When you use the generator to get a password, you can also let Bitwarden save it in its vault automatically. From then on, Bitwarden can help us fill in the user name and password of this ISP account, so we no longer need to memorize the complicated password. This way, the passwords of different accounts are totally different, which can significantly prevent credential stuffing.
Personal Account Security
Password management tools are really helpful but will also lead to a problem. It is that if the Bitwarden account is hacked, does it mean that all the accounts will be hacked? To explain this, we need to break this down into two questions:
How do we minimize the Bitwarden account theft? Because Bitwarden is the portal of all the accounts, we can’t set an extremely complicated password for Bitwarden.
If the Bitwarden account is hacked, how do we ensure all the accounts in the Bitwarden vault can not be easily hacked?
Two-factor authentication (2FA) can help us.
Multi-factor authentication (MFA; encompassing authentication, or 2FA, along with similar terms) is an electronic authentication method in which a user is granted access to a website or application only after successfully presenting two or more pieces of evidence (or factors) to an authentication mechanism: knowledge (something only the user knows), possession (something only the user has), and inherence (something only the user is). MFA protects user data—which may include personal identification or financial assets—from being accessed by an unauthorised third party that may have been able to discover, for example, a single password.
Wikipedia
Based on Wikipedia and above, in a nutshell, besides providing the user name and password, the user needs to provide at least one more piece of evidence before getting access to the account. For example:
OTP SMS. This is quite popular for 2FA, and sometimes it becomes the first authentication method. To be honest, using OTP SMS as the first authentication method without 2FA is really a bad idea. If your phone is lost, someone can take SIM out of your phone, easily get your contact number, and log in to your account with OTP SMS without unlocking your cellphone. So to prevent this, I have enabled SIM lock on all of my SIMs. That is to say that if my cellphone is rebooted or the SIM is put into a new cellphone, the SIM will not work, and the cellphone will show no signal or service. If the PIN has been wrongly input three times, the SIM will be locked unless you can provide a correct PUK or get a new SIM from the carrier.
OTP E-Mail.
OTP generated by authenticator APPs. Microsoft Authenticator and Google Authenticator are the most popular. I recommend the former one because it can sync between devices. Once my cellphone malfunctioned, I could not get the OTP via Google Authenticator to log in to an account containing some important historical information. The support was quite “dedicated” and refused to reset my Authenticator binding, even after I provided my user name, password, E-Mail address, and a list of previous login locations and timelines. 🤦♂️
The recovery codes when binding Authenticator. Please do take note of that unless you can make sure you will not lose the bound Authenticator, or you will face the same issue I mentioned above.
Security keys. I will explain later.
Let’s get back to the first question. How do we minimize the Bitwarden account theft? Enable the 2FA of the Bitwarden account.
The answer to the second question is the same. Enable the 2FA of all the accounts if ISPs support 2FA.
Issues when 2FA is enabled
Conclusion first:
Please ensure you enable at least two different 2FA methods if the ISPs support them.
OTP SMS is quite convenient until you would like to update your contact number. I needed to update my contact number once due to relocation to another city, and I couldn’t recall all the ISPs binding my previous contact number, so I could not update the contact number of all the accounts. Even if I could recall, it would be horrible to update all over again. Now with the help of the password management tool, I can easily list and categorize all my accounts. For example, all the accounts binding my China contact number are sorted out; all binding my Singapore contact number are in another category, all binding security keys are sorted out, etc. Also, I activated at least two 2FA methods to ensure I don’t need to update all the account security settings immediately.
Try not to use commonly changing 2FA methods, such as contact numbers. Instead, I prefer E-Mail and security keys.
If commonly changing 2FA methods are not avoidable, make sure you have a backup method. Mainly I bind two contact numbers on my essential accounts. Significantly I bind two if security key authentication is enabled because security keys cannot be duplicated in a usual way. I take one with me and put one in a safe.
Security Key
Mentioning security keys, it was back to my university days. The bank industry was really backward, so online and mobile payments were unavailable yet, and even credit cards were not expected. We should pay via cash nearly everywhere.
Nearly by the end of my university life, several banks, such as CMB, released the online payment and online transferring. But the processes were really complicated. Whenever I would like to do this, I had to meet four requirements:
Windows OS. So I had to install a Windows virtual PC on my MacBook.
One management software that the bank provides, and it only supports Windows OS.
Internet Explorer. Because the bank password input component is an ActiveX controller that only supports IE.
One Dongle named U Key can only be used to operate bank accounts.
Due to the complexity of the operation and lack of requirements, I mostly prefer doing the transfer via ATM. And due to low utilization, I lost the U key twice when I moved to a new dormitory or accommodation. If I would like to apply for a new one, I needed to apply to disable the lost one first. The application for a new one could only be processed 24 hours after the application to disable. It meant I needed to bring lots of documents to the bank twice. Terrible!
I updated my contact number again after arriving in Singapore. And this made me think about trying a security key again. It looks amazing that there are tens of security keys supporting Universal 2nd Factor (U2F). Supporting U2F means that I use one security key as the 2FA method for nearly all my accounts and don’t need to assign each account a different key. Finally, I chose YubiKey after going through lots of reviews. If you have difficulties selecting a suitable model of YubiKey, you can use this chooser provided officially. 😂 You can also choose an appropriate security key from the list above.
The chooser that provided by Yubico officially.
If you would like to use a security key to authenticate on your cellphone, please choose the NFC model. Because most apps can now read security keys via NFC, you can simply tap your key on the back of the cellphone to authenticate.
One tip. If you choose the NFC model, I highly recommend using this kind of steel cable keychains as below. If you still use the common hard steel ring keychain, it will affect the NFC reading of the cellphone because the keychain will block the key totally adhering to the back of the cellphone.
Steal cable keychains
As a security key, its ability is far beyond account login. For example:
It can authenticate the PC login, that is to say, that you need to plug in the key to finish the login after starting the PC. After all, the theft of thesis and dissertation is not rare anymore. Of course, if your document is important enough to enable the security key for the PC login, don’t forget to encrypt your disk in case someone takes your hard disk out of your PC. 😂
With an NFC module and a digital lock supporting open source home automation, you can use a security key to unlock the door.
Of course, we can also use an outdated NFC-supported cellphone as an NFC reading module to create more exciting ideas with an open-source home automation application.
It can manage your GPG key for passwordless SSH login and passwordless Github repo operations.
The above is just to throw a brick, and you can dig more.
I may believe that most computers contain unique customizations, which may be why most people hate reinstalling the operating systems or setting up a new computer.
Such as my laptop, there are a bunch of tools that improve my experience using a computer. Here is a non-exhaustive list:
Can easily attach the windows to the sides or corners of the screen. If the screen is big enough, you may put the documentation on the left and IDE on the right.
Pap.er
It can periodically and automatically set a beautiful sightseeing image as your wallpaper.
Besides improving my experience in using a computer, these tools also cause a few inconveniences, especially when I need to reinstall the OS and set up a new laptop. I have to look for an alternative because sometimes one is no longer free of charge, or sometimes one no longer supports the latest OS. This didn’t bother me much until I changed my Macbook Pro thrice in half a year. So I tried to find a way to minimize the number of tools I relied on, and I found Hammerspoon. I can say this is really a Swiss Army Knife on macOS.
Actually, there are some similar tools, but Hammerspoon finds the best balance between usage simplicity and functionality complexity. The users only need a little knowledge of Lua before customizing with Hammerspoon. Under the situation of no experience in Lua, I quickly finished the customizing based on the official documentation.
We can customize with the official spoons, such as windows manipulation.
-- We can quickly implement this with the WinWin spoon
hs.loadSpoon("WinWin")
-- Check whether WinWin is loaded and bind hotkeys to different directions.
if spoon.WinWin then
-- Supporting symbol characters in the message of Hammerspoon is quite helpful. We will talk about this later. I will talk about this later.
-- Side
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "left", "Window ⬅", function()spoon.WinWin:moveAndResize("halfleft")end)
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "right", "Window ➡", function() spoon.WinWin:moveAndResize("halfright") end)hs.hotkey.bind({"cmd", "alt", "ctrl"}, "up", "Window ⬆", function() spoon.WinWin:moveAndResize("halfup") end)hs.hotkey.bind({"cmd", "alt", "ctrl"}, "down", "Window ⬇", function() spoon.WinWin:moveAndResize("halfdown") end)
-- Cornerhs.hotkey.bind({"shift", "alt", "ctrl"}, "left", "Window ↖", function() spoon.WinWin:moveAndResize("cornerNW") end)hs.hotkey.bind({"shift", "alt", "ctrl"}, "right", "Window ↘", function() spoon.WinWin:moveAndResize("cornerSE") end)hs.hotkey.bind({"shift", "alt", "ctrl"}, "up", "Window ↗", function() spoon.WinWin:moveAndResize("cornerNE") end)hs.hotkey.bind({"shift", "alt", "ctrl"}, "down", "Window ↙", function() spoon.WinWin:moveAndResize("cornerSW") end)
-- Stretchhs.hotkey.bind({"cmd", "alt", "ctrl"}, "C", "Window Center", function() spoon.WinWin:moveAndResize("center") end)hs.hotkey.bind({"cmd", "alt", "ctrl"}, "M", "Window ↕↔", function() spoon.WinWin:moveAndResize("maximize") end)
-- Screenhs.hotkey.bind({"alt", "ctrl"}, "right", "Window ➡ 🖥", function() spoon.WinWin:moveToScreen("next") end)
-- Otherhs.hotkey.bind({"cmd", "alt", "ctrl"}, "/", "Window Undo", function() spoon.WinWin:undo() end)endCode language:PHP(php)
It is pretty easy, right? Only several hotkey bindings to functionality are enough.
We can also create spoons with the API, such as BreakTime.
To implement this, we need to periodically use a page or image to cover the whole screen to make the guys in front of the PC take a rest.
Firstly, we can quickly start a timer with hs.timer:
Load the BreakTime spoon in the same way to load the WinWin spoon, and start it. Done!
We can also customize the taskbar menu to improve the user experience.
Take BreakTime as an example. We can show the timeline of the next break.
BreakTime’s Menu
Besides this, we can also show all the hotkeys defined with Hammerspoon.
Menu showing all the hotkeys
Hammerspoon supports symbol characters quite well, so users can make the menu items more attractive. Isn’t this amazing? 😄
obj.menubar:setTitle("⌨️")
obj.menubar:setTooltip("Hot Key Info")
local hotkeys = hs.hotkey.getHotkeys()
local menuItem = {}
for key, value in pairs(hotkeys) do
local item = { title = value["msg"] }
table.insert(menuItem, item)
end
obj.menubar:setMenu(menuItem)Code language:JavaScript(javascript)
Besides all the above, Hammerspoon still has much that needs going through. I am also keeping going through to make my customization more additional. Here’s mine.
BTW, not only reinstalling these tools, but I also need to reinstall all of the common applications such as VS Code, Plex, Sublime Text, VIM, etc. This is also terrible. Now I am maintaining a tap list containing the applications with homebrew. 😂