<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Tag: linux - blog.dotcs.me</title>
  <link href="https://blog.dotcs.me/feeds/tags/linux.xml" rel="self" type="application/atom+xml"/>
  <link href="https://blog.dotcs.me/tags/linux" rel="alternate" type="text/html"/>
  <updated>2024-12-18T18:34:21.145Z</updated>
  <author>
    <name>dotcs</name>
  </author>
  <id>https://blog.dotcs.me/feeds/tags/linux.xml</id>
  <entry>
    <title>Copy large files to Nextcloud</title>
    <published>2021-01-02T16:49:22+01:00</published>
    <updated>2021-01-02T19:35:57+01:00</updated>
    <id>https://blog.dotcs.me/posts/nextcloud-copy-large-files</id>
    <link href="https://blog.dotcs.me/posts/nextcloud-copy-large-files"/>
    <summary>Copying large files to Nextcloud can be time consuming as a lot overhead is involved in passing the files through the LAMP stack. This blog post shows how files can be copied directly in the underlying file system and how Nextcloud's caches can be invalidated to inform Nextcloud about the new files.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/nextcloud-copy-large-files">&lt;p&gt;I'm running my own Nextcloud instance in a &lt;a href="https://hub.docker.com/_/nextcloud/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;docker container&lt;/a&gt; with the &lt;code&gt;data&lt;/code&gt; directory mounted from a local folder on my disk.
Unfortuantely it's not very satisfying to use the web UI or using a &lt;a href="https://docs.nextcloud.com/server/16/user_manual/files/access_webdav.html"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;davfs2 mount&lt;/a&gt; of the disk to copy large files to the Nextcloud instance.
This is because files must be passed through the full &lt;a href="https://en.wikipedia.org/wiki/LAMP_%28software_bundle%29"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;LAMP stack&lt;/a&gt; which involves a lot overhead and slows down any large file uploads.&lt;/p&gt;
&lt;p&gt;An alternative to upload files via the browser or WebDAV is to copy them directly into the user data folder and then force Nextcloud to sync the content with its internal file cache and database entries.&lt;/p&gt;
&lt;p&gt;Say our Nextcloud instance data lives in &lt;code&gt;/opt/nextcloud/data&lt;/code&gt; and our source files live in &lt;code&gt;/tmp/stage&lt;/code&gt; on the server.
Further let the Nextcloud username be &lt;code&gt;my-user&lt;/code&gt; and say the source data should be copied to &lt;code&gt;~/my-folder&lt;/code&gt; in Nextcloud.&lt;/p&gt;
&lt;p&gt;Copying the data would then look like this:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-comment"&gt;# copy files&lt;/span&gt;
rsync -avP /tmp/stage/ /opt/nextcloud/data/my-user/files/my-folder/
&lt;span class="hljs-comment"&gt;# fix permissions&lt;/span&gt;
chmod www-data:www-data /opt/nextcloud/data/my-user/files/my-folder
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's necessary to fix the permissions since the &lt;a href="https://github.com/nextcloud/docker/blob/b23910be9215f8338aee419007feb70cdacb7741/20.0/apache/entrypoint.sh#L16"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;default user&lt;/a&gt; in the &lt;a href="https://hub.docker.com/_/nextcloud/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;official Nextcloud docker images&lt;/a&gt; is the &lt;code&gt;www-data&lt;/code&gt; user.
See also the &lt;a href="https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/occ_command.html#file-operations"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Nextcloud documentation&lt;/a&gt;.
Details:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; docker-compose &lt;span class="hljs-built_in"&gt;exec&lt;/span&gt; nextcloud id www-data&lt;/span&gt;
uid=33(www-data) gid=33(www-data) groups=33(www-data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the files have been copied, Nextcloud must be forced to re-index all files within this directory:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; docker-compose &lt;span class="hljs-built_in"&gt;exec&lt;/span&gt; -u www-data nextcloud ./occ files:scan --path=&lt;span class="hljs-string"&gt;&amp;quot;/my-user/files/my-folder&amp;quot;&lt;/span&gt;&lt;/span&gt;
Starting scan for user 1 out of 1 (my-user)
+---------+-------+--------------+
| Folders | Files | Elapsed time |
+---------+-------+--------------+
| 6       | 354   | 00:00:01     |
+---------+-------+--------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The internal database and caches have been updated and your files will pop up in the web UI afterwards.&lt;/p&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="nextcloud"/>
    <category term="notes"/>
    <category term="tech"/>
  </entry>
  <entry>
    <title>Privacy and Audible Audiobooks</title>
    <published>2020-12-30T22:46:05+01:00</published>
    <updated>2021-01-07T11:38:05+01:00</updated>
    <id>https://blog.dotcs.me/posts/audible-audiobooks-privacy</id>
    <link href="https://blog.dotcs.me/posts/audible-audiobooks-privacy"/>
    <summary>This article mentions privacy concerns of the Amazon Audible platform and discusses how to prevent a lock-in into Amazon's apps in order to gain more privacy.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/audible-audiobooks-privacy">&lt;p&gt;Audible has a lot books available as audiobooks and I think a price of about 10 EUR per book is more than justified.
But unfortunately Audible locks people into their own ecosystem.
Users must use the official Audible app(s) to download and listen to the purchased books.
To my knowledge third party software is not supported.
This has a lot to do with digital right managment (DRM) of course, but the situation also plays into Amazon's cards.
By locking the people into a certain app they can analyze how people listen to the audiobooks.
For example they could answer the following questions about you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which are the audiobooks that you listen to?&lt;/li&gt;
&lt;li&gt;Which audiobooks have you started to hear? Which of them have you finished? Which have you rejected?&lt;/li&gt;
&lt;li&gt;Which chapters have you re-read? Which parts have you skipped?&lt;/li&gt;
&lt;li&gt;and so on&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From their privacy information details:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Automatic information we collect and analyze include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[...]&lt;/li&gt;
&lt;li&gt;content interaction information, such as &lt;strong&gt;content downloads, streams, playback details&lt;/strong&gt;, &lt;strong&gt;listening behavior like start and stop points&lt;/strong&gt;, &lt;strong&gt;listening duration&lt;/strong&gt;, reading behavior on your Kindle devices and apps (so we can provide our WhisperSync for Voice functionality &lt;strong&gt;and award badges based on your listening&lt;/strong&gt; and also calculate royalties), and network details for streaming and download quality, including information about your internet service provider;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;small&gt;&lt;a href="https://help.audible.com/s/article/audible-privacy-information?language=en_US"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Audible Privacy Information&lt;/a&gt;, relevant text has been highlighted by me&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm wondering if those award badges are mainly there so that Amazon can argue about any privacy concerns that people might have.
At least for me they are not important at all, I would prefer a tracking-free Audible variant and would gladly waive the badges for this.&lt;/p&gt;
&lt;p&gt;While it's not possible to prevent Amazon from tracking which Audiobooks are bought, it is possible to stop them from tracking HOW you read them.
Let's see how this can be done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;:
This approach breaks the DRM protection of the Audiobooks.
Please make sure that this is legal in your country for the intended purpose.&lt;/p&gt;
&lt;h2 id="downloading-audiobooks"&gt;&lt;a class="markdownIt-Anchor" href="#downloading-audiobooks"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Downloading Audiobooks&lt;/h2&gt;
&lt;p&gt;Audiobooks that you have bought from Audible can be downloaded from your &lt;a href="https://www.audible.de/library/titles"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;library&lt;/a&gt;.
Execute this script in your &lt;a href="https://developer.mozilla.org/en-US/docs/Tools/Browser_Console"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;browser's console&lt;/a&gt; to copy all relevant download links into the clipboard.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; links = &lt;span class="hljs-built_in"&gt;Array&lt;/span&gt;.from(&lt;span class="hljs-built_in"&gt;document&lt;/span&gt;.querySelectorAll(&lt;span class="hljs-string"&gt;&amp;#x27;.adbl-lib-action-download &amp;gt; a[href^=&amp;quot;https://cds.audible.de/download&amp;quot;]&amp;#x27;&lt;/span&gt;))
    .map(&lt;span class="hljs-function"&gt;&lt;span class="hljs-params"&gt;el&lt;/span&gt; =&amp;gt;&lt;/span&gt; el.attributes[&lt;span class="hljs-string"&gt;&amp;#x27;href&amp;#x27;&lt;/span&gt;].nodeValue);
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; titles = &lt;span class="hljs-built_in"&gt;Array&lt;/span&gt;.from(&lt;span class="hljs-built_in"&gt;document&lt;/span&gt;.querySelectorAll(&lt;span class="hljs-string"&gt;&amp;#x27;#adbl-library-content-main .bc-list a.bc-link[href^=&amp;quot;/pd&amp;quot;]&amp;#x27;&lt;/span&gt;))
    .map(&lt;span class="hljs-function"&gt;&lt;span class="hljs-params"&gt;el&lt;/span&gt; =&amp;gt;&lt;/span&gt; el.innerText);

&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; data = links.map(&lt;span class="hljs-function"&gt;(&lt;span class="hljs-params"&gt;href, i&lt;/span&gt;) =&amp;gt;&lt;/span&gt; ({ href, &lt;span class="hljs-attr"&gt;title&lt;/span&gt;: titles[i]}));
copy(data);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a valid JSON object in your clipboard which contains a list of records with the keys &lt;code&gt;href&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt; for each audiobook.
&lt;strong&gt;Don't share the document with anyone as the download links contain your private key.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;wl-paste &amp;gt; /tmp/audible.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I'm using the &lt;a href="https://github.com/bugaevc/wl-clipboard"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;wl-paste&lt;/a&gt; (wayland only) command to get the content from the system's clipboard.
If you're using X11 you might want to replace &lt;code&gt;wl-paste&lt;/code&gt; with &lt;code&gt;xsel&lt;/code&gt; or whatever you have installed.
In a second I will also use &lt;a href="https://stedolan.github.io/jq/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;jq&lt;/a&gt; to filter the JSON file, make sure to install it also.&lt;/p&gt;
&lt;p&gt;If everything worked out, the temporary file you have created should look like this:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;[
  {
    &lt;span class="hljs-attr"&gt;&amp;quot;href&amp;quot;&lt;/span&gt;: &lt;span class="hljs-string"&gt;&amp;quot;https://cds.audible.de/download?asin=B08KQJ469F&amp;amp;cust_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&amp;amp;codec=LC_128_44100_Stereo&amp;amp;source=Audible&amp;amp;type=AUDI&amp;quot;&lt;/span&gt;,
    &lt;span class="hljs-attr"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;: &lt;span class="hljs-string"&gt;&amp;quot;Stille Nacht in der Provence&amp;quot;&lt;/span&gt;
  },
  &lt;span class="hljs-comment"&gt;// ....&lt;/span&gt;
]
&lt;/code&gt;&lt;/pre&gt;
&lt;small&gt;
&lt;p&gt;Note that the param &lt;code&gt;asin&lt;/code&gt; in the link refers to the book and &lt;code&gt;cust_id&lt;/code&gt; is a customer specific identifier that gives access to the book and should not be shared with anyone.&lt;/p&gt;
&lt;/small&gt;
&lt;p&gt;Now let's kick off &lt;code&gt;wget&lt;/code&gt; and download our audiobooks.
Please note that audiobooks are large (~1-2GB per file).
Make sure that you have enough storage available.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;mkdir -p /tmp/audible &amp;amp;&amp;amp; &lt;span class="hljs-built_in"&gt;cd&lt;/span&gt; &lt;span class="hljs-variable"&gt;$_&lt;/span&gt;

jq -c &lt;span class="hljs-string"&gt;&amp;#x27;.[]&amp;#x27;&lt;/span&gt; /tmp/audible.json | &lt;span class="hljs-keyword"&gt;while&lt;/span&gt; &lt;span class="hljs-built_in"&gt;read&lt;/span&gt; i; &lt;span class="hljs-keyword"&gt;do&lt;/span&gt;
    href=$(&lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; &lt;span class="hljs-variable"&gt;$i&lt;/span&gt; | jq -r &lt;span class="hljs-string"&gt;&amp;#x27;.href&amp;#x27;&lt;/span&gt;)
    title=$(&lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; &lt;span class="hljs-variable"&gt;$i&lt;/span&gt; | jq -r &lt;span class="hljs-string"&gt;&amp;#x27;.title&amp;#x27;&lt;/span&gt;)
    wget -O &lt;span class="hljs-string"&gt;&amp;quot;&lt;span class="hljs-variable"&gt;$title&lt;/span&gt;.aax&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;&lt;span class="hljs-variable"&gt;$href&lt;/span&gt;&amp;quot;&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;small&gt;
&lt;p&gt;In case you want to download the audiobooks in chunks you can also use &lt;a href="https://www.systutorials.com/docs/linux/man/1-jq/#lbBX"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;jq ranges&lt;/a&gt;, e.g. &lt;code&gt;jq -c '.[:3]'&lt;/code&gt;.&lt;/p&gt;
&lt;/small&gt;
&lt;p&gt;This will place all your audiobooks as &lt;code&gt;*.aax&lt;/code&gt; files in the &lt;code&gt;/tmp/audible&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: If you have a lot audiobooks you might want to consider a different approach that parallelizes the download queries.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="convert-from-aax-to-m4a"&gt;&lt;a class="markdownIt-Anchor" href="#convert-from-aax-to-m4a"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Convert from aax to m4a&lt;/h2&gt;
&lt;p&gt;The files contain a DRM protection which prevents users from sharing the files with others.
In this step you will remove the DRM protection.
&lt;strong&gt;Please make sure that this step is allowed by law in your country before proceeding.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To remove the DRM protection &lt;a href="https://github.com/ryanfb/docker_inaudible_rainbowcrack"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;this respository&lt;/a&gt; can be used.
It contains a docker file that comes pre-installed with all dependencies to break the DRM encryption and decrypt the files.
Make sure to have &lt;a href="https://docs.docker.com/get-docker/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;docker&lt;/a&gt; pre-installed to be able to follow the next steps.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;mkdir -p /tmp/inaudible &amp;amp;&amp;amp; &lt;span class="hljs-variable"&gt;$_&lt;/span&gt;
git &lt;span class="hljs-built_in"&gt;clone&lt;/span&gt; https://github.com/ryanfb/docker_inaudible_rainbowcrack .
docker build -t inaudible .

&lt;span class="hljs-built_in"&gt;cd&lt;/span&gt; /tmp/audible
docker run --rm -v $(&lt;span class="hljs-built_in"&gt;pwd&lt;/span&gt;):/data inaudible
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will read in all aax files, restore the encryption key via brute-force and then decrypt all aax files.
The result will be one m4a and one png artwork file for each aax file.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note that this will take additional storage on your disk - approximately the same amount that is needed for the aax files.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="listen-on-android"&gt;&lt;a class="markdownIt-Anchor" href="#listen-on-android"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Listen on Android&lt;/h2&gt;
&lt;p&gt;To listen to m4a files from an Android device I can highly recommend the &lt;a href="https://f-droid.org/en/packages/de.ph1b.audiobook/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Voice&lt;/a&gt; app from the F-Droid store.
The interface is super clean, the application remembers the playback location and simply does its job - without tracking the user's behavior.
Kudos to Paul Woitaschek for this piece of software!&lt;/p&gt;
&lt;p&gt;Upload both, the m4a and png artwork file, to a folder on your device and add this folder to the list of folders that are scanned by Voice and you're done.&lt;/p&gt;
&lt;h2 id="mission-completed"&gt;&lt;a class="markdownIt-Anchor" href="#mission-completed"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Mission completed 🥳&lt;/h2&gt;
&lt;p&gt;So these few steps allow you to create a private copy of the audiobooks that you own.
By using m4a files it's up to you to choose what player you want to use.
Using an open source player such as &lt;a href="https://f-droid.org/en/packages/de.ph1b.audiobook/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Voice&lt;/a&gt; helps to be sure that noone is tracking how you read your books.
Let's take our privacy back - step by step.&lt;/p&gt;
&lt;p&gt;Oh and since award badges seem to be relevant these days, here is your nerds-love-privacy badge&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 4em;"&gt;🤓&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Have fun with it or throw it away, I don't care.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;:
Oh, and if you're interested in an ETL pipeline that integrates well with a Nextcloud instance to serve the &lt;code&gt;m4a&lt;/code&gt; files, have a look into &lt;a href="https://git.home.dotcs.me/dotcs/audible-nextcloud-etl"&gt;this repository&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="drm"/>
    <category term="linux"/>
    <category term="tech"/>
  </entry>
  <entry>
    <title>Migrate from i3 to sway</title>
    <published>2020-11-15T09:52:00Z</published>
    <updated>2020-11-28T21:27:00+01:00</updated>
    <id>https://blog.dotcs.me/posts/migrate-from-i3-to-sway</id>
    <link href="https://blog.dotcs.me/posts/migrate-from-i3-to-sway"/>
    <summary>This post describes my migration from i3 (X.org Server) to Sway (Wayland).</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/migrate-from-i3-to-sway">&lt;p&gt;I recently changed from the Linux display server protocol &lt;a href="https://en.wikipedia.org/wiki/X.Org_Server"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;X.org Server&lt;/a&gt; to &lt;a href="https://en.wikipedia.org/wiki/Wayland_(display_server_protocol)"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Wayland&lt;/a&gt; on one of my machines.
My favorite window manager &lt;a href="https://i3wm.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;i3&lt;/a&gt; is not compatible with Wayland though, so I had to search for an alternative.
Luckily there is a drop-in replacement for i3 available which is named &lt;a href="https://swaywm.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Sway&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sway is very similar to i3, it even uses the same syntax for the config, so the change required only a few tweaks which I will now talk about.
I can also recommend to read the &lt;a href="https://wiki.archlinux.org/index.php/Sway"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Sway article on the Arch Wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At this let's take a brief moment to say &amp;quot;Thank you&amp;quot; to all contributors of Sway and Wayland and maintainers of the corresponding packages in the various distros out there. ♥&lt;/p&gt;
&lt;h2 id="installation"&gt;&lt;a class="markdownIt-Anchor" href="#installation"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Installation&lt;/h2&gt;
&lt;p&gt;Installation of sway under Arch Linux is easy.
It's as simple as:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;yay -S sway
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="copy-configuration"&gt;&lt;a class="markdownIt-Anchor" href="#copy-configuration"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Copy configuration&lt;/h2&gt;
&lt;p&gt;Sway searches it's configuration in &lt;code&gt;~/.config/sway/config&lt;/code&gt; so I copied my i3 config there.
All changes go into this config file.&lt;/p&gt;
&lt;h2 id="adjust-configuration"&gt;&lt;a class="markdownIt-Anchor" href="#adjust-configuration"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Adjust configuration&lt;/h2&gt;
&lt;p&gt;After the configuration has been copied use a separate TTY to try our sway and its configuration.
Remember that &lt;code&gt;&amp;lt;SUPER&amp;gt; + SHIFT + c&lt;/code&gt; does reload your configuration which is quite handy for trying things out.
Also &lt;code&gt;swaymsg&lt;/code&gt; can be used to send messages to sway, so for example the following command would set the scaling 2 for all output devices.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;swaymsg output &amp;quot;*&amp;quot; scale 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="screen-output-resolution"&gt;&lt;a class="markdownIt-Anchor" href="#screen-output-resolution"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Screen output resolution&lt;/h3&gt;
&lt;p&gt;I'm working with a HiDPI screen which was detected correctly in Sway.
But I found the scaling factor of 2, which is the default in HiDPI screens, too much.
Although it's not recommended to use float values here, I found a scaling factor of 1.3 to fit my needs, so I added this line to my config:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;# Screen scaling (default is 2)
output eDP-1 scale 1.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To list connected displays use &lt;code&gt;swaymsg -t get_outputs&lt;/code&gt; which in my case now (after the change) shows as:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; swaymsg -t get_outputs   &lt;/span&gt;
Output eDP-1 &amp;#x27;Apple Computer Inc Color LCD 0x00000000&amp;#x27; (focused)
  Current mode: 2560x1600 @ 59.972000 Hz
  Position: 0,0
  Scale factor: 1.300000
  Scale filter: linear
  Subpixel hinting: unknown
  Transform: normal
  Workspace: 4
  Max render time: off
  Adaptive sync: disabled
  Available modes:
    2560x1600 @ 59.972000 Hz
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="background-images-with-automatic-rotation"&gt;&lt;a class="markdownIt-Anchor" href="#background-images-with-automatic-rotation"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Background images with automatic rotation&lt;/h3&gt;
&lt;p&gt;I like to have randomly chosen background images that change every now and then.
Sway makes it easy to implement this.
I added the following line to my config which executes a script during start.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;exec --no-startup-id ~/.local/scripts/sway-rotate-bg-image.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script itself doesn't do much.
It lists all files in a certain folder, shuffles the names and selects one of them.
It updates the background on all attached displays image via &lt;code&gt;swaymsg&lt;/code&gt; and then pauses for 300 seconds (=5min) before the next iteration.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;#!/usr/bin/env bash&lt;/span&gt;
IMG_DIR=~/wallpapers
&lt;span class="hljs-keyword"&gt;while&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;;
&lt;span class="hljs-keyword"&gt;do&lt;/span&gt;
    IMG=`ls -t1 &lt;span class="hljs-variable"&gt;$IMG_DIR&lt;/span&gt;/* | shuf | head -n 1`
    swaymsg output &lt;span class="hljs-string"&gt;&amp;quot;*&amp;quot;&lt;/span&gt; &lt;span class="hljs-built_in"&gt;bg&lt;/span&gt; &lt;span class="hljs-variable"&gt;$IMG&lt;/span&gt; fill; sleep 300
&lt;span class="hljs-keyword"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="detect-idle-state-and-lock-screen"&gt;&lt;a class="markdownIt-Anchor" href="#detect-idle-state-and-lock-screen"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Detect idle state and lock screen&lt;/h3&gt;
&lt;p&gt;To automatically lock the screen there are luckily two programs available that do the heavy-lifting.
They are called swayidle and swaylock and can be installed in Arch via:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;yay -S swayidle swaylock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following script is taken from the &lt;code&gt;swayidle&lt;/code&gt; manpage:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This will lock your screen after 300 seconds of inactivity, then turn off your displays after another 300 seconds, and turn your screens back on when resumed. It will also lock your screen before your computer goes to sleep.&lt;/p&gt;
&lt;p&gt;To make sure swayidle waits for swaylock to lock the screen before it releases the inhibition lock, the -w options is used in swayidle, and -f in swaylock.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;exec --no-startup-id swayidle -w \
    timeout 300 'swaylock -f -c 000000' \
    timeout 600 'swaymsg &amp;quot;output * dpms off&amp;quot;' \
    resume 'swaymsg &amp;quot;output * dpms on&amp;quot;' \
    before-sleep 'swaylock -f -c 000000'
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="screen-backlight-keys"&gt;&lt;a class="markdownIt-Anchor" href="#screen-backlight-keys"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Screen backlight keys&lt;/h3&gt;
&lt;p&gt;In my i3 setup I used &lt;code&gt;xbacklight&lt;/code&gt; to change the backlight of my screen.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;bindsym XF86MonBrightnessUp exec xbacklight +10
bindsym XF86MonBrightnessDown exec xbacklight -10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This of course won't work anymore in Wayland, so I replaced the old configuration with &lt;code&gt;brightnessctl&lt;/code&gt; which needs to be installed first:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;yay -S brightnessctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The syntax of &lt;code&gt;brightnessctrl&lt;/code&gt; differs slightly:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;bindsym XF86MonBrightnessDown exec brightnessctl set 5%-
bindsym XF86MonBrightnessUp exec brightnessctl set +5%
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="keyboard-bindings"&gt;&lt;a class="markdownIt-Anchor" href="#keyboard-bindings"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Keyboard bindings&lt;/h3&gt;
&lt;p&gt;For me one key on the keyboard is completely superfluous: capslock.
In my systems I either deactivate this key or map it to ESC if possible.
Having ESC closer to the home row is benefitial to me - especially when working a lot with vim.
This can done with xkb_options.&lt;/p&gt;
&lt;p&gt;Another interesting setting is the key repeat delay and rate, which can be tuned also quite easily.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;input &amp;quot;type:keyboard&amp;quot; {
    # Capslock key should work as escape key
    xkb_options caps:escape

    repeat_delay 350
    repeat_rate 45
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="ssh-agent"&gt;&lt;a class="markdownIt-Anchor" href="#ssh-agent"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; SSH Agent&lt;/h3&gt;
&lt;p&gt;To automatically start the SSH agent I use a systemd service which is placed in &lt;code&gt;~/.config/systemd/user/ssh-agent.service&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-section"&gt;[Unit]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Description&lt;/span&gt;=SSH key agent

&lt;span class="hljs-section"&gt;[Service]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Type&lt;/span&gt;=simple
&lt;span class="hljs-attr"&gt;Environment&lt;/span&gt;=SSH_AUTH_SOCK=%t/ssh-agent.socket
&lt;span class="hljs-comment"&gt;# DISPLAY required for ssh-askpass to work&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Environment&lt;/span&gt;=DISPLAY=:&lt;span class="hljs-number"&gt;0&lt;/span&gt;
&lt;span class="hljs-attr"&gt;ExecStart&lt;/span&gt;=/usr/bin/ssh-agent -D -a &lt;span class="hljs-variable"&gt;$SSH_AUTH_SOCK&lt;/span&gt;

&lt;span class="hljs-section"&gt;[Install]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;WantedBy&lt;/span&gt;=default.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also configure the pam environment in &lt;code&gt;~/.pam_environment&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;SSH_AUTH_SOCK DEFAULT=&lt;span class="hljs-string"&gt;&amp;quot;&lt;span class="hljs-variable"&gt;${XDG_RUNTIME_DIR}&lt;/span&gt;/ssh-agent.socket&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then start the service and enable it for future system starts: &lt;code&gt;systemctl --user enable --now ssh-agent.service&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="exit-script"&gt;&lt;a class="markdownIt-Anchor" href="#exit-script"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Exit script&lt;/h3&gt;
&lt;p&gt;Finally I updated my exit script that allows me to lock my screen, suspend, shutdown or reboot my machine, etc.&lt;/p&gt;
&lt;p&gt;The Sway configuration looks as this&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;set $mode_system System (1) lock, (e) logout, (s) suspend, (h) hibernate, (r) reboot, (d) shutdown
mode &amp;quot;$mode_system&amp;quot; {
    bindsym l exec --no-startup-id ~/.local/scripts/sway-exit.sh lock, mode &amp;quot;default&amp;quot;
    bindsym e exec --no-startup-id ~/.local/scripts/sway-exit.sh logout, mode &amp;quot;default&amp;quot;
    bindsym s exec --no-startup-id ~/.local/scripts/sway-exit.sh suspend, mode &amp;quot;default&amp;quot;
    bindsym h exec --no-startup-id ~/.local/scripts/sway-exit.sh hibernate, mode &amp;quot;default&amp;quot;
    bindsym r exec --no-startup-id ~/.local/scripts/sway-exit.sh reboot, mode &amp;quot;default&amp;quot;
    bindsym d exec --no-startup-id ~/.local/scripts/sway-exit.sh shutdown, mode &amp;quot;default&amp;quot;
    # back to normal: Enter or Escape
    bindsym Return mode &amp;quot;default&amp;quot;
    bindsym Escape mode &amp;quot;default&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which utilizes the script located in &lt;code&gt;~/.local/scripts/sway-exit.sh&lt;/code&gt;&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-title"&gt;lock&lt;/span&gt;&lt;/span&gt;() {
    swaylock -f -c 000000
}

&lt;span class="hljs-keyword"&gt;case&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;&lt;span class="hljs-variable"&gt;$1&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
    lock)
        lock
        ;;
    &lt;span class="hljs-built_in"&gt;logout&lt;/span&gt;)
        swaymsg &lt;span class="hljs-built_in"&gt;exit&lt;/span&gt;
        ;;
    &lt;span class="hljs-built_in"&gt;suspend&lt;/span&gt;)
        lock &amp;amp;&amp;amp; systemctl &lt;span class="hljs-built_in"&gt;suspend&lt;/span&gt;
        ;;
    hibernate)
        lock &amp;amp;&amp;amp; systemctl hibernate
        ;;
    reboot)
        systemctl reboot
        ;;
    shutdown)
        systemctl poweroff
        ;;
    *)
        &lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;Usage: &lt;span class="hljs-variable"&gt;$0&lt;/span&gt; {lock|logout|suspend|hibernate|reboot|shutdown}&amp;quot;&lt;/span&gt;
        &lt;span class="hljs-built_in"&gt;exit&lt;/span&gt; 2
&lt;span class="hljs-keyword"&gt;esac&lt;/span&gt;

&lt;span class="hljs-built_in"&gt;exit&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="notifications"&gt;&lt;a class="markdownIt-Anchor" href="#notifications"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Notifications&lt;/h3&gt;
&lt;p&gt;In i3 I used &lt;a href="https://dunst-project.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;dunst&lt;/a&gt; to handle notifications.
Unfortunately it's not &lt;a href="https://github.com/dunst-project/dunst/issues/264"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;yet ready&lt;/a&gt; to work with wayland.
I found &lt;a href="https://github.com/emersion/mako"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;mako&lt;/a&gt; to be a good replacement.&lt;br&gt;
Using &lt;code&gt;mako&lt;/code&gt; is dead simple.
After installation an additional line &lt;code&gt;exec mako&lt;/code&gt; in the sway config file does the job.&lt;/p&gt;
&lt;h3 id="printer"&gt;&lt;a class="markdownIt-Anchor" href="#printer"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Printer&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://wiki.archlinux.org/index.php/CUPS"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;CUPS&lt;/a&gt; was not properly started after the switch.
What helped was to create the following configuration in &lt;code&gt;/etc/systemd/system/cups.socket&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-section"&gt;[Unit]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Description&lt;/span&gt;=CUPS Printing Service Sockets

&lt;span class="hljs-section"&gt;[Socket]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;ListenStream&lt;/span&gt;=/var/run/cups/cups.sock
&lt;span class="hljs-attr"&gt;ListenStream&lt;/span&gt;=&lt;span class="hljs-number"&gt;0.0&lt;/span&gt;.&lt;span class="hljs-number"&gt;0.0&lt;/span&gt;:&lt;span class="hljs-number"&gt;631&lt;/span&gt;
&lt;span class="hljs-attr"&gt;ListenDatagram&lt;/span&gt;=&lt;span class="hljs-number"&gt;0.0&lt;/span&gt;.&lt;span class="hljs-number"&gt;0.0&lt;/span&gt;:&lt;span class="hljs-number"&gt;631&lt;/span&gt;
&lt;span class="hljs-attr"&gt;BindIPv6Only&lt;/span&gt;=ipv6-&lt;span class="hljs-literal"&gt;on&lt;/span&gt;ly

&lt;span class="hljs-section"&gt;[Install]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;WantedBy&lt;/span&gt;=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then enable/start the service with &lt;code&gt;systemctl enable --now cups.service&lt;/code&gt; and make sure it started properly:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; systemctl status cups.service&lt;/span&gt;
● cups.service - CUPS Scheduler
     Loaded: loaded (/usr/lib/systemd/system/cups.service; enabled; vendor preset: disabled)
     Active: active (running) since Sat 2020-11-28 21:21:45 CET; 4min 31s ago
TriggeredBy: ● cups.socket
             ● cups.path
       Docs: man:cupsd(8)
   Main PID: 55543 (cupsd)
     Status: &amp;quot;Scheduler is running...&amp;quot;
      Tasks: 1 (limit: 19070)
     Memory: 5.2M
     CGroup: /system.slice/cups.service
             └─55543 /usr/bin/cupsd -l

Nov 28 21:21:45 mali systemd[1]: Starting CUPS Scheduler...
Nov 28 21:21:45 mali systemd[1]: Started CUPS Scheduler.
&lt;/code&gt;&lt;/pre&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="notes"/>
  </entry>
  <entry>
    <title>Automate tasks with docker-compose and systemd</title>
    <published>2020-05-22T15:57:00Z</published>
    <updated>2020-05-22T15:57:00Z</updated>
    <id>https://blog.dotcs.me/posts/automate-tasks-with-systemd</id>
    <link href="https://blog.dotcs.me/posts/automate-tasks-with-systemd"/>
    <summary>This article shows how tasks that have been encapsulated in Docker containers can be controlled by systemd timers. In case of an error a separate systemd service is triggered which sends a mail which contains the last view lines from the journal log.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/automate-tasks-with-systemd">&lt;p&gt;I have several tasks encapsulated in Docker containers which I need to trigger on a regular basis.
The scheduling can be done with systemd.
Both tools together have proven to be a quite powerful combination.&lt;/p&gt;
&lt;h2 id="example-backup-service"&gt;&lt;a class="markdownIt-Anchor" href="#example-backup-service"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Example: Backup service&lt;/h2&gt;
&lt;p&gt;Let's assume we have a backup service that lives in &lt;code&gt;/opt/backup&lt;/code&gt;.
This folder contains a &lt;code&gt;docker-compose.yaml&lt;/code&gt; file which contains the configuration of a backup service.&lt;/p&gt;
&lt;p&gt;We need one systemd unit for the service and one for the timer.
Both are shown below.
The setup is pretty straight forward.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-comment"&gt;# /etc/systemd/system/backup.service&lt;/span&gt;
&lt;span class="hljs-section"&gt;[Unit]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Description&lt;/span&gt;=Backup service
&lt;span class="hljs-attr"&gt;Requires&lt;/span&gt;=docker.service
&lt;span class="hljs-attr"&gt;After&lt;/span&gt;=docker.service

&lt;span class="hljs-comment"&gt;# Send mail in case of an error&lt;/span&gt;
&lt;span class="hljs-attr"&gt;OnFailure&lt;/span&gt;=status-email-user@%n.service

&lt;span class="hljs-section"&gt;[Service]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;WorkingDirectory&lt;/span&gt;=/opt/backup

&lt;span class="hljs-attr"&gt;ExecStart&lt;/span&gt;=/usr/local/bin/docker-compose up

&lt;span class="hljs-section"&gt;[Install]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;WantedBy&lt;/span&gt;=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-comment"&gt;# /etc/systemd/system/backup.timer&lt;/span&gt;
&lt;span class="hljs-section"&gt;[Unit]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Description&lt;/span&gt;=Timer for backup service
&lt;span class="hljs-attr"&gt;Requires&lt;/span&gt;=backup.service

&lt;span class="hljs-section"&gt;[Timer]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Unit&lt;/span&gt;=backup.service

&lt;span class="hljs-comment"&gt;# Time to wait after booting before we run first time&lt;/span&gt;
&lt;span class="hljs-attr"&gt;OnBootSec&lt;/span&gt;=&lt;span class="hljs-number"&gt;10&lt;/span&gt;min

&lt;span class="hljs-comment"&gt;# Define a calendar event (see `man systemd.time`)&lt;/span&gt;
&lt;span class="hljs-attr"&gt;OnCalendar&lt;/span&gt;=*-*-* &lt;span class="hljs-number"&gt;03&lt;/span&gt;:&lt;span class="hljs-number"&gt;00&lt;/span&gt;:&lt;span class="hljs-number"&gt;00&lt;/span&gt; Europe/Berlin

&lt;span class="hljs-section"&gt;[Install]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;WantedBy&lt;/span&gt;=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The service unit has a &lt;code&gt;OnFailure&lt;/code&gt; hook which runs a separate systemd service in case the exit code of the service is non-zero.
This idea comes from the &lt;a href="https://wiki.archlinux.org/index.php/Systemd/Timers#As_a_cron_replacement"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Arch Wiki&lt;/a&gt;.&lt;br&gt;
The status email service can be configured in a generic way such that it can be re-used in other systemd services as well.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-comment"&gt;# /etc/systemd/system/status-email-user@.service&lt;/span&gt;
&lt;span class="hljs-section"&gt;[Unit]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Description&lt;/span&gt;=Status Email for %i to user

&lt;span class="hljs-section"&gt;[Service]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Type&lt;/span&gt;=&lt;span class="hljs-literal"&gt;on&lt;/span&gt;eshot
&lt;span class="hljs-attr"&gt;ExecStart&lt;/span&gt;=/usr/local/bin/systemd-email email@example.com %i
&lt;span class="hljs-attr"&gt;User&lt;/span&gt;=nobody
&lt;span class="hljs-attr"&gt;Group&lt;/span&gt;=systemd-journal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;/usr/local/bin/systemd-email&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;#!/bin/sh&lt;/span&gt;

/usr/bin/mail -Ssendwait -t &amp;lt;&amp;lt;&lt;span class="hljs-string"&gt;ERRMAIL
To: $1
From: Monitor (systemd) &amp;lt;alert@example.tld&amp;gt;
Subject: $2
Content-Transfer-Encoding: 8bit
Content-Type: text/plain; charset=UTF-8

$(systemctl status --full &amp;quot;$2&amp;quot;)
ERRMAIL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally the timer needs to be started/enabled as usual:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;systemctl start backup.timer
systemctl &lt;span class="hljs-built_in"&gt;enable&lt;/span&gt; backup.timer
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="show-logs"&gt;&lt;a class="markdownIt-Anchor" href="#show-logs"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Show logs&lt;/h2&gt;
&lt;p&gt;Logs can be read with &lt;code&gt;journalctl&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;journalctl -b -u backup.service
&lt;/code&gt;&lt;/pre&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="notes"/>
    <category term="tech"/>
  </entry>
  <entry>
    <title>Webcam Support in Arch Linux on Macbooks</title>
    <published>2020-04-01T18:07:00Z</published>
    <updated>2020-04-01T18:07:00Z</updated>
    <id>https://blog.dotcs.me/posts/macbook-webcam-arch</id>
    <link href="https://blog.dotcs.me/posts/macbook-webcam-arch"/>
    <summary>Learn how to install a kernel module that allows to use the Apple Facetime HD camera in your Arch or Manjaro Linux installation.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/macbook-webcam-arch">&lt;p&gt;I'm running &lt;a href="https://manjaro.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Manjaro Linux&lt;/a&gt; (an &lt;a href="https://www.archlinux.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Arch Linux&lt;/a&gt; derivative) on my MacbookPro12,1 (Retina, 13-inch, Early 2015).&lt;/p&gt;
&lt;p&gt;
        &lt;div class="text-center bg-gray-100 py-2"&gt;
            &lt;div class="overflow-x-auto px-1"&gt;
                &lt;img src="/posts/%3Cpost_slug%3E/macbook-pro.png" alt="Image source: support.apple.com, 2020/04/01" class="inline-block mb-2"&gt;
            &lt;/div&gt;
            &lt;div class="italic text-gray-700"&gt;Image source: support.apple.com, 2020/04/01&lt;/div&gt;
        &lt;/div&gt;
    &lt;/p&gt;
&lt;p&gt;I was astonished how many things just worked out-of-the-box.
Kudos to the Arch and Manjaro teams for their great work!&lt;/p&gt;
&lt;p&gt;Unfortunately one thing that did not work out-of-the-box is the webcam.
It requires a driver that is not part of the official kernel but must be installed separately.&lt;br&gt;
The code is in the &lt;a href="https://aur.archlinux.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;Arch User Repository (AUR)&lt;/a&gt;.
I use &lt;a href="https://github.com/Jguer/yay"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;yay&lt;/a&gt; to install packages from AUR which I can highly recommend and which I will use in this article.&lt;/p&gt;
&lt;p&gt;Let's get our hands dirty!&lt;/p&gt;
&lt;p&gt;First let's get information about all installed kernels and see if the headers are installed for all of them:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; pacman -Q | grep -E &lt;span class="hljs-string"&gt;&amp;#x27;linux[0-9]+&amp;#x27;&lt;/span&gt;  &lt;span class="hljs-comment"&gt;# see which kernels are installed&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For each installed linux kernel there should be a &lt;code&gt;-headers&lt;/code&gt; file next to it, e.g.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;linux419 4.19.113-1
linux419-headers 4.19.113-1
linux54 5.4.28-1
linux54-headers 5.4.28-1
linux55 5.5.13-1
linux55-headers 5.5.13-1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the headers are missing, make sure to install them:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; yay -S linux-headers   &lt;span class="hljs-comment"&gt;# select the headers that are missing&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then let's get the &lt;a href="https://aur.archlinux.org/packages/bcwc-pcie-git/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;driver&lt;/a&gt; and install it from AUR:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; yay -S bcwc-pcie-git&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the installation we need to load the kernel module:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; modprobe facetimehd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can test if the video source has been identified correctly by executing &lt;code&gt;v4l2-ctl --list-devices&lt;/code&gt;.
If everything worked out, the output should be:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;Apple Facetime HD (PCI:0000:02:00.0):
	/dev/video0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the output is instead &lt;code&gt;No /dev/video0 device&lt;/code&gt;, then make sure to unload the kernel module &lt;code&gt;bdc_pci&lt;/code&gt; as described in the &lt;a href="https://github.com/patjak/bcwc_pcie/wiki#known-issues"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;wiki&lt;/a&gt;.
This can be done by running the following commands:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;modprobe -r facetimehd  &lt;span class="hljs-comment"&gt;# temporary remove facetimehd module&lt;/span&gt;
modprobe -r bdc_pci     &lt;span class="hljs-comment"&gt;# remove disturbing kernel module&lt;/span&gt;

&lt;span class="hljs-comment"&gt;# make sure that the disturbing kernel module is blacklisted&lt;/span&gt;
&lt;span class="hljs-comment"&gt;# and cannot be loaded as a dependency of another module.&lt;/span&gt;
&lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;blacklist bdc_pci\ninstall bdc_pci /bin/false&amp;quot;&lt;/span&gt; &amp;gt; /etc/modprobe.d/bcwc-pcie.conf

modprobe facetimehd     &lt;span class="hljs-comment"&gt;# load the facetimehd module again&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The webcam should work now.
You can test it on any website that requires a webcam, such as &lt;a href="https://meet.jit.si/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;meet.jit.si&lt;/a&gt;.
Have fun!&lt;/p&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="notes"/>
    <category term="tech"/>
  </entry>
  <entry>
    <title>OfflineIMAP + systemd timer</title>
    <published>2020-04-01T14:38:00Z</published>
    <updated>2020-04-01T14:38:00Z</updated>
    <id>https://blog.dotcs.me/posts/offlineimap-systemd-timer</id>
    <link href="https://blog.dotcs.me/posts/offlineimap-systemd-timer"/>
    <summary>Learn how to setup a systemd timer that regularly fetches new mails from an IMAP server with OfflineIMAP.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/offlineimap-systemd-timer">&lt;p&gt;I use &lt;a href="http://www.mutt.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;mutt&lt;/a&gt; to manage my emails and access them from the terminal.
To sync the mails between the IMAP server and mutt I use &lt;a href="https://www.offlineimap.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;OfflineIMAP&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To regularly check for new mails I use a &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd.timer.html"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;systemd timer&lt;/a&gt;.
The necessary files can be found &lt;a href="https://github.com/OfflineIMAP/offlineimap/tree/master/contrib/systemd"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;in the official repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let's clone the repository first and copy all necessary files to &lt;code&gt;/etc/systemd/user&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-built_in"&gt;cd&lt;/span&gt; /tmp
git &lt;span class="hljs-built_in"&gt;clone&lt;/span&gt; --depth 1 git@github.com:OfflineIMAP/offlineimap.git  &lt;span class="hljs-comment"&gt;# a shallow copy is enough&lt;/span&gt;
&lt;span class="hljs-built_in"&gt;cd&lt;/span&gt; offlineimap/contrib/systemd
sudo cp *.{service,timer} /etc/systemd/user/
systemctl --user daemon-reload
&lt;span class="hljs-built_in"&gt;cd&lt;/span&gt; /tmp &amp;amp;&amp;amp; rm -rf /tmp/offlineimap
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default the update interval of the timer is set to 15min.
I preferred an update interval of 5 min, which can be easily accomplished.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; systemctl --user edit offlineimap-oneshot.timer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this file values can be overwritten as such:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-section"&gt;[Timer]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;OnUnitInactiveSec&lt;/span&gt;=&lt;span class="hljs-number"&gt;5&lt;/span&gt;min
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally it's time to enable and start the timer.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; systemctl --user &lt;span class="hljs-built_in"&gt;enable&lt;/span&gt; offlineimap-oneshot.timer &lt;span class="hljs-comment"&gt;# autostart at boot&lt;/span&gt;&lt;/span&gt;
&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; systemctl --user start offlineimap-oneshot.timer  &lt;span class="hljs-comment"&gt;# start now&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's check if the timer is up and running.
&lt;code&gt;systemctl --user status offlineimap-oneshot.timer&lt;/code&gt; should show that it is up and running and tell how many time is left until the next run:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;● offlineimap-oneshot.timer - Offlineimap Query Timer
     Loaded: loaded (/usr/lib/systemd/user/offlineimap-oneshot.timer; enabled; vendor preset: enabled)
    Drop-In: /home/dotcs/.config/systemd/user/offlineimap-oneshot.timer.d
             └─override.conf
     Active: active (waiting) since Wed 2020-04-01 16:27:20 CEST; 8min ago
    Trigger: Wed 2020-04-01 16:37:34 CEST; 1min 55s left
   Triggers: ● offlineimap-oneshot.service
&lt;/code&gt;&lt;/pre&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="notes"/>
    <category term="tech"/>
  </entry>
  <entry>
    <title>i3 + termite + custom themes = &lt;3</title>
    <published>2020-04-01T09:36:00Z</published>
    <updated>2020-04-01T09:36:00Z</updated>
    <id>https://blog.dotcs.me/posts/i3-termite-theme</id>
    <link href="https://blog.dotcs.me/posts/i3-termite-theme"/>
    <summary>i3 + termite is awesome. Having a simple theme changer is even better. Learn how to set up custom themes and apply them with a simple keystroke.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/i3-termite-theme">&lt;p&gt;I love the sun – especially in Spring when temperatures are not too hot and taking a sunbath is a real pleasure. And I love working in the sun, which is often a challenge because of the poor contrast - especially if, like me, you like to use dark themes.&lt;/p&gt;
&lt;p&gt;Since I recently changed to &lt;a href="https://i3wm.org/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;i3&lt;/a&gt; as my window manager, I use &lt;a href="https://github.com/thestinger/termite"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;termite&lt;/a&gt; as my default terminal which has by default no simple way to switch themes – at least not to my knowledge. But working in the sun requires a light theme, so I decided to work on a simple theme changer that is also integrated in i3.&lt;/p&gt;
&lt;p&gt;So let's get to work.&lt;/p&gt;
&lt;p&gt;First we need custom color themes. I have taken the two themes from &lt;a href="https://github.com/alpha-omega/termite-colors-solarized"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;this GitHub repository&lt;/a&gt; and put them in &lt;code&gt;~/.config/termite/themes&lt;/code&gt;.
Of course you can also define custom themes and put them there. The theme files should have the following format:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-section"&gt;[colors]&lt;/span&gt;
foreground = &lt;span class="hljs-comment"&gt;#000000&lt;/span&gt;
background = &lt;span class="hljs-comment"&gt;#ffffff&lt;/span&gt;
&lt;span class="hljs-comment"&gt;# and so on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then copy your current &lt;code&gt;~/.config/termite/config&lt;/code&gt; to &lt;code&gt;~/.config/termite/config.base&lt;/code&gt; and remove the &lt;code&gt;colors&lt;/code&gt; section.&lt;/p&gt;
&lt;p&gt;We will now need a way to append a theme file to the &lt;code&gt;config.base&lt;/code&gt; file. I've created a simple script that does this job:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;#!/usr/bin/env bash&lt;/span&gt;

USAGE=&lt;span class="hljs-string"&gt;&amp;quot;&lt;span class="hljs-variable"&gt;$0&lt;/span&gt; light|dark&amp;quot;&lt;/span&gt;

TERMITE_CONF_FOLDER=~/.config/termite
THEME=&lt;span class="hljs-variable"&gt;$1&lt;/span&gt;

&lt;span class="hljs-function"&gt;&lt;span class="hljs-title"&gt;change_theme&lt;/span&gt;&lt;/span&gt;() {
    &lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;# THIS FILE HAS BEEN AUTOGENERATED. DO NOT CHANGE MANUALLY!&amp;quot;&lt;/span&gt; | \
        cat - /tmp/termite-switch-theme.hint &lt;span class="hljs-variable"&gt;$TERMITE_CONF_FOLDER&lt;/span&gt;/config.base &lt;span class="hljs-variable"&gt;$TERMITE_CONF_FOLDER&lt;/span&gt;/themes/&lt;span class="hljs-variable"&gt;$1&lt;/span&gt; &amp;gt; &lt;span class="hljs-variable"&gt;$TERMITE_CONF_FOLDER&lt;/span&gt;/config
    killall -USR1 termite || &lt;span class="hljs-literal"&gt;true&lt;/span&gt;
}

&lt;span class="hljs-keyword"&gt;case&lt;/span&gt; &lt;span class="hljs-variable"&gt;$THEME&lt;/span&gt; &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
    light|solarized-light) change_theme solarized-light ;;
    dark|solarized-dark) change_theme solarized-dark ;;
    *) &lt;span class="hljs-built_in"&gt;echo&lt;/span&gt; &lt;span class="hljs-variable"&gt;$USAGE&lt;/span&gt; ;;
&lt;span class="hljs-keyword"&gt;esac&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Put this script somewhere and make it executable. In my case I've saved the file in &lt;code&gt;~/.local/scripts/termite-switch-theme.sh&lt;/code&gt;. You should be able to switch themes now by calling the script, e.g. &lt;code&gt;~/.local/scripts/termite-switch-theme.sh&lt;/code&gt; light.&lt;/p&gt;
&lt;p&gt;This is already great, but for a perfect integration with i3 put these lines into your &lt;code&gt;~/.config/i3/config&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;set $mode_term_theme Terminal theme (l) light, (d) dark
mode &amp;quot;$mode_term_theme&amp;quot; {
    # choose which theme should be applied by pressing l (light) or d (dark)
    bindsym l exec --no-startup-id &amp;quot;~/.local/scripts/termite-switch-theme.sh light&amp;quot;, mode &amp;quot;default&amp;quot;
    bindsym d exec --no-startup-id &amp;quot;~/.local/scripts/termite-switch-theme.sh dark&amp;quot;, mode &amp;quot;default&amp;quot;
    # back to normal: Enter or Escape
    bindsym Return mode &amp;quot;default&amp;quot;
    bindsym Escape mode &amp;quot;default&amp;quot;
}
bindsym $mod+t mode &amp;quot;$mode_term_theme&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally reload the i3 config with &lt;code&gt;mod+shift+c&lt;/code&gt;. Now you can change themes with &lt;code&gt;mod+t&lt;/code&gt; and choose which theme should be applied (light or dark). All running terminals will immediately reflect your theme changes. Have fun!&lt;/p&gt;
&lt;h2 id="base16-themes"&gt;&lt;a class="markdownIt-Anchor" href="#base16-themes"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Base16 Themes&lt;/h2&gt;
&lt;p&gt;If you want to have even more themes to choose from take a look at the wonderful repository &lt;a href="https://github.com/khamer/base16-termite"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;khamer/base16-termite&lt;/a&gt;. Those themes are working out-of-the-box just as described above.&lt;/p&gt;
&lt;h2 id="acknowledgements"&gt;&lt;a class="markdownIt-Anchor" href="#acknowledgements"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Acknowledgements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Thanks to &lt;a href="https://github.com/BarbUk"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;@BarbUk&lt;/a&gt; for &lt;a href="https://github.com/thestinger/termite/issues/730"&gt;&lt;i class="lab la-github" title="This link refers to an external site"&gt;&lt;/i&gt;helping me find the correct signal&lt;/a&gt; to send to running termite instances.&lt;/li&gt;
&lt;li&gt;Thanks to &lt;a href="https://nils-braun.github.io/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;@nils-braun&lt;/a&gt; for reviewing this article.&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="notes"/>
    <category term="tech"/>
  </entry>
  <entry>
    <title>Spotify Desktop App with HiDPI Scaling in GNOME 3</title>
    <published>2019-11-12T16:45:00Z</published>
    <updated>2019-11-12T16:45:00Z</updated>
    <id>https://blog.dotcs.me/posts/spotify-desktop-high-dpi-scaling</id>
    <link href="https://blog.dotcs.me/posts/spotify-desktop-high-dpi-scaling"/>
    <summary>Spotify Desktop seems to have issues with HiDPI screens in Linux. This post shows how to fix it.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/spotify-desktop-high-dpi-scaling">&lt;p&gt;When using a HiDPI screen, such as the MacBook Pro with Retina display, Spotify Desktop may not automatically detect the correct scaling factor.
I have noticed issues in my Manjaro installation that runs with GNOME 3 Desktop.
Spotify has been installed from the AUR package repository.&lt;br&gt;
The wrong scaling factor leads to very small font size that is hard to read.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; spotify --version&lt;/span&gt;
Spotify version 1.1.10.546.ge08ef575, Copyright (c) 2019, Spotify Ltd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fortunately there is an option to force Spotify Desktop to use a (hardcoded) scaling factor.
Use the following command and vary the scaling factor in order to find the correct factor first:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; spotify --force-device-scale-factor=2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the correct value has been found, adjust the desktop entry that GNOME uses to when starting the application via its launcher.
The file lives in &lt;code&gt;/usr/share/applications/spotify.desktop&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-section"&gt;[Desktop Entry]&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Type&lt;/span&gt;=Application
&lt;span class="hljs-attr"&gt;Name&lt;/span&gt;=Spotify
&lt;span class="hljs-attr"&gt;GenericName&lt;/span&gt;=Music Player
&lt;span class="hljs-attr"&gt;Icon&lt;/span&gt;=spotify-client
&lt;span class="hljs-attr"&gt;TryExec&lt;/span&gt;=spotify
&lt;span class="hljs-attr"&gt;Exec&lt;/span&gt;=spotify --force-device-scale-factor=&lt;span class="hljs-number"&gt;2&lt;/span&gt; %U
&lt;span class="hljs-attr"&gt;Terminal&lt;/span&gt;=&lt;span class="hljs-literal"&gt;false&lt;/span&gt;
&lt;span class="hljs-attr"&gt;MimeType&lt;/span&gt;=x-scheme-handler/spotify&lt;span class="hljs-comment"&gt;;&lt;/span&gt;
&lt;span class="hljs-attr"&gt;Categories&lt;/span&gt;=Audio&lt;span class="hljs-comment"&gt;;Music;Player;AudioVideo;&lt;/span&gt;
&lt;span class="hljs-attr"&gt;StartupWMClass&lt;/span&gt;=spotify
&lt;/code&gt;&lt;/pre&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="notes"/>
    <category term="tech"/>
  </entry>
  <entry>
    <title>An "open" command in Linux</title>
    <published>2019-11-11T21:03:00Z</published>
    <updated>2019-11-11T21:03:00Z</updated>
    <id>https://blog.dotcs.me/posts/open-command-in-linux</id>
    <link href="https://blog.dotcs.me/posts/open-command-in-linux"/>
    <summary>This article explains how to configure a command "open" in Linux that behaves similar to the command that macOS provides.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/open-command-in-linux">&lt;p&gt;As a previous macOS user I am used to call &lt;code&gt;open &amp;lt;anything&amp;gt;&lt;/code&gt; in a terminal to open the current file or folder with the standard tool.
So &lt;code&gt;open .&lt;/code&gt; would open the current folder while &lt;code&gt;open file.pdf&lt;/code&gt; would open the PDF in the default PDF viewer.&lt;/p&gt;
&lt;p&gt;Today I learned that &lt;code&gt;xdg-open&lt;/code&gt; serves the same purpose on the Linux desktop. So I configured an alias, to have the same behavior on both systems:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-built_in"&gt;alias&lt;/span&gt; open=&lt;span class="hljs-string"&gt;&amp;quot;xdg-open &amp;amp;&amp;gt;/dev/null&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="query-and-set-defaults"&gt;&lt;a class="markdownIt-Anchor" href="#query-and-set-defaults"&gt;&lt;span class="hidden sm:inline-block x-headline-anchor"&gt;#&lt;/span&gt;&lt;/a&gt; Query and set defaults&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;xdg-open&lt;/code&gt; is part of &lt;a href="https://wiki.archlinux.org/index.php/Xdg-utils"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;&lt;code&gt;xdg-utils&lt;/code&gt;&lt;/a&gt;, which &lt;a href="https://freedesktop.org/wiki/Software/xdg-utils/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;describes itself&lt;/a&gt; as&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;xdg-utils is a set of tools that allows applications to easily integrate with the desktop environment of the user, regardless of the specific desktop environment that the user runs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's super convenient to change the default application for a given file, say a PDF.
Let's change the default program:&lt;/p&gt;
&lt;p&gt;First let's assume we don't know the mime-type of the PDF, which is &lt;code&gt;application/pdf&lt;/code&gt;.
We can find this type by query all known filetypes:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; xdg-mime query filetype /path/to/a/file.pdf &lt;/span&gt;
application/pdf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's see which default application is currently configured for this filetype:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; xdg-mime query default application/pdf&lt;/span&gt;
chromium.desktop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we don't want to use chromium to read PDFs, but for example &lt;a href="https://pwmt.org/projects/zathura/"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;zathura&lt;/a&gt; we can change the default application as follows:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;$&lt;/span&gt;&lt;span class="bash"&gt; find /usr/share/applications/ -name &lt;span class="hljs-string"&gt;&amp;#x27;*zathura*&amp;#x27;&lt;/span&gt;&lt;/span&gt;
/usr/share/applications/org.pwmt.zathura-pdf-mupdf.desktop
/usr/share/applications/org.pwmt.zathura.desktop
&lt;span class="hljs-meta"&gt;
$&lt;/span&gt;&lt;span class="bash"&gt; xdg-mime default org.pwmt.zathura.desktop application/pdf&lt;/span&gt;
&lt;span class="hljs-meta"&gt;
$&lt;/span&gt;&lt;span class="bash"&gt; xdg-mime query default application/pdf&lt;/span&gt;
org.pwmt.zathura.desktop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now PDF files are opened with zathura when using our new &lt;code&gt;open&lt;/code&gt; command as defined above.&lt;/p&gt;
&lt;p&gt;A lot programs bring their own &lt;code&gt;.desktop&lt;/code&gt; file(s). Files are listed in &lt;code&gt;/usr/share/appliations&lt;/code&gt; and can be overridden or suplemented with files located in &lt;code&gt;~/.local/share/applications&lt;/code&gt;. The specification of those files &lt;a href="https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#recognized-keys"&gt;&lt;i class="las la-external-link-alt" title="This link refers to an external site"&gt;&lt;/i&gt;can be found here&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="notes"/>
    <category term="tech"/>
  </entry>
  <entry>
    <title>GNOME 3: Change wallpaper periodically</title>
    <published>2019-11-10T18:52:00Z</published>
    <updated>2019-11-10T18:52:00Z</updated>
    <id>https://blog.dotcs.me/posts/gnome3-change-wallpapers-automatically</id>
    <link href="https://blog.dotcs.me/posts/gnome3-change-wallpapers-automatically"/>
    <summary>This post describes how wallpapers can be automatically changed in GNOME 3 with a simple script and a cronjob.</summary>
    <content type="html" xml:base="https://blog.dotcs.me/posts/gnome3-change-wallpapers-automatically">&lt;p&gt;If you are using GNOME 3 and you want to periodically change your desktop background using images in a folder, this is for you.&lt;/p&gt;
&lt;p&gt;Put this script somewhere and make it executable.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;&lt;span class="hljs-meta"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="hljs-comment"&gt;# You need to adjust this path&lt;/span&gt;
WALLPAPER_FOLDER=/path/to/your/wallpaper/folder

&lt;span class="hljs-comment"&gt;# https://askubuntu.com/a/1073769/277761&lt;/span&gt;
PID=$(pgrep gnome-session | tail -n1)
&lt;span class="hljs-built_in"&gt;export&lt;/span&gt; DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/&lt;span class="hljs-variable"&gt;$PID&lt;/span&gt;/environ|cut -d= -f2-)

FILE_PATH=`ls &lt;span class="hljs-variable"&gt;$WALLPAPER_FOLDER&lt;/span&gt; | shuf -n 1`
FILE_URI=&lt;span class="hljs-string"&gt;&amp;quot;file://&lt;span class="hljs-variable"&gt;$WALLPAPER_FOLDER&lt;/span&gt;/&lt;span class="hljs-variable"&gt;$FILE_PATH&lt;/span&gt;&amp;quot;&lt;/span&gt;
/usr/bin/gsettings &lt;span class="hljs-built_in"&gt;set&lt;/span&gt; org.gnome.desktop.background picture-uri &lt;span class="hljs-variable"&gt;$FILE_URI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then create a cronjob that executes this script periodically, e.g. by using this line:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code&gt;*/10 * * * * /path/to/your/file.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you're done. Have fun!&lt;/p&gt;
</content>
    <author>
      <name>dotcs</name>
    </author>
    <category term="linux"/>
    <category term="notes"/>
    <category term="tech"/>
  </entry>
</feed>