<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://mopidy.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://mopidy.com/" rel="alternate" type="text/html" /><updated>2026-06-24T06:39:40+00:00</updated><id>https://mopidy.com/feed.xml</id><title type="html">Mopidy</title><subtitle>The extensible music server</subtitle><entry><title type="html">Mopidy 4.0 released</title><link href="https://mopidy.com/blog/2026/04/25/mopidy-4.0/" rel="alternate" type="text/html" title="Mopidy 4.0 released" /><published>2026-04-25T00:00:00+00:00</published><updated>2026-04-25T00:00:00+00:00</updated><id>https://mopidy.com/blog/2026/04/25/mopidy-4.0</id><content type="html" xml:base="https://mopidy.com/blog/2026/04/25/mopidy-4.0/"><![CDATA[<p>Mopidy 4.0 is a major release with very few functional changes. The focus has
been on modernizing the tech stack to keep Mopidy maintainable and enjoyable to
work on going forward.</p>

<p>In Mopidy 4.0 we’ve:</p>

<ul>
  <li>dropped support for old versions of our dependencies,</li>
  <li>rebuilt data models using Pydantic, so data is validated at the edges of the
application rather than failing silently on use,</li>
  <li>removed a few long-deprecated APIs,</li>
  <li>rebuilt the app startup sequence,</li>
  <li>made many modules explicitly private,</li>
  <li>added type hints to most of the source code, and</li>
  <li>rebuilt <a href="https://docs.mopidy.com/">our docs</a> using Zensical.</li>
</ul>

<!-- more -->

<p>These changes make the codebase less scary and more fun to work in, which
matters a lot for a volunteer-maintained project. You can read more in <a href="https://docs.mopidy.com/stable/changelog/#v400-2026-04-25">the full
changelog</a>.</p>

<h2 id="updated-extensions">Updated extensions</h2>

<p>All 12 extensions in the <a href="https://github.com/mopidy">mopidy</a> GitHub organization
have been updated to require Mopidy 4.0 and have gotten new major releases.</p>

<p>This includes <a href="https://github.com/mopidy/mopidy-spotify">mopidy-spotify</a>, which
finally has a non-pre-release version using <code class="language-plaintext highlighter-rouge">gst-plugin-spotify</code> and the Spotify
Web API 🎉</p>

<p>We can’t test all of them fully (we don’t have anyone with a Pandora
subscription, for instance), so please report any issues you run into.</p>

<h2 id="for-end-users">For end users</h2>

<p>There’s not a lot here for the average end user, and that’s fine. This release
is about laying a better foundation, and hopefully it’ll breathe some life back
into Mopidy development.</p>

<p>Packages are already on PyPI. Distribution packages will follow when the
packagers get around to it, including apt.mopidy.com, which now serves as a
backport channel for the latest Mopidy packages from Debian unstable.</p>

<h2 id="for-issue-reporters-and-pr-authors">For issue reporters and PR authors</h2>

<p>There’s a considerable backlog of open issues and PRs across the Mopidy repos.
If you’ve filed an issue or opened a PR, it’d be a big help if you could check
whether it’s still valid and rebase or update as needed. We now have a clean
slate, making it easier to get improvements shipped.</p>

<h2 id="for-extension-maintainers">For extension maintainers</h2>

<p>If you maintain a Mopidy extension, now’s the time to:</p>

<ul>
  <li>Bump your minimum Mopidy version to 4.0.</li>
  <li>Test against Mopidy 4.0 and cut a new release, even if nothing needed
changing, so users know your extension is ready.</li>
</ul>

<p>It’s also worth checking out the updated
<a href="https://github.com/mopidy/mopidy-ext-template">mopidy-ext-template</a>, which has
been heavily modernized. It now uses Copier, with much better support for
keeping existing projects in sync with template improvements, not just
bootstrapping new ones.</p>

<h2 id="for-distribution-packagers">For distribution packagers</h2>

<p>A few distributions packaged alpha versions during the long gap between
releases. We appreciate the enthusiasm, and hope those will be swapped out for
the release versions quickly, which will go a long way toward getting the
broader Mopidy ecosystem back into shape.</p>

<h2 id="want-to-help">Want to help?</h2>

<p>All extensions in the <a href="https://github.com/mopidy">mopidy</a> org are starting from
a fairly clean slate. If you’ve been thinking about getting involved, whether
fixing bugs, reviewing PRs, or helping maintain an extension you use, this is a
good moment to jump in. We’d love more hands on deck.</p>]]></content><author><name>Stein Magnus Jodal</name></author><category term="mopidy" /><category term="release" /><summary type="html"><![CDATA[Mopidy 4.0 is a major release with very few functional changes. The focus has been on modernizing the tech stack to keep Mopidy maintainable and enjoyable to work on going forward. In Mopidy 4.0 we’ve: dropped support for old versions of our dependencies, rebuilt data models using Pydantic, so data is validated at the edges of the application rather than failing silently on use, removed a few long-deprecated APIs, rebuilt the app startup sequence, made many modules explicitly private, added type hints to most of the source code, and rebuilt our docs using Zensical.]]></summary></entry><entry><title type="html">Mopidy 3 upgrade FAQ</title><link href="https://mopidy.com/blog/2019/12/27/mopidy-3-faq/" rel="alternate" type="text/html" title="Mopidy 3 upgrade FAQ" /><published>2019-12-27T00:00:00+00:00</published><updated>2019-12-27T00:00:00+00:00</updated><id>https://mopidy.com/blog/2019/12/27/mopidy-3-faq</id><content type="html" xml:base="https://mopidy.com/blog/2019/12/27/mopidy-3-faq/"><![CDATA[<p>Mopidy 3.0 is a backwards-incompatible release. This post aims to address
common questions that users and/or developers may have when they come to
upgrade.</p>

<!-- more -->

<h2 class="no_toc" id="questions">Questions</h2>

<ul id="markdown-toc">
  <li><a href="#whats-new-in-mopidy-30" id="markdown-toc-whats-new-in-mopidy-30">What’s new in Mopidy 3.0?</a></li>
  <li><a href="#should-i-upgrade-yet" id="markdown-toc-should-i-upgrade-yet">Should I upgrade yet?</a></li>
  <li><a href="#how-do-i-upgrade-to-mopidy-3" id="markdown-toc-how-do-i-upgrade-to-mopidy-3">How do I upgrade to Mopidy 3?</a></li>
  <li><a href="#why-did-you-drop-support-for-python-2" id="markdown-toc-why-did-you-drop-support-for-python-2">Why did you drop support for Python 2?</a></li>
  <li><a href="#there-are-numerous-versions-of-python-3-which-one-do-i-need" id="markdown-toc-there-are-numerous-versions-of-python-3-which-one-do-i-need">There are numerous versions of Python 3, which one do I need?</a></li>
  <li><a href="#what-about-mopidy-3-on-ubuntu-1804-lts" id="markdown-toc-what-about-mopidy-3-on-ubuntu-1804-lts">What about Mopidy 3 on Ubuntu 18.04 LTS?</a></li>
  <li><a href="#so-how-do-i-install-mopidy-3-on-ubuntu-1804-lts" id="markdown-toc-so-how-do-i-install-mopidy-3-on-ubuntu-1804-lts">So how do I install Mopidy 3 on Ubuntu 18.04 LTS?</a></li>
  <li><a href="#what-about-mopidy-3-on-debian-stretch" id="markdown-toc-what-about-mopidy-3-on-debian-stretch">What about Mopidy 3 on Debian Stretch?</a></li>
  <li><a href="#what-happened-to-the-mpd-frontend-and-the-local-backend" id="markdown-toc-what-happened-to-the-mpd-frontend-and-the-local-backend">What happened to the MPD frontend and the Local backend?</a></li>
  <li><a href="#why-doesnt-mopidy-extension-x-work" id="markdown-toc-why-doesnt-mopidy-extension-x-work">Why doesn’t Mopidy extension X work?</a></li>
  <li><a href="#when-will-mopidy-extension-x-support-mopidy-3" id="markdown-toc-when-will-mopidy-extension-x-support-mopidy-3">When will Mopidy extension X support Mopidy 3?</a></li>
  <li><a href="#do-i-need-to-remove-anything-from-mopidy-2" id="markdown-toc-do-i-need-to-remove-anything-from-mopidy-2">Do I need to remove anything from Mopidy 2?</a></li>
  <li><a href="#what-about-these-service-configuration-changes" id="markdown-toc-what-about-these-service-configuration-changes">What about these service configuration changes?</a></li>
</ul>

<h2 id="whats-new-in-mopidy-30">What’s new in Mopidy 3.0?</h2>

<p>The most significant change in Mopidy 3.0 is adding support for Python 3.7+ and
dropping support for Python 2.x. Other release highlights include:</p>

<ul>
  <li>
    <p>Moving the MPD frontend and Local backend out of Mopidy Core and into their own projects.</p>
  </li>
  <li>
    <p>The new <a href="https://mopidy.com/ext/">extension registry</a>.</p>
  </li>
  <li>
    <p>A configurable default web app for the HTTP frontend.</p>
  </li>
  <li>
    <p>Simplified logging configuration.</p>
  </li>
  <li>
    <p>Improvements to Mopidy’s Core API including removal of many long-deprecated APIs.</p>
  </li>
</ul>

<p>For a comprehensive list of changes please see the <a href="https://docs.mopidy.com/en/latest/changelog/">changelog</a>.</p>

<p>Mopidy 3 also brings new versions of all extensions, some of which include new
features. Most noticeably,
<a href="https://github.com/mopidy/mopidy-spotify/blob/master/CHANGELOG.rst#v400-2019-12-22">Mopidy-Spotify 4</a>
supports (read-only) playlists again, and also offers additional browse sections.</p>

<h2 id="should-i-upgrade-yet">Should I upgrade yet?</h2>

<p>Yes! The Debian packages for Mopidy and those extensions maintained under the
<a href="https://github.com/mopidy/">Mopidy GitHub organisation</a> should now be
available from <a href="https://apt.mopidy.com/">apt.mopidy.com</a> for all supported
architectures.</p>

<p>Likewise, packages for
<a href="https://docs.mopidy.com/en/latest/installation/arch/#arch-install">Arch Linux</a>
and everything required to <a href="https://docs.mopidy.com/en/latest/installation/pypi/">install from
source</a> is ready.</p>

<h2 id="how-do-i-upgrade-to-mopidy-3">How do I upgrade to Mopidy 3?</h2>

<p>This depends on how you installed Mopidy 2.x.
See our <a href="https://docs.mopidy.com/en/latest/installation/">documentation</a>.</p>

<h2 id="why-did-you-drop-support-for-python-2">Why did you drop support for Python 2?</h2>

<p><a href="https://pythonclock.org/">Python 2 will not be maintained after January 1,
2020</a> and there is no future for Python projects that
are not compatible with Python 3. Python 2 and Python 3 are similar but do have
significant differences and so there’s considerable burden in also supporting
Python 2. If you are limited to Python 2 then stay with <a href="https://docs.mopidy.com/en/release-2.3/changelog/">Mopidy
v2.3.1</a>.</p>

<h2 id="there-are-numerous-versions-of-python-3-which-one-do-i-need">There are numerous versions of Python 3, which one do I need?</h2>

<p>The minimum supported version is Python 3.7 but we also support newer versions
such as Python 3.8. Python 3.7 was primarily chosen as it, at the time of
porting, is the version of Python shipped in Debian stable (Buster). Python
3.7, or newer, is also available by default in Ubuntu 18.10, Arch Linux,
Fedora 29, and in macOS via Homebrew. You can see what the default version of
Python 3 is on your system by running <code class="language-plaintext highlighter-rouge">python3 --version</code>.</p>

<h2 id="what-about-mopidy-3-on-ubuntu-1804-lts">What about Mopidy 3 on Ubuntu 18.04 LTS?</h2>

<p>Ubuntu 18.04 (Bionic Beaver) is <a href="https://wiki.ubuntu.com/BionicBeaver">nearly 2 years
old</a> and <a href="https://wiki.ubuntu.com/LTS">Long Term
Support</a> releases are enterprise focused with
stability in mind; they are <em>not</em> designed for running cutting-edge software,
such as Mopidy 3. The next Ubuntu LTS release is 20.04 (Focal Fossa) and
scheduled for April 2020. It will ship with Python 3.8 and so Mopidy will work
out of the box with that. If you are stuck using Ubuntu 18.04 then you’ll find
it uses Python 3.6 by default. Getting Mopidy 3 running is possible, but
requires some work. One such way is detailed below.</p>

<p>Alternatively, you can continue using Mopidy v2.3.1 until Ubuntu 20.04 is
released - just be sure to use Mopidy’s <a href="https://docs.mopidy.com/en/release-2.3/">2.x
documentation</a> and only install old
Python 2 versions of any extensions from
<a href="https://pypi.org/search/?q=mopidy">PyPI</a>.</p>

<p>A Docker based installation of Mopidy 3 on Ubuntu 18.04 should also be possible.</p>

<h2 id="so-how-do-i-install-mopidy-3-on-ubuntu-1804-lts">So how do I install Mopidy 3 on Ubuntu 18.04 LTS?</h2>

<p>Newer versions of Python are available from Ubuntu’s software repositories and
installing Python 3.7 is as easy as running:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install -y python3.7
</code></pre></div></div>

<p>Next, follow the first <strong>three</strong> steps of the instructions for <a href="https://docs.mopidy.com/en/latest/installation/pypi/">installing from
source</a>. Then install
Mopidy <em>under Python 3.7</em> with:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo python3.7 -m pip install --ignore-installed mopidy
</code></pre></div></div>

<p>The GStreamer side of things is a little trickier. We need versions
of <code class="language-plaintext highlighter-rouge">python3-gi</code> and <code class="language-plaintext highlighter-rouge">python3-gst-1.0</code> that are compatible with Python 3.7 but
the versions available in Ubuntu 18.04
(<a href="https://packages.ubuntu.com/bionic/python3-gi">-gi</a>,
<a href="https://packages.ubuntu.com/bionic/python3-gst-1.0">-gst-1.0</a>) only support the
system Python version.</p>

<p>First up is pygobject: the Python 3 bindings for gobject-introspection
(<code class="language-plaintext highlighter-rouge">python3-gi</code>). This is easy to build from source using <code class="language-plaintext highlighter-rouge">pip</code>, once the
required dependencies have been installed:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install -y \
    libcairo2-dev \
    libffi-dev \
    libgirepository1.0-dev \
    libglib2.0-dev \
    python3.7-dev

sudo python3.7 -m pip install --ignore-installed --no-cache pygobject
</code></pre></div></div>

<p>The GStreamer Python binding overrides (<code class="language-plaintext highlighter-rouge">python3-gst-1.0</code>) are not so simple as
they are <a href="https://gitlab.freedesktop.org/gstreamer/gst-python/issues/25">not available from
PyPI</a>. The
easiest way is to get 3.7 compatible files from an alternate version of
<code class="language-plaintext highlighter-rouge">python3-gst-1.0</code>, and copy them into the Python 3.7 installation:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget http://archive.ubuntu.com/ubuntu/pool/universe/g/gst-python1.0/python3-gst-1.0_1.14.4-1_amd64.deb
ar x python3-gst-1.0_1.14.4-1_amd64.deb
tar -pxvf data.tar.xz
sudo mv usr/lib/python3/dist-packages/gi/overrides/* /usr/local/lib/python3.7/dist-packages/gi/overrides/
</code></pre></div></div>

<p>If you want to <a href="https://docs.mopidy.com/en/latest/running/terminal/">run Mopidy in a
terminal</a> then you are
all done and <code class="language-plaintext highlighter-rouge">python3.7 -m mopidy</code> should now work. But if you want to <a href="https://docs.mopidy.com/en/latest/running/service/">run
Mopidy as a service</a> then
there are a few more steps and things get a little messier.</p>

<p>Download the latest Debian package for Mopidy 3 (as of writing this is
v3.0.2 but adjust as required):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wget https://apt.mopidy.com/pool/main/m/mopidy/mopidy_3.0.2-1_all.deb
</code></pre></div></div>

<p>Find any missing dependencies by attempting to install; this will likely fail:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo dpkg -i mopidy_3.0.2-1_all.deb
</code></pre></div></div>

<p>Install those missing dependencies and then install again; this should succeed:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install --fix-broken
sudo dpkg -i mopidy_3.0.2-1_all.deb
</code></pre></div></div>

<p>Force the Mopidy service to use our Python 3.7 installation:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo sed -i 's/python3/python3.7/' /usr/bin/mopidy
</code></pre></div></div>

<p>Finally, remove packages we no longer need, including those left over from
Mopidy 2.x:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt autoremove \
    libcairo2-dev \
    libffi-dev \
    libgirepository1.0-dev \
    libglib2.0-dev
</code></pre></div></div>

<p>Be sure to install all Mopidy extensions from source using
<code class="language-plaintext highlighter-rouge">sudo python3.7 -m pip install mopidy-foo-extension</code>.</p>

<h2 id="what-about-mopidy-3-on-debian-stretch">What about Mopidy 3 on Debian Stretch?</h2>

<p>Debian Stretch (oldstable) is not supported. Mopidy 3 requires
GStreamer &gt;= v1.14.0 but <a href="https://packages.debian.org/stretch/libgstreamer1.0-0">Stretch provides
v1.10.x</a>. There are
<a href="https://gstreamer.freedesktop.org/releases/1.14">great new features in v1.14</a>
and now we get to finally start using them.</p>

<h2 id="what-happened-to-the-mpd-frontend-and-the-local-backend">What happened to the MPD frontend and the Local backend?</h2>

<p>The <a href="https://mopidy.com/ext/mpd">Mopidy-MPD</a> and
<a href="https://mopidy.com/ext/local">Mopidy-Local</a> extensions are no longer bundled
with Mopidy and have been moved to independent extension. We hope this will
help ease development and encourage contributions. After the move, Mopidy-Local
merged with Mopidy-Local-SQLite and Mopidy-Local-Images; the functionality of
these three projects is now available under one roof in Mopidy-Local. If you
used either of these extensions you will now need to explicitly install them.</p>

<p>To install Mopidy-MPD: <code class="language-plaintext highlighter-rouge">sudo python3 -m pip install mopidy-mpd</code></p>

<p>To install Mopidy-Local: <code class="language-plaintext highlighter-rouge">sudo python3 -m pip install mopidy-local</code>.</p>

<p>The configuration for Mopidy-Local has changed and you may need to merge/move
your previous settings. Refer to <a href="https://github.com/mopidy/mopidy-local#configuration">Mopidy-Local’s
documentation</a> for the
available config values.</p>

<h2 id="why-doesnt-mopidy-extension-x-work">Why doesn’t Mopidy extension X work?</h2>

<p>Some Mopidy extensions do not support Mopidy 3 yet. You can find information on
which ones do at our <a href="https://mopidy.com/ext/">extension registry</a>. Any Python
3 compatible extensions installed using your package manager should be updated
when you upgrade Mopidy. But any extensions that were installed from PyPI will
need to be explicitly re-installed for Python 3
e.g. <code class="language-plaintext highlighter-rouge">sudo python3 -m pip install Mopidy-dLeyna</code>.</p>

<h2 id="when-will-mopidy-extension-x-support-mopidy-3">When will Mopidy extension X support Mopidy 3?</h2>

<p>Extensions maintained under the <a href="https://github.com/mopidy/">Mopidy GitHub
organisation</a> have been ported to Python 3 and
support Mopidy 3.0. For those commmunity maintained extensions not yet ported to
Python 3, visit the project’s GitHub page for more info and also consider
lending the maintainer a helping hand. Please be patient during this
transitional period.</p>

<h2 id="do-i-need-to-remove-anything-from-mopidy-2">Do I need to remove anything from Mopidy 2?</h2>

<p>If <a href="https://docs.mopidy.com/en/latest/installation/pypi/">installed from source or
PyPI</a> you may want to
remove Mopidy 2 from your system, but it’s not strictly necessary. Mopidy on
Python 3 won’t in any way be affected by any remnants of Mopidy on Python 2.</p>

<p>Mopidy installed using your system package manager (e.g. apt) will
automatically remove the old Python 2 version of Mopidy as part of the upgrade.</p>

<h1 id="what-about-these-service-configuration-changes">What about these service configuration changes?</h1>

<p>When updating the Debian package you will probably get the following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Configuration file '/etc/mopidy/mopidy.conf'
 ==&gt; Modified (by you or by a script) since installation.
 ==&gt; Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
*** mopidy.conf (Y/I/N/O/D/Z) [default=N] ? 
</code></pre></div></div>

<p>If you enter <code class="language-plaintext highlighter-rouge">D</code> here it will display the differences. You’ll see the default
service-specific <code class="language-plaintext highlighter-rouge">[core]</code> and <code class="language-plaintext highlighter-rouge">[logging]</code> configuration has been removed (it
now lives elsewhere). The remaining differences will be anything you added
yourself e.g. account details for extensions, the path to your music files, a
custom audio output etc. You’ll probably still need all of that. The main
exception is any configuration for <a href="https://mopidy.com/ext/local/">Mopidy-Local</a>
as some things changed following the move, please check the project’s
<a href="https://github.com/mopidy/mopidy-local#configuration">documentation</a> for
details.</p>

<p>If you are not sure what to do, select option <code class="language-plaintext highlighter-rouge">Y</code> and get the new default
Mopidy 3 service configuration. You will still find your old configuration at
<code class="language-plaintext highlighter-rouge">/etc/mopidy/mopidy.conf.dpkg-old</code>, which you can compare against the output of
<code class="language-plaintext highlighter-rouge">sudo mopidyctl config</code> to see what configuration you actually still need to
specify in <code class="language-plaintext highlighter-rouge">/etc/mopidy/mopidy.conf</code> to obtain the setup you want. Afterwards,
feel free to delete <code class="language-plaintext highlighter-rouge">mopidy.conf.dpkg-old</code>.</p>]]></content><author><name>Nick Steel</name></author><category term="mopidy" /><category term="release" /><category term="python" /><summary type="html"><![CDATA[Mopidy 3.0 is a backwards-incompatible release. This post aims to address common questions that users and/or developers may have when they come to upgrade.]]></summary></entry><entry><title type="html">10 years of Mopidy</title><link href="https://mopidy.com/blog/2019/12/23/10y-of-mopidy/" rel="alternate" type="text/html" title="10 years of Mopidy" /><published>2019-12-23T00:00:00+00:00</published><updated>2019-12-23T00:00:00+00:00</updated><id>https://mopidy.com/blog/2019/12/23/10y-of-mopidy</id><content type="html" xml:base="https://mopidy.com/blog/2019/12/23/10y-of-mopidy/"><![CDATA[<p>Ten years ago today, on December 23, 2009, Mopidy was born. While chatting with
my friend and then-colleague Johannes Knutsen, we came up with the idea of
building an MPD server that could play music from Spotify instead of local
files.</p>

<p>This is the story of the first decade of Mopidy.</p>

<!-- more -->

<p>After a brief discussion of how it could work and what we could build upon,
Johannes came up with the name “Mopidy.” The name is, maybe quite obviously, a
combination of the consonants from “MPD” combined with the vowels from
“Spotify.” At the same time, the name is different enough from both of its
origins not to be mixed up with them. Even during the first few hours we had
some thoughts about maybe adding file playback and support for other backends
in the future. Thus we quickly appreciated that the “Mopidy” name would still
work, even if Spotify wasn’t always the sole focus of the project.</p>

<p>Within a couple of hours we had a Git repo with some plans written up. We
joined the #mopidy IRC channel on Freenode and we had recruited Thomas Adamcik
to the project. Over the next few years, he designed many of our most essential
components, including the extension system. Today, ten years later, Thomas is
still involved with Mopidy and many of its extensions.</p>

<p>After a couple of days, it worked! We had built a primitive MPD server in
Python that at least worked with the Sonata MPD client. On the backend side, we
used the reverse-engineered “despotify” library to interface with Spotify as
it already had some Python bindings available. For all three of us, coming
mostly from web development and Django, I believe we already had a feeling of
achievement and expanding horizons. If we could pull this off, we could build
anything.</p>

<p>The story of Mopidy is a story of thousands of small iterative improvements
that, over time, add up to something far greater than the sum of its parts. It
was a hack, but a hack with good test coverage from the very start, making
changes and iteration safe and joyful.</p>

<p>In March 2010 we released our first alpha release. Over the next decade this
would become the first of 74 releases, not counting the numerous releases of
the extensions we later extracted from Mopidy or built from the ground up.</p>

<p>Later in 2010, as we added an alternative Spotify backend using the official
libspotify library, we started seeing the first traces of our current system
architecture. At that time, you switched between the single active backend by
manually changing the config file and restarting Mopidy. Support for multiple
active backends wouldn’t come until much later, after we had built the muxing
“core layer” in-between the backend and frontend layers. However, multiple
frontends were supported from the start. The MPD server was the first frontend,
and during the first year, we added a second one with the Last.fm scrobbler.</p>

<p>By the end of 2010 we had made GStreamer a requirement and thrown out the
support for direct audio output to OSS and ALSA. In 2011 we built upon the
great power of GStreamer to support multiple outputs; this allowed us to play
audio locally whilst also streaming it to a Shoutcast/Icecast server at the same
time. This support for multiple outputs survived for about a year before we
removed it. Instead, we exposed the GStreamer pipeline configuration directly,
just like we still do today with the <code class="language-plaintext highlighter-rouge">audio/output</code> configuration. Streaming to
Icecast is also still possible but is involved enough to require specific
documentation for the setup. However, by exposing the GStreamer pipeline
directly, we didn’t have to guess what kind of installations people would use
Mopidy in and exposed the full power of GStreamer to our end-users.</p>

<p>We added support for Python 2.7, but we definitely didn’t plan to stay
with it for eight years. During the winter of 2010/2011, I designed and built the
<a href="https://pykka.readthedocs.io/">Pykka</a>
actor library based on the concurrency patterns we had established in Mopidy.
When we started using Pykka in Mopidy in March 2011, it already supported
Python 3.</p>

<p>Towards the end of the year, we added support for the Ubuntu Sound Menu and the
MPRIS D-Bus specification in our <a href="https://mopidy.com/ext/mpris/">third frontend</a>.</p>

<p>Most of 2012 went by without much happening other than a few maintenance
releases. However, in November, we released the almost revolutionary Mopidy
0.9 after finally building out the muxing core layer in-between frontends
and backends. Depending on the type of request from a frontend, the core layer
would either forward the request to the correct backend or, e.g., in the case
of search, fan out the request to all backends and then merge the returned
search results before passing the result back to the frontend. We had
accomplished one of our original goals from the very first day of development:
we had a music server that could play music from both Spotify and local files.</p>

<p>Less than a month later, the wheel turned again and we released Mopidy 0.10
with the HTTP frontend. This exposed the full Core API using JSON-RPC over a
WebSocket. With this it was suddenly possible to build clients for Mopidy
directly, instead of going through MPD.</p>

<p>In a lazy and ingenious moment, we decided that we had no interest in manually
keeping the Core API and the JSON-RPC API in sync for the indefinite future.
Thus, we based the JSON-RPC API on introspection of the Core API and included a
JSON-RPC endpoint which returned a data structure that described the full API.
On top of this, I built the <a href="https://github.com/mopidy/mopidy.js">Mopidy.js</a>
library and released it together with Mopidy 0.10. Mopidy.js uses the API
description data structure to dynamically build a mirror of our Core API in
JavaScript, working both on Node.js and in the browser.</p>

<p>Even as the JSON-RPC implementation and the Mopidy.js library became the
foundation for several popular Mopidy web clients over the next few years, no
bug was ever reported that originated in this library. To this day, I testament
this to two things: proper test-driven development and excellent code review by
Thomas, making these few weeks in November-December 2012 one of the highlights
of my years as an open source maintainer.</p>

<p>Jumping just a few months ahead to Easter 2013, the next revolution was about
to happen. In a single long and intense day, Thomas and I hashed out and
implemented Mopidy’s extension support. Up to this point, there was just one
Mopidy. Today, a search for “mopidy” on PyPI returns 127 results.</p>

<p>The Stream backend was created early in 2013, and later in the year, it learned
how to parse several playlist formats to find the streamable URL they
contained. This made it easy to build backend extensions for music services
that exposed playable URIs, like SoundCloud, Google Music, and thousands of
radio stations. The backends only had to find and present the playable streams
as a playlist or as a virtual file hierarchy; the heavy-lifting of actually
playing the audio could be fully delegated to Mopidy and its Stream backend.</p>

<p>By the end of 2013 we had performed the first round of shrinking Mopidy’s core.
The <a href="/ext/spotify/">Spotify support</a>,
<a href="/ext/scrobbler/">Last.fm scrobbler</a> and
<a href="/ext/mpris/">MPRIS server</a> were all
extracted to new extensions living outside the core project. I believe that
pulling extensions out of core has helped reduce the amount one must juggle in
one’s head to effectively develop on Mopidy.</p>

<p>In 2013 we eased the on-ramping for new users by automatically creating an
initial configuration file on the first run. Mopidy also got support for
announcing its servers through Zeroconf so they could be autodetected by
mobile apps, like <a href="https://mopidy.com/ext/mobile/">Mopidy-Mobile</a>.</p>

<p>Elsewhere in 2013, Wouter van Wijk built the first iterations of the
<a href="https://github.com/pimusicbox">Pi MusicBox</a>
distribution for Raspberry Pi. Pi MusicBox provided a turn-key jukebox
setup built on Mopidy. This made Mopidy more approachable for the masses that
didn’t know Mopidy, Python, or even Linux; allowing them to create their own
hi-fi setups.</p>

<p>The next year, in 2014, Fon launched a Kickstarter campaign to build a “modern
cloud jukebox” named
<a href="https://www.kickstarter.com/projects/fon/gramofon-modern-cloud-jukebox">Gramofon</a>.
It turned out that they based their prototype on
Mopidy and Javier Domingo Cansino from their development team started
submitting patches and becoming active in Mopidy development.</p>

<p>In the summer of 2014 we had our first real-life development sprint at
EuroPython in Berlin. Javier and I were joined by several newcomers that got up
and running with Mopidy development and squashed a few bugs.</p>

<p>Mopidy 0.19.5 was released on Mopidy’s fifth anniversary in December 2014. A
few months later, we released Mopidy 1.0. The release of Mopidy 1.0 did not
mark a breaking change, but rather the decision that we could commit to the
current APIs for a while and bring stability to the extension ecosystem.</p>

<p>In the summer of 2015, Thomas joined us as we had our second development sprint
at EuroPython in Bilbao, Javier’s hometown.</p>

<p>The year between the sprints of 2014 and 2015, and the 0.19, 1.0, and 1.1
releases, were quite significant when looking back at the project’s history.
They were not as notable in features as when we added multi-backend, the HTTP
API, and extension support back in 2012/2013. Still, they were significant in
that the project garnered lots of interest. Up to twenty different people
contributed code to each of these three releases.</p>

<p>More than five years ago, in July 2014,
I opened Mopidy’s <a href="https://github.com/mopidy/mopidy/issues/779">issue #779</a> for
tracking the port to Python 3. There were three large buckets of work that had
to be completed. First, our libspotify Python bindings had no Python 3 support.
Second, we needed to upgrade to GStreamer 1. Finally, we had to port Mopidy and
all of its extensions.</p>

<p>Over the next year, I rewrote <a href="https://pyspotify.readthedocs.io/">pyspotify</a>
from scratch using CFFI. Just a couple
of weeks before I shipped the final version, Spotify deprecated the libspotify
API. However, since they’ve never provided a replacement API for audio
playback, we’re still using pyspotify 2 and libspotify to play music from
Spotify more than four years later.</p>

<p>During the autumn of 2015 I ported Mopidy from GStreamer 0.10 to 1.x.
GStreamer 0.10 was quickly being deprecated, so this work was necessary solely
for Mopidy to continue being packaged in Debian and Ubuntu. It was a nice bonus
that the new PyGObject wrapper also supported Python 3. With the release of
Mopidy 2.0 in February 2016, the move to GStreamer 1 was complete, and thanks
to Thomas, we finally supported gapless playback.</p>

<p>Shortly after the 2.0 release, life caught up with several of the most active
contributors. A mix of more kids and more work threw Mopidy into a
three-year-long period with lower activity and almost exclusively maintenance
releases. The only significant development of Mopidy during this period was the
support for persisting playback and tracklist state across restarts,
contributed by Jens Lütjen, and released in 2.1 in 2017.</p>

<p>Jumping ahead to 2019. Five years after I wrote the tracking issue for moving
Mopidy to Python 3, the world looks quite different. Python 2.7’s announced
end-of-life is looming at the end of the year, and Python 3 is the standard for
all new projects.</p>

<p>So, finally, in the middle of October, we got started on the third and final
step toward Python 3.</p>

<p>Once we had a small part of the test suite running on both Python 2 and 3, it
took Nick Steel and myself about three weeks of porting modules one by one until
suddenly the full test suite was running. Once Mopidy without extensions ran
well on Python 3, we axed all Python 2 support, cleaned up all hacks left over
from the porting process, and reformatted the code with Black. All of a sudden
Mopidy felt like a modern Python codebase.</p>

<p>The six weeks since then have mostly been spent on extensions.</p>

<p>We’ve built a new <a href="/ext/">Mopidy extension registry</a>.
We believe that the new registry
will ease the discovery of extensions in general. Short-term, we also hope it
will help users navigate the extension ecosystem while it is temporarily split
in two between Python 2 and 3.</p>

<p>All extensions in the Mopidy GitHub organization are now running on
Python 3, as well as a few popular extensions elsewhere. In total, we have
almost 20 extensions compatible with Mopidy 3.0 on the day of the release.</p>

<p>Some extensions have also recently received some extra tender loving care.</p>

<p>The <a href="/ext/local/">Mopidy-Local</a>
extension was pushed out of core early in the Python 3
porting. After becoming an independent extension, Thomas Kemmer’s excellent
Mopidy-Local-SQLite and Mopidy-Local-Images were merged into Mopidy-Local. We
now have a single comprehensive extension for using Mopidy with pre-indexed
local music collections.</p>

<p>Next, Nick did a great job fixing up the
<a href="/ext/spotify/">Mopidy-Spotify</a> extension. Since
<a href="https://jodal.no/2016/02/18/guide-to-poor-api-management/">Spotify suddently broke the playlist part of libspotify</a>
a while ago, Mopidy-Spotify has been without functional playlist support.
It now uses the Spotify Web API for
everything related to playlists and Nick has continued adding several new
features using the Web API. Some are shipped in the release that went out
together with Mopidy 3.0, and more are right around the corner. Once complete,
Mopidy-Spotify will support everything Mopidy-Spotify-Web provides, once again
leaving us with a single comprehensive extension for using Mopidy with Spotify.</p>

<p>Just a few days ago, the
<a href="/ext/mpd/">Mopidy-MPD</a> frontend was pushed out to an extension
too. With this, we’ve come full circle from Mopidy being named after “MPD” and
“Spotify.” As of Mopidy 3.0, both Mopidy-MPD and Mopidy-Spotify are independent
extensions, and Mopidy core knows nothing of either. I wasn’t entirely sure
whether moving the MPD server would bring any benefits. Still, once the move
was complete, it was evident that Mopidy-MPD deserves to be a project by itself.
The split reduced the amount of code in Mopidy by 25% and cut the test suite
run time in half. Hopefully this will also make it easier for newcomers to start
contributing to either Mopidy-MPD or Mopidy itself.</p>

<p>Finally, December 22, the day before the Mopidy project’s 10th anniversary, we
published <a href="/blog/2019/12/22/mopidy-3.0/">Mopidy 3.0</a>.</p>

<p>Together with Mopidy 3.0, we uploaded ten updated extensions to PyPI, with at
least six more having compatible pre-releases, and, hopefully, final releases
over the next few days. For an up to date overview of what’s ready for Python 3
right now, the <a href="/ext/">extension registry</a> is the place to look.</p>

<p>It’s still early days for Mopidy 3.0. Our
<a href="https://github.com/mopidy/homebrew-mopidy/">Homebrew tap</a>
is up to date with the
new releases, and parts of Arch Linux are already up to date. Updated Debian
packages, both at
<a href="https://apt.mopidy.com/">apt.mopidy.com</a> and in Debian,
are still some days away.
Nonetheless, Mopidy 3.0 will definitively be a part of Ubuntu 20.04 LTS come
spring.</p>

<p>Now, go forth and update your extensions to work with Python 3.7+ and Mopidy
3.0.</p>

<p>In a week, Python 2.7 reaches end-of-life.
Mopidy, however, is ready for the next decade.</p>

<p><em>Thanks to <a href="https://github.com/kingosticks">Nick Steel</a> for reviewing this blog
post.</em></p>]]></content><author><name>Stein Magnus Jodal</name></author><category term="mopidy" /><category term="python" /><category term="mpd" /><category term="spotify" /><category term="gstreamer" /><summary type="html"><![CDATA[Ten years ago today, on December 23, 2009, Mopidy was born. While chatting with my friend and then-colleague Johannes Knutsen, we came up with the idea of building an MPD server that could play music from Spotify instead of local files. This is the story of the first decade of Mopidy.]]></summary></entry><entry><title type="html">Mopidy 3.0 released</title><link href="https://mopidy.com/blog/2019/12/22/mopidy-3.0/" rel="alternate" type="text/html" title="Mopidy 3.0 released" /><published>2019-12-22T00:00:00+00:00</published><updated>2019-12-22T00:00:00+00:00</updated><id>https://mopidy.com/blog/2019/12/22/mopidy-3.0</id><content type="html" xml:base="https://mopidy.com/blog/2019/12/22/mopidy-3.0/"><![CDATA[<p>The long-awaited Mopidy 3.0 is finally here, just in time for the Mopidy
project’s 10th anniversary on December 23rd!</p>

<p>Mopidy 3.0 is a backward-incompatible release in a pretty significant way:
Mopidy no longer runs on Python 2.</p>

<!-- more -->

<p><strong>Mopidy 3.0 requires Python 3.7 or newer.</strong></p>

<p>While extensions have been able to continue working without changes
throughout the 1.x and 2.x series of Mopidy, this time is different:</p>

<ul>
  <li>
    <p>All extensions must be updated to work on Python 3.7 and newer.</p>
  </li>
  <li>
    <p>Some extensions need to replace their use of a few long-deprecated APIs
that we’ve removed.
See <a href="https://docs.mopidy.com/en/latest/changelog/">the full changelog</a>
for details.</p>
  </li>
  <li>
    <p>Extension maintainers are also encouraged to update their project’s setup to
match our refreshed
<a href="https://github.com/mopidy/cookiecutter-mopidy-ext">extension cookiecutter</a>.</p>
  </li>
</ul>

<p>In parallel with the development of Mopidy 3.0, we’ve coordinated with a few
extension maintainers and upgraded almost 20 of the most popular extensions.
These will all be published shortly after the release of Mopidy 3.0.</p>

<p>We’ve also built a new <a href="/ext/">extension registry</a>, where you can quickly track
what extensions are ready for Python 3.</p>

<p>In other news, the <a href="/ext/mpd/">Mopidy-MPD</a> and <a href="/ext/local/">Mopidy-Local</a>
extensions have grown up and moved out to flourish as independent extension
projects. After the move, Mopidy-Local merged with Mopidy-Local-SQLite and
Mopidy-Local-Images, which are now both a part of the Mopidy-Local extension.</p>

<p>For further details,
please see <a href="https://docs.mopidy.com/en/latest/changelog/">the changelog</a>.</p>

<hr />

<p><em>To read more about the story behind Mopidy 3.0, see our next post,
<a href="/blog/2019/12/23/10y-of-mopidy/">10 years of Mopidy</a>.</em></p>]]></content><author><name>Stein Magnus Jodal</name></author><category term="mopidy" /><category term="release" /><summary type="html"><![CDATA[The long-awaited Mopidy 3.0 is finally here, just in time for the Mopidy project’s 10th anniversary on December 23rd! Mopidy 3.0 is a backward-incompatible release in a pretty significant way: Mopidy no longer runs on Python 2.]]></summary></entry><entry><title type="html">Mopidy-MPRIS 2.0 released</title><link href="https://mopidy.com/blog/2018/12/07/mopidy-mpris-2.0/" rel="alternate" type="text/html" title="Mopidy-MPRIS 2.0 released" /><published>2018-12-07T00:00:00+00:00</published><updated>2018-12-07T00:00:00+00:00</updated><id>https://mopidy.com/blog/2018/12/07/mopidy-mpris-2.0</id><content type="html" xml:base="https://mopidy.com/blog/2018/12/07/mopidy-mpris-2.0/"><![CDATA[<p>I’ve released <a href="https://github.com/mopidy/mopidy-mpris">Mopidy-MPRIS</a> 2.0, the
first major update to Mopidy-MPRIS in about 3.5 years.</p>

<p>Mopidy-MPRIS is a Mopidy extension that makes <a href="https://mopidy.com/">Mopidy</a>
controllable from other programs on the same machine through D-Bus. This makes
it possible to control Mopidy from various widgets in GNOME/KDE/etc, as well as
with keyboard media keys.</p>

<!-- more -->

<p>This release replaces the <code class="language-plaintext highlighter-rouge">python-dbus</code> D-Bus bindings with <code class="language-plaintext highlighter-rouge">python-pydbus</code> to
modernize the code base and prepare it for the move to Python 3. It also wires
up a lot of events so that various UI elements are immediately updated when the
server state changes.</p>

<p>As part of the release, the
<a href="https://github.com/mopidy/mopidy-mpris/blob/master/README.rst">documentation</a>
has been greatly extended, including a survey of some MPRIS clients and tips on
how to run Mopidy-MPRIS on the system bus. Throughout the documentation, I’ve
added calls for help wherever something isn’t working perfectly and I haven’t
figured it out yet. Even with these rough spots, this is easily the best
Mopidy-MPRIS release so far.</p>

<p>For all the details, check out the
<a href="https://github.com/mopidy/mopidy-mpris/blob/v2.0.0/CHANGELOG.rst">changelog</a>.</p>

<hr />

<p><em>This blog post was originally published at
<a href="https://jodal.no/2018/12/07/mopidy-mpris-2.0/">jodal.no</a>.</em></p>]]></content><author><name>Stein Magnus Jodal</name></author><category term="mopidy" /><category term="mpris" /><category term="python" /><summary type="html"><![CDATA[I’ve released Mopidy-MPRIS 2.0, the first major update to Mopidy-MPRIS in about 3.5 years. Mopidy-MPRIS is a Mopidy extension that makes Mopidy controllable from other programs on the same machine through D-Bus. This makes it possible to control Mopidy from various widgets in GNOME/KDE/etc, as well as with keyboard media keys.]]></summary></entry><entry><title type="html">Four years of JavaScript churn: Mopidy.js 1.0</title><link href="https://mopidy.com/blog/2018/12/02/4y-of-js-churn/" rel="alternate" type="text/html" title="Four years of JavaScript churn: Mopidy.js 1.0" /><published>2018-12-02T00:00:00+00:00</published><updated>2018-12-02T00:00:00+00:00</updated><id>https://mopidy.com/blog/2018/12/02/4y-of-js-churn</id><content type="html" xml:base="https://mopidy.com/blog/2018/12/02/4y-of-js-churn/"><![CDATA[<p>Yesterday, I released v1.0.0 of the <a href="https://github.com/mopidy/mopidy.js">Mopidy.js</a>
JavaScript library. Even though the library serves as the basis for most Mopidy
web clients and has been in active use since 2013, this was the first release
in almost four years.</p>

<p>Four years is quite a long time in the world of JavaScript.</p>

<!-- more -->

<p>In the beginning of October, I <a href="https://github.com/mopidy/mopidy/commit/1e0d7c6715dcf137759b272b6d5e1c0b77268c99">stopped
bundling</a>
Mopidy.js with the Mopidy Python project and thus had to update the Mopidy.js
documentation. While doing so, I tried to run the test suite, written using
<a href="https://github.com/busterjs">Buster.JS</a>, which has been abandoned for a few
years. To no avail, npm and Yarn were not able to install the library’s
development dependencies.</p>

<p>After four years of standing still while the fast-moving world of JavaScript
sped on, I seemed forced to spend some time on modernizing the library and
it’s development tooling to ensure that it would be maintainable going
forward.</p>

<p>I asked a couple of coworkers for advice on what to replace Buster.JS with that
could test a library in both Node.js and the browser, and what they would use
instead of Browserify today. I was quickly pointed towards
<a href="https://jestjs.io/">Jest</a> for testing and <a href="https://parceljs.org/">Parcel</a> for
zero-configuration builds.</p>

<p>Porting the full test suite–three times the size of the library–to Jest was
<a href="https://github.com/mopidy/mopidy.js/commit/fc1bd39e6251fc7306c200b81d969d6784972830">work</a>,
but mostly mechanical work. The only part I needed to read a bit up on was
Jest’s <a href="https://jestjs.io/docs/en/mock-functions">mocking capabilities</a>
compared to <a href="https://sinonjs.org/">Sinon.JS</a>.</p>

<h1 id="modernizing-development-tooling">Modernizing development tooling</h1>

<p>After getting the test suite running again the modernization continued.</p>

<p>JSHint and a <a href="https://github.com/mopidy/mopidy.js/commit/6cec1fc5f46095b53693a76871eb673926bba73f">list of
rules</a>
were replaced with <a href="https://eslint.org/">ESLint</a> and <a href="https://github.com/airbnb/javascript">Airbnb’s style
guide</a>.</p>

<p>All code was reformatted with <a href="https://prettier.io/">Prettier</a>. This required
<a href="https://github.com/mopidy/mopidy.js/commit/720f550991078073a56c36033d497bf027a2aadb">almost no
configuration</a>,
once figuring out how to make ESLint and Prettier stay friends. However, the
experience of getting an entirely consistent code style without any effort is
priceless. I can accept most differences from my previous styles in exchange
for not having to do the work myself and not having to enforce that my
contributors and coworkers do the same. Formatters like Prettier,
<a href="https://black.readthedocs.io/">Black</a>, <code class="language-plaintext highlighter-rouge">gofmt</code>, and <code class="language-plaintext highlighter-rouge">rustfmt</code> are here to stay
and will probably be an integral part of all new programming languages.</p>

<p>The Mopidy.js code was originally hand-written ES5 using all the hard-learned
tricks of the trade from David Herman’s splendid book <a href="http://effectivejs.com/">Effective
JavaScript</a>. At least it was splendid in 2013. Now it
was
<a href="https://github.com/mopidy/mopidy.js/commit/52e36e19a185a868b8bf50e443a3b7bd14d50853">converted</a>
to a modern ES6 class with a single click in VS Code, passing all tests bar one:
you cannot instantiate an ES6 class without the <code class="language-plaintext highlighter-rouge">new</code> keyword.</p>

<p>Removing Buster.JS and JSHint reduced the project’s Grunt setup a bit. The move
from Browserify for browser builds and Uglify for minification to Parcel lead
to the removal of Grunt entirely, and the replacement of <a href="https://github.com/mopidy/mopidy.js/commit/e2e2118003ec33421ce4ad40cf9116ac7908a896">a monitor height or
two</a>
of Grunt config with the command <code class="language-plaintext highlighter-rouge">parcel build src/mopidy.js</code>.</p>

<h1 id="reducing-runtime-dependencies">Reducing runtime dependencies</h1>

<p>The time had now come to runtime dependencies.</p>

<p>The <code class="language-plaintext highlighter-rouge">faye-websocket</code> package was replaced with the
<a href="https://www.npmjs.com/package/ws">ws</a> package, which made it possible to
replace our own Node.js/browser <a href="https://github.com/mopidy/mopidy.js/commit/703d18b82c34ab779471aa0cb2e5d90a3c39cb26">compatibility
layer</a>
for WebSocket usage with
<a href="https://www.npmjs.com/package/isomorphic-ws">isomorphic-ws</a>.</p>

<p>Since the last release of Mopidy.js in 2015, ES6’s Promise implementation has
become quite universally available. Thus,
<a href="https://www.npmjs.com/package/when">when</a> could be replaced with Promise,
<a href="https://github.com/mopidy/mopidy.js/commit/23ecc224d642bac0ab5b411acc370906af510348">shrinking</a>
the minified library from 42 kB to 12 kB.</p>

<p><a href="https://github.com/busterjs/bane">BANE</a>, an event emitter library that was
part of the now-dead Buster.JS testing tool, was replaced with the
<code class="language-plaintext highlighter-rouge">EventEmitter</code> implementation from Node.js’ standard library. Parcel
helpfully and entirely automatically included the <code class="language-plaintext highlighter-rouge">EventEmitter</code> implementation
from Node.js as part of the web bundle, without having to add a dependency on
<a href="https://www.npmjs.com/search?q=events">one of the npm packages</a> that has
extracted this lib from the Node.js standard library.</p>

<h1 id="making-demo-applications">Making demo applications</h1>

<p>Once everything was modernized, I added two demo applications to the project.</p>

<p>The
<a href="https://github.com/mopidy/mopidy.js/commit/d600608034ae4362a02443441ce3ed5dfa7bdedc">web-based</a>
application is served by Parcel’s web server. The configuration needed? Add
<code class="language-plaintext highlighter-rouge">parcel examples/web.html</code> as the <code class="language-plaintext highlighter-rouge">start</code> script in <code class="language-plaintext highlighter-rouge">package.json</code> and I was
done: <code class="language-plaintext highlighter-rouge">yarn start</code> now runs the demo web app on <code class="language-plaintext highlighter-rouge">http://localhost:1234</code>, with
automatic code reloading on source changes.</p>

<p>For the Node.js <a href="https://github.com/mopidy/mopidy.js/commit/9db5a903024cae2d6aed7ec52a25919ad9af6b7a">console
application</a>,
I quickly remembered that while promises are better than callbacks, they can
still quickly become quite mind-boggling to work with. Enter async/await,
spreading like wildfire from language to language the last few years, and
fully available in Node.js since 2017. You just have to remember to create all
the promises you need, and only then <code class="language-plaintext highlighter-rouge">await</code> them. This makes it possible for
the promises to be fulfilled in parallel instead of sequentially, avoiding that
the sequential round trip times to the server add up.</p>

<p>Somewhere around here I read a bit up on TypeScript and tested out porting the
library to TypeScript with great help from VS Code. Due to Mopidy.js’ tiny static
API and quite large dynamic API, automatically generated based on the API
description retrieved from the server, this didn’t seem a worthy path to go
down this time around. However, the experience was a good one, and I’ll
probably revisit TypeScript in the future on other projects.</p>

<p>Finally, the Mopidy.js docs were
<a href="https://github.com/mopidy/mopidy.js/commit/20c0fdc13c9f5e4558e9a2205200fec51fd8abc3">moved</a>
from the Mopidy docs to the Mopidy.js project and updated accordingly. Being
used to writing docs in <a href="https://www.sphinx-doc.org/">Sphinx</a>, Markdown’s lack
of features like generating a table of contents can feel limiting. Of course,
<a href="https://github.com/neilsustc/vscode-markdown">several</a> VS Code
extensions can automatically generate a ToC and keep it up to date every
time you save your file.</p>

<h1 id="wrapping-up">Wrapping up</h1>

<p>In the late 1990s, I tweaked JavaScript-based web calculators. In the 2000s I
surfed with JavaScript disabled and required apps we built to work without it.
From 2011 through 2015, I spent a small majority of my time in frontend
JavaScript. Since the summer of 2016, I’ve done very little, if any, JavaScript.</p>

<p>It seems that my relationship with and usage of JavaScript varies like the
tide, even if on another time scale. After a while away, JavaScript as of late
2018 seems to be in a lot better place than in 2015. The language is nicer.
The chore of project setup and maintenance is reduced. Tooling is better, and
way better integrated. I’ve felt the JavaScript fatigue before, but from my
perspective, it seems like many things are stabilizing in a quite good place.</p>

<p>I’d go as far as claiming that the exercise of modernizing Mopidy.js
and its development tooling was, at times, fun and inspiring.</p>

<p>Here’s to four more years of Mopidy.js. Then I might be back with a port to
WebAssembly, implemented in Rust, or a language yet to be designed. We’ll see!</p>

<hr />

<p><em>This blog post was originally published at
<a href="https://jodal.no/2018/12/02/4y-of-js-churn/">jodal.no</a>.</em></p>]]></content><author><name>Stein Magnus Jodal</name></author><category term="mopidy" /><category term="javascript" /><summary type="html"><![CDATA[Yesterday, I released v1.0.0 of the Mopidy.js JavaScript library. Even though the library serves as the basis for most Mopidy web clients and has been in active use since 2013, this was the first release in almost four years. Four years is quite a long time in the world of JavaScript.]]></summary></entry><entry><title type="html">Debian packaging of Mopidy</title><link href="https://mopidy.com/blog/2014/10/28/debian-packaging/" rel="alternate" type="text/html" title="Debian packaging of Mopidy" /><published>2014-10-28T00:00:00+00:00</published><updated>2014-10-28T00:00:00+00:00</updated><id>https://mopidy.com/blog/2014/10/28/debian-packaging</id><content type="html" xml:base="https://mopidy.com/blog/2014/10/28/debian-packaging/"><![CDATA[<p>My first upload to Debian as a Debian Maintainer, Mopidy 0.19.4-3, landed in
Debian testing today, well in time for the upcoming freeze.</p>

<p>The new version adjusts the LSB facilities the sysvinit script depends on, to
make sure that DNS lookups, DBus (used by Mopidy-MPRIS), and Avahi (used for
Zeroconf service publishing) are available before Mopidy starts.</p>

<!-- more -->

<p>Most importantly, maybe, the new package adds a systemd service file. The
sysvinit init script included a custom action called “run”, which is used to
run Mopidy subcommands with the same user and configuration as the system
service use. To replace this with something that can also be used on a system
running systemd, a new executable called <code class="language-plaintext highlighter-rouge">mopidyctl</code> has been added. The new
executable does the same: it runs Mopidy with the same user and
configuration as the init system uses to start Mopidy as a system service.</p>

<p>In short, <code class="language-plaintext highlighter-rouge">sudo service mopidy run config</code> now becomes <code class="language-plaintext highlighter-rouge">sudo mopidyctl config</code>,
both on systems running sysvinit and systems running systemd.</p>

<hr />

<p><em>This blog post was originally published at
<a href="https://jodal.no/2014/10/28/debian-packaging/">jodal.no</a>.</em></p>]]></content><author><name>Stein Magnus Jodal</name></author><category term="debian" /><category term="python" /><category term="mopidy" /><summary type="html"><![CDATA[My first upload to Debian as a Debian Maintainer, Mopidy 0.19.4-3, landed in Debian testing today, well in time for the upcoming freeze. The new version adjusts the LSB facilities the sysvinit script depends on, to make sure that DNS lookups, DBus (used by Mopidy-MPRIS), and Avahi (used for Zeroconf service publishing) are available before Mopidy starts.]]></summary></entry><entry><title type="html">Bringing the Mopidy music server to the browser</title><link href="https://mopidy.com/blog/2013/01/09/mopidy-in-the-browser/" rel="alternate" type="text/html" title="Bringing the Mopidy music server to the browser" /><published>2013-01-09T00:00:00+00:00</published><updated>2013-01-09T00:00:00+00:00</updated><id>https://mopidy.com/blog/2013/01/09/mopidy-in-the-browser</id><content type="html" xml:base="https://mopidy.com/blog/2013/01/09/mopidy-in-the-browser/"><![CDATA[<p><a href="https://mopidy.com/">Mopidy</a> is a music server written in
Python. It plays music from various sources, including local disk and Spotify.
Mopidy can be remote-controlled by, among others, <abbr title="Music Player Daemon">MPD</abbr> clients.</p>

<p>In Mopidy 0.10, released in the middle of December, we added an HTTP frontend.
The HTTP frontend takes Mopidy’s full core API and makes it available from
JavaScript in the browser. This means that you now can make your own web
clients for Mopidy in JavaScript, and Wouter van Wijk has already started on
<a href="https://github.com/pimusicbox/mopidy-musicbox-webclient">his client</a> (<em>updated
link</em>).</p>

<p>I’d like to write a bit about how we made the HTTP client.</p>

<!-- more -->

<p>From the start, I was quite clear on having enough work to do on the server-side
of Mopidy. Thus, making my own client to test out REST APIs and to make
sure the APIs we exposed were usable was mostly out of the question. Also,
making a REST API would require us to spend huge amounts of time on figuring
out how to best remap our procedural “core API” to REST resources. When the
remapping would be complete, if ever, we would be stuck with the maintenance of
yet another API on top of the core API, with all the associated mismatches and
hacks required to match them up. We got enough of them in the MPD frontend.</p>

<p>Wouter had experimented a bit himself with making an HTTP frontend and
suggested that we should go for an <abbr title="Remote Procedure Call">RPC</abbr> model. I was reluctant at first. RPC reminds me of SOAP, the
nineties, and other similar ideas that I don’t exactly regard as the state of
the art.</p>

<p>After some thought, I figured that with an RPC API, I could probably make the
entire API on the server-side dynamically. In other words, I could get it done
in a lot less time than a REST API, and it would maintain itself. At least, it
would maintain itself to any degree such a thing is possible. If we added a new
method to the core API, it would immediately be available through the HTTP RPC
API. This would of course also mean that if we changed anything in the existing
core API, we’d break any web client that uses that part of the API. After some
discussion, we decided that we were OK with this drawback. After all, we intend
the core API to become quite stable with time, where time approximately equals
the release of v1.0. Also, the initial development work and future maintenance
work associated with making an RPC API were within our reach, without
distracting us for too long from work on the core code, the MPD and MPRIS
frontends, and the local storage and Spotify backends. You see, we already got
a healthy list of moving parts to keep oiled and working.</p>

<p>The part that got me excited on an RPC API (of all things to get
excited about) was the insight that if I added some introspection support to
the API, I could make a JavaScript library to rebuild the entire API in the
browser. So, instead of just providing a web service endpoint URL to potential
client providers, we could offer them a complete API in the browser. Ready for
development. Queue your first music track in a few minutes of development.
That’s a good value proposition for aspiring client developers if you ask me.</p>

<p>So, I made a new HTTP frontend. It started a CherryPy web server. Then it
plugged ws4py into CherryPy, and we got a working WebSocket. Then I made my
custom RPC API, using JSON as the transport format. I sent messages from
Chrome’s console, and music started playing. It worked. It wasn’t tested, but I
was happy so far.</p>

<p>Then Thomas, my main co-developer, wise as always, pasted the URL to the
<a href="http://www.jsonrpc.org/specification">JSON-RPC 2.0 specification</a>. Humph, I
thought, not leaving it much chance. I read through the rather short spec and
concluded that it was really close to what I’d reinvented, minus support for
calls with both positional and named arguments at the same time.</p>

<p>Cutting it short, I spent the next day or so implementing JSON-RPC 2.0, this
time with tests. I plugged it into the HTTP frontend, and it worked.</p>

<p>Now you might say: Why didn’t you use one of the 25 or so existing JSON-RPC
implementations on PyPI. Because there are 25 or so. How am I to review them in
less time than it takes to implement the perfect one for my needs? Many of the
alternatives provide examples of how to execute a Python file, and then
magically a web server will be running. That’s not a selling point to me since
JSON-RPC got nothing to do with webservers or the message transport for that
matter. JSON-RPC is simply a mapping between a JSON format and method calls. It
should be implemented by some function/object that accepts JSON, makes the
required Python calls, and then returns the return values as JSON again. That’s
it. No web server. Maybe some API introspection.</p>

<p>Digression aside, I’m considering extracting and releasing our JSON-RPC
adapter. Then it’ll be N+1 <a href="https://xkcd.com/927/">competing standards</a>, eh, I
mean, implementations.</p>

<p>Next up was the JavaScript library. The main discussion here was actually where
to place the code in our pure-Python repo. Bikeshedding of easily reversible
decisions continues to be the easiest discussions to have. We ended on <code class="language-plaintext highlighter-rouge">js/</code> in
the root of the repo. How imaginative of us.</p>

<p>The first thing in any new JavaScript project is, of course, to set up
<a href="http://www.busterjs.org/">Buster.JS</a> for testing. I also tried out the <a href="https://gruntjs.com/">Grunt
build tool</a> for the first time. (My friend Pål recently
wrote an <a href="https://ruudud.github.io/2012/12/22/grunt/">introduction to Grunt</a>
featured at HN and in JavaScript Weekly.) Buster.JS in combination with Grunt
and <a href="http://phantomjs.org/">PhantomJS</a> was a delight. If you simply run
<code class="language-plaintext highlighter-rouge">grunt watch</code> and then modify a source file, your code is linted and tested
in a headless browser in second or so. This makes JavaScript development for
the browser feel like server-side development. If this sounds interesting,
check out <a href="https://github.com/mopidy/mopidy.js">our JavaScript project
setup</a> (<em>updated link</em>).</p>

<p>TODO</p>

<ul>
  <li>Mopidy.js usage examples</li>
  <li>Invitation to develop clients</li>
</ul>

<hr />

<h3 id="note-from-august-2017">Note from August 2017</h3>

<p>This is a blog post draft that was originally written in January 2013,
left unattended for 1689 days, and rediscovered and published unedited in
August 2017.</p>

<p>During the five years since Mopidy entered the browser with its HTTP JSON-RPC
API and the Mopidy.js JavaScript library, many successful Mopidy web
clients have been built on top of this foundation. The APIs themselves have
survived the test of time and have required minimal maintenance, just as I
hoped when implementing the APIs back in November 2012.</p>

<p>To quickly address the above TODOs from January 2013: Usage examples can
be found in the <a href="https://docs.mopidy.com/en/latest/api/js/">Mopidy docs</a>, and
an invitation to develop clients wasn’t needed, as <a href="https://docs.mopidy.com/en/latest/ext/web/">a
dozen clients</a> was made without
it.</p>

<hr />

<p><em>This blog post was originally published at
<a href="https://jodal.no/2017/08/26/mopidy-in-the-browser/">jodal.no</a>.</em></p>]]></content><author><name>Stein Magnus Jodal</name></author><category term="api" /><category term="mopidy" /><category term="python" /><category term="javascript" /><category term="web" /><category term="websocket" /><summary type="html"><![CDATA[Mopidy is a music server written in Python. It plays music from various sources, including local disk and Spotify. Mopidy can be remote-controlled by, among others, MPD clients. In Mopidy 0.10, released in the middle of December, we added an HTTP frontend. The HTTP frontend takes Mopidy’s full core API and makes it available from JavaScript in the browser. This means that you now can make your own web clients for Mopidy in JavaScript, and Wouter van Wijk has already started on his client (updated link). I’d like to write a bit about how we made the HTTP client.]]></summary></entry></feed>