<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.7">Jekyll</generator><link href="https://japh.se/feed.xml" rel="self" type="application/atom+xml" /><link href="https://japh.se/" rel="alternate" type="text/html" /><updated>2025-05-11T14:13:11+02:00</updated><id>https://japh.se/feed.xml</id><title type="html">http/japh.se</title><subtitle>just another {perl,} hacker</subtitle><entry><title type="html">jump to function definitions in vim</title><link href="https://japh.se/2022/05/21/jump_to_function_definition_in_vim.html" rel="alternate" type="text/html" title="jump to function definitions in vim" /><published>2022-05-21T00:00:00+02:00</published><updated>2022-05-21T00:00:00+02:00</updated><id>https://japh.se/2022/05/21/jump_to_function_definition_in_vim</id><content type="html" xml:base="https://japh.se/2022/05/21/jump_to_function_definition_in_vim.html"><![CDATA[<p>I’ve been looking for a solution to simply jump to where a function is defined
for some time. There’s all sorts of ways that doesn’t work well for the gigantic
perl codebase I’m working with.</p>

<p>I’ve known about tags and ctags all this time, but I thought it would involve
a ton of configuration and maintenance to get it functional.</p>

<p>Turns out, I was wrong.</p>

<p>This is all there is to get perl tags and vim working together.</p>

<p>First, tell vim where to look for a tag file. This can be adjusted in an
autocommand for a flexible tag setup depending on project location.</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">set</span> <span class="k">tags</span><span class="p">=.</span><span class="sr">/tags,tags,~/</span>dev<span class="sr">/tags,~/</span>dev<span class="sr">/askas/</span>utils<span class="p">-</span>askas<span class="sr">/vim/</span><span class="k">tags</span>
</code></pre></div></div>

<p>Next we need to generate the tags, and ctags is really fast:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2116 files, 1433894 lines (43984 kB) scanned in 0.7 seconds (64208 kB/s)
36621 tags added to tag file
36621 tags sorted in 0.00 seconds
</code></pre></div></div>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
ctags <span class="nt">-f</span> ~/dev/tags <span class="nt">--recurse</span> <span class="nt">--totals</span> <span class="se">\</span>
  <span class="nt">--exclude</span><span class="o">=</span>blib <span class="nt">--exclude</span><span class="o">=</span>.svn  <span class="nt">--exclude</span><span class="o">=</span>CLEAN             <span class="se">\</span>
  <span class="nt">--exclude</span><span class="o">=</span>.git <span class="nt">--exclude</span><span class="o">=</span><span class="s1">'*~'</span>                              <span class="se">\</span>
  <span class="nt">--extras</span><span class="o">=</span>q                                                 <span class="se">\</span>
  <span class="nt">--languages</span><span class="o">=</span>Perl,Vim                                       <span class="se">\</span>
  <span class="nt">--langmap</span><span class="o">=</span>Perl:+.t                                         <span class="se">\</span>
  ~/dev/
</code></pre></div></div>

<p>Since I’ll be doing this a lot, I’m mapping keys to go to tag definition and
back to where I was prior to jumping like this:</p>

<div class="language-vim highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nnoremap <span class="p">&lt;</span><span class="nb">backspace</span><span class="p">&gt;</span> <span class="p">&lt;</span>C<span class="p">-]&gt;</span>
nnoremap <span class="p">&lt;</span><span class="k">tab</span><span class="p">&gt;</span>       <span class="p">&lt;</span>C<span class="p">-</span>T<span class="p">&gt;</span>
</code></pre></div></div>

<p>Now, we can use tags for much more than this and I’ll be exploring this in the
next couple of weeks.</p>]]></content><author><name>Magnus Woldrich</name></author><category term="perl," /><category term="vim," /><category term="tags" /><summary type="html"><![CDATA[I’ve been looking for a solution to simply jump to where a function is defined for some time. There’s all sorts of ways that doesn’t work well for the gigantic perl codebase I’m working with.]]></summary></entry><entry><title type="html">use perl modules in python3</title><link href="https://japh.se/2021/08/03/use-perl-modules-in-python3.html" rel="alternate" type="text/html" title="use perl modules in python3" /><published>2021-08-03T00:00:00+02:00</published><updated>2021-08-03T00:00:00+02:00</updated><id>https://japh.se/2021/08/03/use-perl-modules-in-python3</id><content type="html" xml:base="https://japh.se/2021/08/03/use-perl-modules-in-python3.html"><![CDATA[<p>Imagine this:</p>

<p>You’re a seasoned perl veteran that for one reason or another needs to
write some python. You’re not very good at it, though you’re enjoying it
more than what you initially thought. Some things in python are easier,
some things are harder, and many things are just different.</p>

<p>You’ve done a fair amount of work on your perl modules over at <a href="https://metacpan.org/author/WOLDRICH">metacpan</a>,
and you <strong>use</strong> functionality imported from them in many new projects.</p>

<p>While learning the language by writing <a href="https://github.com/trapd00r/beets-tcp">plugins</a> for
<a href="https://github.com/beetbox/beets/">beets</a>, you stumble upon a whole
bunch of open issues on that project regarding <a href="https://github.com/beetbox/beets/issues/1593">UI
overhaul</a>.</p>

<p>During long music import sessions there’s so much info spewed out in the
terminal; it would really help with a sprinkle of color and
reformatting.</p>

<p>I’ve written <a href="https://metacpan.org/pod/Term::ExtendedColor">quite</a> a
<a href="https://metacpan.org/pod/Term::ExtendedColor::Xresources">few</a> perl
modules <a href="https://metacpan.org/pod/File::LsColor">dealing with colors</a> in
different ways and I know all there is to know about escape sequences,
terminal emulators and various quirks.</p>

<p>A first step to add some color to the beets import process could be to
color the imported filenames according to the users
<a href="https://github.com/trapd00r/LS_COLORS">LS_COLORS</a> environment variable.
That would add familiarity and remove the need to watch out for file
extensions in the long outputs beets produces.</p>

<p>I’ve seen my <a href="https://metacpan.org/pod/File::LsColor">File::LsColor</a>
project cloned in a variety of languages such as
<a href="https://github.com/sharkdp/lscolors">rust</a> and ruby, so I went over to <a href="https://pypi.org/search/?q=ls+colors">pypi</a> for something
similar.</p>

<p><strong>There’s no such thing.</strong></p>

<p>Well. I could rewrite File::LsColor in python3 myself, but that’s not
what I wanted to spend time on <strong>right now</strong>.</p>
<h3 id="what-if-i-could-mix-perl-and-python">What if I could mix perl and python…</h3>

<p>Now, there’s all kinds of
<a href="https://metacpan.org/search?size=20&amp;q=inline%3A%3A">Inline::</a> modules
on cpan that gives the ability to write perl subroutines in
another language, such as <a href="https://metacpan.org/dist/Inline-C/view/lib/Inline/C.pod">C</a> or <a href="https://metacpan.org/dist/Inline-Python/view/Python.pod">python</a>.
But what about writing <strong>python functions in perl</strong>?</p>

<p>There’s a <a href="https://metacpan.org/dist/Inline-Python/view/Python.pod#Using-
Perl-inside-Python-(inside-Perl)">note</a> in Inline::Python but to me, it’s not
very clear whether this actually works…</p>

<p>However; there is a thing called <a href="https://github.com-
/shlomif/pyperl/blob/master/perlmodule.pod">pyperl/perlmodule</a> that was originally created
by ActiveState in the early 2000’s. There’s loads of (mis)information
regarding it not functioning with python3, but let’s try it out.</p>

<p><strong>Install the pyperl package:</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>cpan pyperl
</code></pre></div></div>

<p>Start by importing the perl module, here aptly named japh.
Let’s also grab some arguments from python:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">perl</span> <span class="k">as</span> <span class="n">japh</span>
<span class="kn">import</span> <span class="nn">sys</span>

<span class="n">filenames</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span>
</code></pre></div></div>

<p>Create a perl subroutine using <strong>perl.eval()</strong>. For a return to work
properly, you need to omit the actual return.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">basename_and_colorize</span> <span class="o">=</span> <span class="n">japh</span><span class="p">.</span><span class="nb">eval</span><span class="p">(</span><span class="s">"""
  sub {
    use File::Basename;
    use File::LsColor qw(ls_color);

    my $file = shift;
    ls_color(basename($file));
  }
"""</span><span class="p">)</span>
</code></pre></div></div>

<p>Use python to iterate over the given argments, and for each argument,
call the perl subroutine using <strong>perl.call()</strong>, and store it in a
python variable.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">filenames</span><span class="p">:</span>
  <span class="n">base</span> <span class="o">=</span> <span class="n">japh</span><span class="p">.</span><span class="n">call</span><span class="p">(</span><span class="n">basename_and_colorize</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
  <span class="k">print</span><span class="p">(</span><span class="n">base</span><span class="p">)</span>
</code></pre></div></div>

<p>Execute the script with a few arguments:</p>

<p><img src="/assets/perlinpython3.png" alt="perlinpython" /></p>

<p>Well, look at that!</p>

<p>Now, I guess I must say one shouldn’t be doing this in production,
yadda, yadda, but remember, the question shouldn’t be <em>why</em>, but
always <em>how</em>. If nothing else, this could make for faster proofs of concepts.</p>

<p>Here’s a <a href="https://github.com/trapd00r/perlinpython3">link</a> to the example code repository.</p>]]></content><author><name>Magnus Woldrich</name></author><category term="perl," /><category term="python" /><summary type="html"><![CDATA[Imagine this:]]></summary></entry><entry><title type="html">a better titlecase function for beets</title><link href="https://japh.se/2021/07/14/a_better_titlecase_function_for_beets.html" rel="alternate" type="text/html" title="a better titlecase function for beets" /><published>2021-07-14T08:48:08+02:00</published><updated>2021-07-14T08:48:08+02:00</updated><id>https://japh.se/2021/07/14/a_better_titlecase_function_for_beets</id><content type="html" xml:base="https://japh.se/2021/07/14/a_better_titlecase_function_for_beets.html"><![CDATA[<p>The builtin template function <code class="highlighter-rouge">%title{}</code> in beets has a number of
issues. It tries to titlecase whatever the first character in the given
string is, rendering results like this:</p>

<p><code class="highlighter-rouge">
It's Raining Men (instrumental Version).flac
</code></p>

<p>It’s using <code class="highlighter-rouge">str.capwords</code> under the hood:</p>

<blockquote>
  <p>string.capwords(s, sep=None)
Split the argument into words using str.split(), capitalize each word
using str.capitalize(), and join the capitalized words using str.join().</p>
</blockquote>

<p>Let’s try to use <code class="highlighter-rouge">str.title</code> instead:</p>

<p><code class="highlighter-rouge">
It'S Raining Men (Instrumental Version).flac
</code></p>

<p>That’s even worse.</p>

<p>I found the <a href="https://pypi.org/project/titlecase/">titlecase</a> python
package that’s a conversion of the excellent perl script
<a href="https://gist.github.com/gruber/9f9e8650d68b13ce4d78">TitleCase.pl</a>.</p>

<p>Not only does it solve the issues mentioned above, it’s also clever
about various corner cases, it does <strong>not</strong> titlecase small words like
‘a’, ‘and’, ‘for’ and so on as outlined in <em>The New York Times Manual of Style</em>.</p>

<p>I packaged this up in a simple beets plugin: <a href="https://github.com/trapd00r/beets-
titlecase_proper">beets-titlecase_proper</a>.</p>

<p>But there’s more!</p>

<p>Sometimes there are acronyms that we do <em>not</em> want titlecased for one
reason or another. You can add those words to <strong>~/beets.titlecase</strong> and
they will always be returned as-is. Check this out:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cd</span> <span class="s2">"Dj Tcp the Reckless │2021│ So Much Drama in the Phd [CDR, MP3]"</span>
<span class="nv">$ </span><span class="k">for </span>w <span class="k">in </span>TCP DJ PhD<span class="p">;</span> <span class="k">do </span><span class="nb">echo</span> <span class="nv">$w</span><span class="p">;</span> <span class="k">done</span> <span class="o">&gt;&gt;</span> ~/.beets_titlecase
<span class="nv">$ </span>beet import <span class="nb">.</span>
<span class="nv">$ </span>beet <span class="nb">ls</span> <span class="nt">-a</span> <span class="s1">'so much drama'</span> <span class="nt">-f</span> <span class="se">\$</span>path
DJ TCP the Reckless │2021│ So Much Drama <span class="k">in </span>the PhD <span class="o">[</span>CDR, MP3]
</code></pre></div></div>

<p>Much cleaner, eh?</p>

<p><a href="https://github.com/beetbox/beets/discussions/3998">The post that started it all</a></p>

<p><a href="https://github.com/beetbox/beets/discussions/4007">Announcement on beets/discussions</a></p>

<p><a href="https://github.com/trapd00r/configs/blob/master/beets/config.yaml">Here’s</a> my beets configuration.</p>]]></content><author><name>Magnus Woldrich</name></author><category term="linux," /><category term="beets," /><category term="music" /><summary type="html"><![CDATA[The builtin template function %title{} in beets has a number of issues. It tries to titlecase whatever the first character in the given string is, rendering results like this:]]></summary></entry><entry><title type="html">capture primary artist as a separate field in beets</title><link href="https://japh.se/2021/06/01/capture-primary-artist-as-a-separate-field-in-beets.html" rel="alternate" type="text/html" title="capture primary artist as a separate field in beets" /><published>2021-06-01T00:00:00+02:00</published><updated>2021-06-01T00:00:00+02:00</updated><id>https://japh.se/2021/06/01/capture-primary-artist-as-a-separate-field-in-beets</id><content type="html" xml:base="https://japh.se/2021/06/01/capture-primary-artist-as-a-separate-field-in-beets.html"><![CDATA[<p>Ever since I started using beets I’ve struggled with the fact that it
creates directories based on the entire artist/albumartist tag when
there’s more than one artist specified. This means my filesystem looked
like this:</p>

<p><img src="/assets/britney.png" alt="britney" /></p>

<p>Not desirable. I thought the <a href="https://beets.readthedocs.io/e-
n/stable/plugins/ftintitle.html">ftintitle</a> plugin would help me sort this out, but
it only does what I expect for single tracks.</p>

<p>I tried a solution as outlined in <a href="https://github.com/beetbox/beets/issues/3176#issuecomment-
632227610">this</a> github issue, but it only catches the cases where the
different artists is separated by a comma:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">item_fields</span><span class="pi">:</span>
  <span class="na">first_artist</span><span class="pi">:</span> <span class="s">albumartist.split(', ',1)[0:1][0]</span></code></pre></figure>

<p>So, time to learn some python! Turns out there’s a very handy
<code class="highlighter-rouge">re.split()</code> method available, so here’s what I came up with:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">item_fields</span><span class="pi">:</span>
  <span class="na">first_artist</span><span class="pi">:</span> <span class="pi">|</span>
    <span class="s">import re</span>
    <span class="s">return re.split(',|\s+(feat(.?|uring)|&amp;|(Vs|Ft).)', albumartist, 1, flags=re.IGNORECASE)[0]</span></code></pre></figure>

<p>This can handle not only comma delimiters, but also:</p>

<ul>
  <li>Artist,</li>
  <li>Artist &amp;</li>
  <li>Artist feat</li>
  <li>Artist feat.</li>
  <li>Artist featuring</li>
  <li>Artist ft.</li>
  <li>Artist vs</li>
  <li>Artist vs.</li>
  <li>Artist &amp;</li>
</ul>

<p>It <strong>will</strong> screw up things like Earth, Wind &amp; Fire, but that’s not a
major issue.</p>

<p>The idea is to use <code class="highlighter-rouge">$first_artist</code> in the beginning of the path
format like so:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%title{$first_artist}/%title{$albumartist}
</code></pre></div></div>

<p>which will put <code class="highlighter-rouge">Jennifer Lopez feat. Pitbull</code> inside the main Jennifer
Lopez directory, but still keep the feat. part in the directory name
inside it. If you don’t want that, use <code class="highlighter-rouge">$first_artist</code> everywhere.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ beet move artist:feat jennifer\ lopez

J/Jennifer Lopez Feat. Pitbull/Jennifer Lopez Feat. Pitbull │2012│ Dance Again [Single, WEB, MP3]/01 Dance Again.mp3
-&gt; J/Jennifer Lopez/Jennifer Lopez Feat. Pitbull │2012│ Dance Again [Single, WEB, MP3]/01 Dance Again.mp3
</code></pre></div></div>

<p>If I were to use <code class="highlighter-rouge">$first_artist</code> instead of <code class="highlighter-rouge">$albumartist</code> all the way, I would end up with</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>J/Jennifer Lopez Feat. Pitbull/Jennifer Lopez Feat. Pitbull │2012│ Dance Again [Single, WEB, MP3]/01 Dance Again.mp3
-&gt; J/Jennifer Lopez/Jennifer Lopez │2012│ Dance Again [Single, WEB, MP3]/01 Dance Again.mp3
</code></pre></div></div>

<p>I haven’t decided yet which one I prefer, but I know that I’m very happy
not clobbering my directories with a ton of ‘X feat Y’ entries.</p>

<p>This is how I use it:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="err">%</span><span class="s">upper{%left{$albumartist,1}}/%title{$first_artist}/%title{$albumartist}%if{$hasyear, │${year}│} %title{$album} [$alb_type$media_type$format]/${padded_tracknr} %title{$title}</span></code></pre></figure>

<p><a href="https://github.com/trapd00r/configs/blob/master/beets/config.yaml">Here’s</a> my beets configuration.</p>]]></content><author><name>Magnus Woldrich</name></author><category term="linux," /><category term="beets," /><category term="music" /><summary type="html"><![CDATA[Ever since I started using beets I’ve struggled with the fact that it creates directories based on the entire artist/albumartist tag when there’s more than one artist specified. This means my filesystem looked like this:]]></summary></entry><entry><title type="html">special rule for live performances in beets</title><link href="https://japh.se/2021/06/01/special-rule-for-live-performances-in-beets.html" rel="alternate" type="text/html" title="special rule for live performances in beets" /><published>2021-06-01T00:00:00+02:00</published><updated>2021-06-01T00:00:00+02:00</updated><id>https://japh.se/2021/06/01/special-rule-for-live-performances-in-beets</id><content type="html" xml:base="https://japh.se/2021/06/01/special-rule-for-live-performances-in-beets.html"><![CDATA[<p>I like to have the live performances by an artist somewhere else but
directly in the artist root directory, yet still nearby. I create a
label simply called <code class="highlighter-rouge">live</code> like this:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">paths</span><span class="pi">:</span>
      <span class="s">label:live: %upper{%left{$albumartist,1}}/%title{$first_artist}/+live/%title{$albumartist}%if{$hasyear, │${year}│} %title{$album} [$alb_type$media_type$format]/${padded_tracknr} %title{$title}</span>
      <span class="s">default</span><span class="err">:</span>    <span class="err">%</span><span class="s">upper{%left{$albumartist,1}}/%title{$first_artist}/%title{$albumartist}%if{$hasyear, │${year}│} %title{$album} [$alb_type$media_type$format]/${padded_tracknr} %title{$title}</span></code></pre></figure>

<p>Now, whenever I specify the <code class="highlighter-rouge">live</code> label, the imported albums is moved
to +live/ in the artist root directory:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% tree -d
.
├── +live
│   ├── Melanie C │1999│ Live In Madrid 1999 [MP3]
│   ├── Melanie C │2000│ Live In Stockholm, Sweden 20-10-2000 Fm Broadcast [MP3]
│   ├── Melanie C │2006│ Live Hits [MP3]
│   ├── Melanie C │2007│ Live At The Mint 06-12-2007 [MP3]
│   └── Melanie C │2008│ Live At The Manhattan Center Ballroom, Nyc 09-02-2008 [MP3]
├── Melanie C │1999│ Northern Star [Single, CD, MP3]
├── Melanie C │2000│ I Turn To You [Single, CD, FLAC]
├── Melanie C │2000│ Never Be The Same Again [Single, CD, MP3]
├── Melanie C │2000│ Northern Star [CD, FLAC]
├── Melanie C │2000│ Northern Star [CD, MP3]
├── Melanie C │2003│ Reason [CD, MP3]
├── Melanie C │2005│ Beautiful Intentions [CD, FLAC]
├── Melanie C │2006│ Beautiful Intentions (new Version) [MP3]
├── Melanie C │2007│ This Time [CD, FLAC]
├── Melanie C │2011│ The Sea [CD, MP3]
└── Melanie C │2016│ Version Of Me [WEB, FLAC]
</code></pre></div></div>

<p>I import like this:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>beet import --set label=live .
</code></pre></div></div>

<p><a href="https://github.com/trapd00r/configs/blob/master/beets/config.yaml">Here’s</a> my beets configuration.</p>]]></content><author><name>Magnus Woldrich</name></author><category term="linux," /><category term="beets," /><category term="music" /><summary type="html"><![CDATA[I like to have the live performances by an artist somewhere else but directly in the artist root directory, yet still nearby. I create a label simply called live like this:]]></summary></entry><entry><title type="html">how to add singletons to artist directory correctly in beets</title><link href="https://japh.se/2021/05/26/how-to-add-singletons-to-artist-dir-correctly-in-beets.html" rel="alternate" type="text/html" title="how to add singletons to artist directory correctly in beets" /><published>2021-05-26T00:00:00+02:00</published><updated>2021-05-26T00:00:00+02:00</updated><id>https://japh.se/2021/05/26/how-to-add-singletons-to-artist-dir-correctly-in-beets</id><content type="html" xml:base="https://japh.se/2021/05/26/how-to-add-singletons-to-artist-dir-correctly-in-beets.html"><![CDATA[<p>Here’s how to properly add singletons to the correct artist dir using
the quick import functionality in beets. We don’t care for tagging or
musicbrainz lookups for these, we just want to add them to the beets
database and move them to to corresponding directory.</p>

<p>Add this to config.yml:</p>

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">plugins</span><span class="pi">:</span> <span class="pi">[</span><span class="s1">'</span><span class="s">fromfilename'</span><span class="pi">]</span>

<span class="na">extrafiles</span><span class="pi">:</span>
  <span class="na">patterns</span><span class="pi">:</span>
    <span class="na">single_tracks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s1">'</span><span class="s">+tracks/'</span>
  <span class="na">paths</span><span class="pi">:</span>
    <span class="na">single_tracks</span><span class="pi">:</span> <span class="s">$artist/+tracks</span>

<span class="na">paths</span><span class="pi">:</span>
  <span class="na">singleton</span><span class="pi">:</span> <span class="err">%</span><span class="s">upper{%left{$artist,1}}/$artist/+tracks/$artist - $title</span></code></pre></figure>

<p>When we import single tracks to beets we don’t use the autotagger, so
it’s important that the artist field is populated in the files, or else
beets doesn’t know where to put the files. To quickly add the artist
field on a bunch of files, we can utilize <a href="https://github.com/trapd00r/id3shit">id3shit</a>:</p>

<p><code class="highlighter-rouge">id3shit -w artist 'Anna Ternheim' *</code></p>

<p><em>Edit 2021-05-28</em>:
We can also use beets directly like this:</p>

<p><code class="highlighter-rouge">beet import --set artist=Anna\ Ternheim</code></p>

<p>The import command to beets for single tracks is <code class="highlighter-rouge">beet import -sA "$@"</code>.
I find it hard to remember all the commands so I saved it as <code class="highlighter-rouge">beet-import-tracks</code>.</p>

<p>Use it like this:</p>

<p><code class="highlighter-rouge">beet-import-tracks *(.) # import every file in cwd</code></p>

<p>Now, since we made sure that the artist field was populated prior to
running the import command, we can find the imported singletons at
<code class="highlighter-rouge">A/Anna Ternheim/+tracks/</code>.</p>

<p>My current beets configuration can be found <a href="https://github.com/trapd00r/configs/blob/master/beets/config.yaml">here</a>.</p>]]></content><author><name>Magnus Woldrich</name></author><category term="linux," /><category term="beets," /><category term="music" /><summary type="html"><![CDATA[Here’s how to properly add singletons to the correct artist dir using the quick import functionality in beets. We don’t care for tagging or musicbrainz lookups for these, we just want to add them to the beets database and move them to to corresponding directory.]]></summary></entry><entry><title type="html">custom beet path rules for record labels</title><link href="https://japh.se/2021/05/23/custom-beet-path-rules-for-record-labels.html" rel="alternate" type="text/html" title="custom beet path rules for record labels" /><published>2021-05-23T00:00:00+02:00</published><updated>2021-05-23T00:00:00+02:00</updated><id>https://japh.se/2021/05/23/custom-beet-path-rules-for-record-labels</id><content type="html" xml:base="https://japh.se/2021/05/23/custom-beet-path-rules-for-record-labels.html"><![CDATA[<p>I’ve been experimenting with
<a href="https://beets.readthedocs.io/en/latest/index.html">beets</a> for the past
two weeks and it’s awesome.</p>

<p>When importing music, I started to notice that sometimes I don’t want
albums grouped by the usual <code class="highlighter-rouge">[a-z]/artist/artist - album</code> structure.
There’s 148 different artists in the <a href="https://musicbrainz.-
org/search?query=8bitpeoples&amp;type=release&amp;limit=25&amp;method=indexed">8bitpeoples</a>
collective and I thought it would be neater if I could group all of them
releases under a main directory, <code class="highlighter-rouge">8/8bitpeoples</code>.</p>

<p>Turns out it’s way easier than I thought, because we can use custom path
setups like so:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>paths:
  label:8bitpeoples: 8/8bitpeoples/%title{$albumartist} %if{$hasyear,│${year}│} %title{$album} [$alb_type$media_type$format]/${padded_tracknr} %title{$title}
</code></pre></div></div>

<p>Which puts all releases from the 8bitpeoples record label inside the
main 8bitpeoples directory, while still keeping the individual
artist names.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ beet move '8bitpeoples'

/mnt/music8/+TAGGED/Y/Yuppster/Yuppster │1999│ The Okinawa Campaign 1 [WEB, MP3]/10 Boomstick.mp3
  -&gt; /mnt/music8/+TAGGED/8/8bitpeoples/Yuppster │1999│ The Okinawa Campaign 1 [WEB, MP3]/10 Boomstick.mp3

</code></pre></div></div>

<p>Check <code class="highlighter-rouge">beet fields</code> for all the available fields you can use in a
setup like this.</p>

<p>You can also categorize things with custom tags:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>beet modify 'green lantern' -a mixtape_host="DJ Green Lantern"

mixtape_host: mixtapes/$mixtape_host/...
</code></pre></div></div>]]></content><author><name>Magnus Woldrich</name></author><category term="linux," /><category term="beets," /><category term="music" /><summary type="html"><![CDATA[I’ve been experimenting with beets for the past two weeks and it’s awesome.]]></summary></entry><entry><title type="html">advanced LS_COLORS rules with ls++</title><link href="https://japh.se/2021/05/14/advanced-lscolor-rules-with-ls++.html" rel="alternate" type="text/html" title="advanced LS_COLORS rules with ls++" /><published>2021-05-14T00:00:00+02:00</published><updated>2021-05-14T00:00:00+02:00</updated><id>https://japh.se/2021/05/14/advanced-lscolor-rules-with-ls++</id><content type="html" xml:base="https://japh.se/2021/05/14/advanced-lscolor-rules-with-ls++.html"><![CDATA[<p>It’s possible to define a few rules outside of simple extension-based
ones using <a href="https://github.com/trapd00r/LS_COLORS">LS_COLORS</a>. You can
for example match literal filenames with no extension or simple globs:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># matches README as well as *.README etc
*README 38;5;220;1

# matches rtorrent.rc as well as .zshrc etc
*rc     38;5;204
</code></pre></div></div>

<p><img src="/assets/lscolors_literal.png" alt="lscolors_literal" /></p>

<p>A few days ago I started using
<a href="https://beets.readthedocs.io/en/latest/index.html">beets</a> to once and
for all organize my music collection. It’s great. While organizing, I
wanted to get a quick sense of what my mp3:flac ratio looks like. I like
to keep both mp3 and flac versions of albums if possible.</p>

<p>Turns out, simply matching <code class="highlighter-rouge">*FLAC*</code> in <code class="highlighter-rouge">LS_COLORS</code>
doesn’t work. What you can’t do in LS_COLORS, you can however do
with <a href="https://github.com/trapd00r/ls--">ls++</a>:</p>

<p>ls++.conf:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%ls_colors = (
  '(?i)\(FLAC\)' =&gt; '204',
  '(?i)\(MP3\)'  =&gt; '137',
);
</code></pre></div></div>

<p>The (?i) tells ls++ to match case insensitive. Here, I’ve chosen color
index 204 for FLAC and index 137 for MP3, the same colors that I use to
list files with these extensions:</p>

<p>$LS_COLORS:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.flac 38;5;204
.mp3  38;5;137
</code></pre></div></div>

<p>And it looks like this:</p>

<p><img src="/assets/color_directories_differently_with_patterns.png" alt="colors" /></p>

<p>Though the patterns above are very simple, we can use the full power of
perl regex to add attributes to whatever we want, or how about matching
season premieres:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%ls_colors = (
  '(?i)(s[0-9]{2}-s[0-9]{2}|s([0-9]{1,2})[eEx]01)|([Ss]?([0-9]{1,2}))[Eex]01' =&gt; 'bold reverse italic 196',
);
</code></pre></div></div>

<p><img src="/assets/season_premiere.png" alt="premiere" /></p>]]></content><author><name>Magnus Woldrich</name></author><category term="linux," /><category term="LS_COLORS," /><category term="ls++" /><summary type="html"><![CDATA[It’s possible to define a few rules outside of simple extension-based ones using LS_COLORS. You can for example match literal filenames with no extension or simple globs:]]></summary></entry><entry><title type="html">abusing permission flags to distinguish watched episodes</title><link href="https://japh.se/2021/05/09/abusing-permission-flags-to-distinguish-watched-episodes.html" rel="alternate" type="text/html" title="abusing permission flags to distinguish watched episodes" /><published>2021-05-09T00:00:00+02:00</published><updated>2021-05-09T00:00:00+02:00</updated><id>https://japh.se/2021/05/09/abusing-permission-flags-to-distinguish-watched-episodes</id><content type="html" xml:base="https://japh.se/2021/05/09/abusing-permission-flags-to-distinguish-watched-episodes.html"><![CDATA[<p><img src="/assets/seen.png" alt="seen" /></p>

<p>I do 95% of my file management straight in the terminal using standard coreutils.
The remaining 5%, I use <a href="https://github.com/trapd00r/vidir">vidir</a>.</p>

<p>I also use things like mplayer and mpd to watch episodes and listen to
music and podcasts, ergo; no builtin way of marking episodes as watched,
as can be found in various gui applications. How, then, would one keep
track of what’s watched and what’s not?</p>

<p>The standard LS_COLORS project have a few interesting ways of adding
attributes to files and directories with special permission bits set.
The most interesting ones are:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SETGID
STICKY
STICKY_OTHER_WRITABLE
</code></pre></div></div>

<p>All of these can be colored individually, and with the exception of the
last one, setting the corresponding bits in the filesystem shouldn’t
have any security implications or limitations, assuming a local
filesystem where you are the only user.</p>

<p>If a file has the <code class="highlighter-rouge">SETGID</code> bit set, when executed, instead of running
with the privileges of the group of the user who started it, runs with
those of the group which owns the file. In the situation described
above, these should be the same in most cases.</p>

<p>If a directory has the <code class="highlighter-rouge">STICKY BIT</code> set, all the files in said directory
will be modifiable only by their owners. Again, in the situation
described above, this isn’t a bad thing.</p>

<p>So, how can we (ab)use this?</p>

<p>Here’s a script called <code class="highlighter-rouge">seen</code> that sets the <code class="highlighter-rouge">SETGID</code> bit on a file and
<code class="highlighter-rouge">STICKY</code> on a directory.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/perl</span>
<span class="c1"># vim:ft=perl:</span>
<span class="c1"># abstract: abuse sticky bits etc to mark a movie or show as seen</span>
<span class="k">use</span> <span class="nv">strict</span><span class="p">;</span>
<span class="k">use</span> <span class="nv">warnings</span> <span class="s">FATAL</span> <span class="o">=&gt;</span> <span class="p">'</span><span class="s1">all</span><span class="p">';</span>

<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nv">@ARGV</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">use</span> <span class="nv">Cwd</span> <span class="p">();</span>
  <span class="nb">push</span> <span class="nv">@ARGV</span><span class="p">,</span> <span class="nn">Cwd::</span><span class="nv">abs_path</span>
<span class="p">}</span>

<span class="k">for</span> <span class="k">my</span> <span class="nv">$f</span><span class="p">(</span><span class="nv">@ARGV</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span><span class="p">(</span><span class="o">-</span><span class="nv">f</span> <span class="nv">$f</span><span class="p">)</span> <span class="p">{</span>
    <span class="nb">chmod</span><span class="p">(</span><span class="mo">02740</span><span class="p">,</span> <span class="nv">$f</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">warn</span> <span class="p">"</span><span class="s2">chmod: $!</span><span class="se">\n</span><span class="p">";</span>
  <span class="p">}</span>
  <span class="k">elsif</span><span class="p">(</span><span class="o">-</span><span class="nv">d</span> <span class="nv">$f</span><span class="p">)</span> <span class="p">{</span>
    <span class="nb">chmod</span><span class="p">(</span><span class="mo">01700</span><span class="p">,</span> <span class="nv">$f</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">warn</span> <span class="p">"</span><span class="s2">chmod: $!</span><span class="se">\n</span><span class="p">";</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="nb">warn</span> <span class="p">"</span><span class="s2">E: </span><span class="si">$_</span><span class="s2"> is neither a file or a directory</span><span class="se">\n</span><span class="p">";</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Use it like this:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mplayer Laleh.S01E01-FOO/Laleh.S01E01-FOO.mkv
$ seen !$
</code></pre></div></div>

<p><img src="/assets/seen2.png" alt="seen2" /></p>

<p><a href="https://github.com/trapd00r/LS_COLORS">LS_COLORS</a></p>]]></content><author><name>Magnus Woldrich</name></author><category term="linux" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">ratpoison, urxvt and borders</title><link href="https://japh.se/2021/03/21/ratpoison-urxvt-and-borders.html" rel="alternate" type="text/html" title="ratpoison, urxvt and borders" /><published>2021-03-21T00:00:00+01:00</published><updated>2021-03-21T00:00:00+01:00</updated><id>https://japh.se/2021/03/21/ratpoison-urxvt-and-borders</id><content type="html" xml:base="https://japh.se/2021/03/21/ratpoison-urxvt-and-borders.html"><![CDATA[<p>The ratpoison window manager seems to have some kind of weird issues
with urxvt and borders, or the other way around. The right and bottom
border of a window gets 1px thicker than the rest and I can’t seem to
figure out why. I’ve recompiled a clean urxvt and tried different fonts,
grepped the ratpoison source and investigated window manager hints, not
to much avail.</p>

<p>Since the borders are merely for aesthetics I found another solution:</p>

<p>By using the gap feature introduced by <a href="https://github.com/jcs/ratpoison">jcs</a>:</p>

<p>.ratpoisonrc:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> set gap 1
</code></pre></div></div>
<p>together with <strong>no</strong> border in Xresources, we can see 1px of the
background inbetween the windows. Since the background is black (by
default), just change it to your desired border color like so:</p>

<p>.xinitrc:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xsetroot -solid '#ff5400'
</code></pre></div></div>

<p>and we get perfect borders as a result:</p>

<p><img src="/assets/rp-urxvt-borders.png" alt="rp-borders" /></p>]]></content><author><name>Magnus Woldrich</name></author><category term="linux," /><category term="ratpoison," /><category term="urxvt" /><summary type="html"><![CDATA[The ratpoison window manager seems to have some kind of weird issues with urxvt and borders, or the other way around. The right and bottom border of a window gets 1px thicker than the rest and I can’t seem to figure out why. I’ve recompiled a clean urxvt and tried different fonts, grepped the ratpoison source and investigated window manager hints, not to much avail.]]></summary></entry></feed>