Using Beets from 3rd Party Python Applications

I am thinking of using Beets as music library to update a project. The only example of using it this way is in the source code of the Beets command-line interface. That code is well-written but does much more than I need so I decided to create a simple example of using Beets in a 3rd party application.

The hardest part turned out to be determining how to create a proper configuration pro grammatically. The final code is short:


        config["import"]["autotag"] = False
        config["import"]["copy"] = False
        config["import"]["move"] = False
        config["import"]["write"] = False
        config["library"] = music_library_file_name
        config["threaded"] = True 

This will create a configuration that keeps the music files in place and does not attempt to autotag them.

Importating files requires one to subclass importer.ImportSession. A simple importer that serves to import files and not change them is:


    class AutoImportSession(importer.ImportSession):
        "a minimal session class for importing that does not change files"

        def should_resume(self, path):
            return True

        def choose_match(self, task):
            return importer.action.ASIS

        def resolve_duplicate(self, task, found_duplicates):
            pass

        def choose_item(self, task):
            return importer.action.ASIS 

That’s the trickiest part of it. The full demo is:


# Copyright 2017, Kevin Dahlhausen
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

from beets import config
from beets import importer
from beets.ui import _open_library

class Beets(object):
    """a minimal wrapper for using beets in a 3rd party application
       as a music library."""

    class AutoImportSession(importer.ImportSession):
        "a minimal session class for importing that does not change files"

        def should_resume(self, path):
            return True

        def choose_match(self, task):
            return importer.action.ASIS

        def resolve_duplicate(self, task, found_duplicates):
            pass

        def choose_item(self, task):
            return importer.action.ASIS

    def __init__(self, music_library_file_name):
        """ music_library_file_name = full path and name of
            music database to use """
        "configure to keep music in place and do not auto-tag"
        config["import"]["autotag"] = False
        config["import"]["copy"] = False
        config["import"]["move"] = False
        config["import"]["write"] = False
        config["library"] = music_library_file_name
        config["threaded"] = True

        # create/open the the beets library
        self.lib = _open_library(config)

    def import_files(self, list_of_paths):
        """import/reimport music from the list of paths.
            Note: This may need some kind of mutex as I
                  do not know the ramifications of calling
                  it a second time if there are background
                  import threads still running.
        """
        query = None
        loghandler = None  # or log.handlers[0]
        self.session = Beets.AutoImportSession(self.lib, loghandler,
                                               list_of_paths, query)
        self.session.run()

    def query(self, query=None):
        """return list of items from the music DB that match the given query"""
        return self.lib.items(query)

if __name__ == "__main__":

    import os

    # this demo places music.db in same lib as this file and
    # imports music from <this dir>/Music
    path_of_this_file = os.path.dirname(__file__)
    MUSIC_DIR = os.path.join(path_of_this_file, "Music")
    LIBRARY_FILE_NAME = os.path.join(path_of_this_file, "music.db")

    def print_items(items, description):
        print("Results when querying for "+description)
        for item in items:
            print("   Title: {} by '{}' ".format(item.title, item.artist))
            print("      genre: {}".format(item.genre))
            print("      length: {}".format(item.length))
            print("      path: {}".format(item.path))
        print("")

    demo = Beets(LIBRARY_FILE_NAME)

    # import music - this demo does not move, copy or tag the files
    demo.import_files([MUSIC_DIR, ])

    # sample queries:
    items = demo.query()
    print_items(items, "all items")

    items = demo.query(["artist:heart,", "title:Hold", ])
    print_items(items, 'artist="heart" or title contains "Hold"')

    items = demo.query(["genre:Hard Rock"])
    print_items(items, 'genre = Hard Rock') 

I hope this helps. Turns out it is easy to use beets in other apps.

Posted in Python | Tagged | Leave a comment

Plane Spotter

My new app Plane Spotter has been approved. The interesting part of it is that it is written in Python and Kivy. Having written Android apps in Java, Cordova, and now Python, I can unequivocally say that the Python/Kivy combination is the most enjoyable. Once more familiar with Kivy and Python for Android, I predict it will greatly reduce develoment time. The only catch so far is that there is a significant load time when starting the app. Anyway, check it out.

Plane Spotter page in Google Play Store

Posted in Kivy, Python | Leave a comment

Adding GIT branch to BASH prompt

Save this:
https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh to ~/.git-prompt.sh

Then add to ~/.bashrc:

source ~/.git-prompt.sh
GIT_PS1_SHOWCOLORHINTS=1
PROMPT_COMMAND='__git_ps1 "\# \w" ": "'

yielding:
19 ~/proj/app (develop):

Note:
There are more options to show the status of files. See the .git-prompt.sh for info.

Edit:
This is a combined Mercurial / Git version:

hg_ps1() {
    hg prompt "({branch})" 2> /dev/null
}
#PS1='\# $(hg_ps1) \w: '
source ~/.git-prompt.sh
GIT_PS1_SHOWCOLORHINTS=1
PROMPT_COMMAND='__git_ps1 "\#" " $(hg_ps1) \w: "'

Posted in programming | Leave a comment

New Programming / Shell / Vim Font

Thanks to Chris Weisel for pointing out a great new font for shells and Vim. I usually check out “great new programming fonts” and am consistently disappointed. This one is different. It is similar to Bitstream Mono, but not as heavy. That makes it more readable for me.

Font on github:
https://github.com/adobe/Source-Code-Pro

in .gvimrc (_gvimrc):
set guifont=Source_Code_Pro_Semibold:h12:cANSI

Posted in programming | Leave a comment

Easy Erg – C++ Library for the Concept 2 Rowing Machine Released

I recently open-sourced some of my code. It’s a C++ library that wraps the API and provides an ‘Erg’ class.

It currently it builds against an older version of the SDK – version 1.24 – and the current build system requires cygwin.
(There’s nothing in the wrapper code itself that requires g++, I just don’t have Visual C++ installed to create a build script or project.)
On my list is updating it to the most recent SDK.

Source is available from GitHub at:
https://github.com/kdahlhaus/easy-erg

Usage is something like this:


 ErgNet *net = ErgNet::getInstance();
        cout << "net.discoverErgs() = " << net->discoverErgs() << "\n";

        Pm3Erg erg = Pm3Erg(0);

        erg.reset();
        erg.goFinished();
        erg.goIdle();
        erg.goReady();
        erg.goInUse();

        while (1)
        {
            cout << erg.hasStartedRowing() << "  " << erg.getPaceInSecondsPer500() << " " << erg.getStrokeStateText() <<  "\n";
        } 

Posted in indoor-rowing, programming, rowing | Leave a comment

New Rowing Series on Row-2K

Row2K has posted the first video of a new web series. This one is called ‘Gut Checks.’ It is a series of short interviews with national-caliber rowers interspersed with some great rowing video.

“The one that sticks out to me is when we got 4th in the olympics by three tenths of a second. (Holds up hands) It’s about that far.”

It’s a very well done video.

http://www.row2k.com/features/784/The-Training-Center—Episode-1–Gut-Checks/#.UsxB47Sbt30

Posted in rowing | Tagged | Leave a comment

VI Joke

I have no idea where I found this. People don’t argue about editors as much as they used to. This joke was more relevant then.

Two guys are sitting in a bar, and get talking.
"What's you IQ?" one asks.
"169" is the reply.
"Wow, amazing --- my IQ's 172. What're your ideas on Hawkings latest work on
superstring theory?"
And the two get chatting and become lifelong friends.

Further down the bar, two other guys are comparing IQs.
"Mine's 104"
"Gosh, mine's 102. What do you think about the latest Cub's game?"
And the two become lifelong friends.

Even further down the bar, two other guys are also comparing IQs.
"Mine's 53."
"Wow! Mine's 54. Do you use emacs or vi?" 

Posted in programming | Tagged , | Leave a comment

RESTful API Design

I just stumbled on Geert Jansen’s book ‘Thoughts on RESTful API Design.’ Here he has documented things he learned while designing the Red Hat Enterprise Virtualization API.

The nice thing is that the source to the book is on github and you can read it on ReadTheDocs.org.

It outlines some good design decisions when creating an API and is well worth taking a look. It’s not too long of a read.

Posted in programming | Tagged , | Leave a comment

Repeating Sections in a Django Template

I have a need to have multiple sections of name/value pairs with a header on some pages. Something like:

<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>History:</h2></div></div>
        <div class="row"><div class="span2">Date added to fleet:</div><div class="span2">{{plane.dateAddedToFleet}}</div></div>
        <div class="row"><div class="span2">Total Flight Time:</div><div class="span2">{{plane.totalFlightTime|asTime}}</div></div>
        <div class="row"><div class="span2">Total Number of Flights:</div><div class="span2">{{plane.totalNumberOfFlights}}</div></div>
    </div>
</div>

So that’s wrong. I first tried creating a custom tag to render the entire section that would be used like this within the django template:


{% specgroup "History" "Date added to fleet" plane.dateAddedToFleet "Total Flight Time:" plane.totalFlightTime|asTime "Total Number of Flights" plane.totalNumberOfFlights %}

The custom tag code for the above is:


# tags for groups of fields (such as on plane detail page)
@register.simple_tag
def specgroup(*args):
    """group header label1 value1 label2 value2 ...."""
    header= args[0]
    logging.getLogger().error(header)
    html = """
<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>%s:</h2></div></div>
"""%header
    # parse remainder of args as  label1 value1 label2 value2 etc....
    data = args[1:]
    diter = iter(data)
    for d in diter:
        data = {}
        data["label"] = d
        data["value"] = diter.next()
        html += """  <div class="row"><div class="span2">%(label)s:</div><div class="span2">%(value)s</div></div>"""%data
    html += """
    </div>
</div>"""
    return html 

You cannot split the arguments across multiple lines to clean up the mess that is the call to the custom tag. So back to the drawing board.

I compromised with this:


{% specheader "History" %}
{% specdata "Date added to fleet" plane.dateAddedToFleet %}
{% specdata "Total Flight Time" plane.totalFlightTime|asTime %}
{% specdata "Total Number of Flights" plane.totalNumberOfFlights %}
{% specend %} 

It’s my favorite compromise between brevity and maintainability.

The custom tags to implement this are:


@register.simple_tag
def specheader(header):
    return """
<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>%s:</h2></div></div>"""%header

@register.simple_tag
def specdata(label,value):
    return '<div class="row"><div class="span2">%s:</div><div class="span2">%s</div></div>'%(label, value)

@register.simple_tag
def specend():
    return "</div></div>"

Which is also cleaner than the all-in-one tag.

It’s not for me, but Skylar Savland on github created a Django Template macros with args and kwargs gist that is another solution to this problem.

I’d love to hear ideas that solve this problem in a better way.

Posted in Django, Python | 8 Comments

Rate limiting with django-ratelimit

I was playing around with James Socol’s django-ratelimit tonight. It provides a decorator to rate-limit view functions. Very nice! I wanted to use it for login blocking, and some minor changes helped this out. My forked version of django-ratelimit is a available on GitHub It adds a message when a call is blocked and the ability to clear the count for given user.

Adding it to django-userena sign-in was as simple as:

in userena/views.py:


from ratelimit.decorators import ratelimit, clear
@ratelimit(field='identification',rate="5/m", method="POST", block=True, error_message="You have too many invalid login attempts.  Please try again later")
@secure_required
def signin(request, auth_form=AuthenticationForm,.....
.
.
.
     #after successful login
     clear(request, field='identification') ### clear rate limiting 

Posted in Django, Python | Leave a comment