ShrimpWorksThe musings, learnings, photos, code and hobbies of Kenneth Watson. Featuring Java, PHP, JavaScript, Linux and other random tutorials, guides and projects.
http://shrimpworks.za.net/
Mon, 19 Feb 2018 20:23:35 +0200Mon, 19 Feb 2018 20:23:35 +0200Jekyll v3.4.3Running Unreal Tournament 99 on Linux (part 2)<p><img src="/assets/posts/2018-02-03-ut-on-linux/ut-logo.png" alt="" class="image-right" /></p>
<p>After <a href="/2018/02/03/ut-on-linux/">installing and running Unreal Tournament (UT99)</a> using Wine,
I thought it would be good to try running a Linux-native version of the game.</p>
<p>Thankfully, this is reasonably easy, and seems very stable - more so than
running under Wine.</p>
<p>Before you start, you’ll need the original Unreal Tournament game files, most
easily obtainable by <a href="/2018/02/03/ut-on-linux/">installing the Steam version using Wine</a>.</p>
<!--more-->
<h2 id="part-two">Part Two</h2>
<p>As per the previous part, I’m using Debian Sid, so these instruction may need
some manual conversion to your distribution of choice, and you’ll need to
enable multi-arch (UT is 32-bit only).</p>
<ul>
<li>
<p>To begin, we’ll use <code class="highlighter-rouge">game-data-packager</code> to build Debian packages, which also
includes scripts to download and apply the latest patch.
<a href="https://wiki.debian.org/Games/GameDataPackager">Game Data Packager</a> is really super cool, and can build
<code class="highlighter-rouge">deb</code> packages for loads of games. It’s worked pretty well for me getting
Freespace 2 running as well for example. Install it now:</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>sudo aptitude install game-data-packager game-data-packager-runtime
</code></pre>
</div>
</li>
<li>
<p>Now, we’ll build the shared data (maps, textures, music, etc) and the actual
executable binary packages. Pass the path to your UT install (here, I’m
passing it the path to the Steam install I did in Part One):</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>game-data-packager ut99 --everything ~/.wine/ut/drive_c/Steam/steamapps/common/Unreal<span class="se">\ </span>Torunament/ --binary-executables
</code></pre>
</div>
</li>
<li>
<p>Once this is done, you’ll have three packages you can install, and they can
be installed using <code class="highlighter-rouge">dpkg</code>:</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>sudo dpkg -i unreal-ut99-shared-data_200+58_all.deb
<span class="gp">$ </span>sudo dpkg -i ut99_451+58_i386.deb
<span class="gp">$ </span>sudo dpkg -i ut99-data_451+58_all.deb
</code></pre>
</div>
</li>
<li>The game depends on SDL 1.2, and will also a require 32-bit PulseAudio OSS
pre-load library for sound to work:
<code class="highlighter-rouge">bash
$ sudo aptitude install libsdl1.2debian:i386 libpulsedsp:i386
</code></li>
<li>
<p>As of this writing, there’s a long-outstanding
<a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=845802">bug with the <code class="highlighter-rouge">padsp</code> script</a> which can’t launch 32-bit
applications. The the bug report includes a suggested fix:</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>sudo cp /usr/bin/padsp /usr/bin/padsp32
<span class="gp">$ </span>sudo sed -i <span class="s1">'s/\/x86_64-linux-gnu\/pulseaudio\//\/i386-linux-gnu\/pulseaudio\//g'</span> /usr/bin/padsp32
</code></pre>
</div>
<p>This provides a new 32-bit capable <code class="highlighter-rouge">padsp32</code> pre-loader command, which we’ll
use to launch the game.</p>
</li>
<li>
<p>Now, you’ll need to attempt running the game. Don’t worry if it fails or
likely doesn’t have sound at the moment. This step is primarily to seed the
<code class="highlighter-rouge">~/.loki/ut</code> directory, where the local game files will be placed, which
we’ll modify shortly. Launch with the <code class="highlighter-rouge">padsp32</code> command as follows:</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>padsp32 ut99
</code></pre>
</div>
<p>Quit the game if it worked, and look at the contents of <code class="highlighter-rouge">~/.loki/ut</code> - you
should now see a familiar-looking <code class="highlighter-rouge">System</code> directory layout and contents.</p>
</li>
<li>Now, lets get a newer OpenGL renderer, with better support for things like
decals and detail textures, hugely improving the graphics of the game.
Download the UTGLR renderer from <a href="http://www.letsplayut.com/">letsplayut.com</a>
(<a href="/assets/posts/2018-02-19-ut-on-linux-2/OpenGLDrv.so">mirror download</a>) and place it in <code class="highlighter-rouge">~/.loki/ut/System</code>. You’ll
need to remove the current symlink first:
<code class="highlighter-rouge">bash
$ unlink ~/.loki/ut/System/OpenGLDrv.so
</code></li>
<li>Modify <code class="highlighter-rouge">~/.loki/ut/System/UnrealTournament.ini</code> to make use of this renderer,
and while we’re here, change the audio device:
<code class="highlighter-rouge">properties
[Engine.Engine]
GameRenderDevice=OpenGLDrv.OpenGLRenderDevice
RenderDevice=OpenGLDrv.OpenGLRenderDevice
AudioDevice=Audio.GenericAudioSubsystem
</code></li>
<li>Now, run the game again with <code class="highlighter-rouge">padsp32 ut99</code>, hopefully there’s sound, and a
better looking game!</li>
<li>Refer to the <a href="http://www.cwdohnal.com/utglr/settings.html">UTGLR Settings</a> page for information about
other rendering options you might tweak, and also refer to
<a href="/2018/02/03/ut-on-linux/">part one</a> for setting the frame rate and limit if desired.</li>
</ul>
<p>That’s it. You should <em>hopefully</em> have a fully Linux-native working Unreal
Tournament installation. It’s also fully compatible with all multiplayer
servers I tried.</p>
<p>You can also install mods and maps by installing them under the <code class="highlighter-rouge">~/.loki/ut</code>
directory - just create <code class="highlighter-rouge">Maps</code>, <code class="highlighter-rouge">Textures</code>, <code class="highlighter-rouge">Music</code> directories under there,
and extract maps and mods to the appropriate places, and they’ll show up
in-game.</p>
<p>I’d like to perhaps investigate writing some simple scripts to manage
installing maps and things into the appropriate places, to make life easier
and UT on Linux even more appealing.</p>
<p>For some additional info in case you have any other issues, check some of the
points on the <a href="https://pcgamingwiki.com/wiki/Unreal_Tournament#Linux">PC Gaming Wiki</a>.</p>
Mon, 19 Feb 2018 00:00:00 +0200http://shrimpworks.za.net/2018/02/19/ut-on-linux-2/
http://shrimpworks.za.net/2018/02/19/ut-on-linux-2/DebianLinuxUnreal TournamentLinuxGamingRunning Unreal Tournament 99 on Linux (part 1)<p><img src="/assets/posts/2018-02-03-ut-on-linux/ut-logo.png" alt="" class="image-right" /></p>
<p>With all the talk of Unreal Tournament 4 possibly being cancelled one of these
days, due to Epic’s runaway success with Fortnite, I’ve decided there’s really
no reason to not be playing UT99.</p>
<p>Thus, we set about trying to run it on modern hardware, with a modern Linux
installation.</p>
<p>As much as this is about setting things up on Linux, it’s also partially my own
attempt at some knowledge preservation, as a lot of this stuff ends up being
forgotten or lost over time (it’s been almost 20 years! a lot of the old sites
and things you expect to find this info on simply do not exist anymore :()</p>
<p>This is part one of two, and will focus on installing and running the game
using Wine.</p>
<!--more-->
<h2 id="part-one---wine">Part One - Wine</h2>
<p>You more than likely don’t have a CD/DVD-ROM any more, so you Steam is the
obvious first port of call. Simply installing Steam via <code class="highlighter-rouge">winetricks</code> will
thereafter allow you to log into your Steam account, and install <em>Unreal
Tournament: Game of the Year</em> edition.</p>
<p>As usual, the details given here are Debian-specific, but you
should be able to translate everything to your distribution of choice.</p>
<p>Some notes about my system setup, which may provide insight into some
prerequisites:</p>
<ul>
<li>Debian Sid/Unstable 64bit</li>
<li>I have a native working Steam installation, which implies multi-arch setup
with various i386 libraries already installed to support Steam
(see <a href="https://wiki.debian.org/Steam">the Debian wiki</a>)</li>
<li>Non-free Nvidia driver 384.111 (see <a href="https://wiki.debian.org/NvidiaGraphicsDrivers">the Debian wiki</a>)</li>
<li>Using PulseAudio</li>
<li>I am using Wine 3.0</li>
</ul>
<h3 id="installing-with-steam-under-wine">Installing with Steam under Wine</h3>
<ul>
<li><a href="https://wiki.winehq.org/Debian">Install wine</a></li>
<li>
<p>Get the latest <a href="https://github.com/Winetricks/winetricks"><code class="highlighter-rouge">winetricks</code></a>:</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
<span class="gp">$ </span>chmod +x winetricks
<span class="gp">$ </span>sudo mv winetricks /usr/local/bin
</code></pre>
</div>
</li>
<li>
<p>Create a new <code class="highlighter-rouge">WINEPREFIX</code> for UT:</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span><span class="nv">WINEPREFIX</span><span class="o">=</span>~/.wine/ut wineboot -i
</code></pre>
</div>
</li>
<li>
<p>Install Steam (I chose to install it to <code class="highlighter-rouge">C:\Steam</code> for ease of use):</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span><span class="nv">WINEPREFIX</span><span class="o">=</span>~/.wine/ut winetricks steam
</code></pre>
</div>
</li>
<li>Once Steam is installed, launch it and install Unreal Tournament GOTY</li>
<li>Download the <a href="http://www.cwdohnal.com/utglr/">Enhanced OpenGL Renderer</a> version 3.7
(<a href="/assets/posts/2018-02-03-ut-on-linux/utglr37.zip">mirror download</a>), extract <code class="highlighter-rouge">OpenGLDrv.dll</code> and place it into
<code class="highlighter-rouge">~/.wine/ut/drive_c/Steam/steamapps/common/Unreal Torunament/System/</code>,
overwriting the existing file.
<ul>
<li>This fixes things like brightness adjustment and supports things like
decals and detail textures, providing much better visuals.</li>
</ul>
</li>
<li>
<p>At this point, I could not get the game to start up and show me the initial
renderer selection, so I had to edit the <code class="highlighter-rouge">System/UnrealTournament.ini</code> file
first, to make use of the OpenGL renderer. Open the file in a text editor,
and set the following:</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="err">[Engine.Engine]</span>
<span class="py">GameRenderDevice</span><span class="p">=</span><span class="s">OpenGLDrv.OpenGLRenderDevice</span>
<span class="py">RenderDevice</span><span class="p">=</span><span class="s">OpenGLDrv.OpenGLRenderDevice</span>
</code></pre>
</div>
<ul>
<li>If the game does start for you and launches the first-run renderer
selection window, choose “Show all devices” in that window and choose
“OpenGL Support”.</li>
</ul>
</li>
<li>After this, launch the game in Steam, and away you go.</li>
<li>
<p>To adjust the FPS cap (vsync is forced on by default), modify
<code class="highlighter-rouge">UnrealTournament.ini</code> again with the following (where 200 is something not
insane):</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="err">[OpenGLDrv.OpenGLRenderDevice]</span>
<span class="py">FrameRateLimit</span><span class="p">=</span><span class="s">200</span>
<span class="py">SwapInterval</span><span class="p">=</span><span class="s">0</span>
</code></pre>
</div>
<p><code class="highlighter-rouge">SwapInterval</code> is pretty much “Vsync”, with options of <code class="highlighter-rouge">-1</code> (driver select),
<code class="highlighter-rouge">0</code> (off), or <code class="highlighter-rouge">1</code> (on). A <code class="highlighter-rouge">FrameRateLimit</code> value is <em>required</em>, or the game
will execute as fast as possible, and be unplayable (think old DOS games
being played on a PC with the Turbo button on).</p>
</li>
</ul>
<p>There are some downsides to running via Wine, especially with a manually
managed Wine install like this. In particular it’s simply unpleasant to have
to deal with the paths involved when modifying your <code class="highlighter-rouge">User.ini</code> and the
aforementioned <code class="highlighter-rouge">UnrealTournament.ini</code>, although some simple symlinks and
scripts should make it easier.</p>
<p>I have found that often the game fails to launch successfully via Steam, and I
have to find and kill the <code class="highlighter-rouge">UnrealTorunament.exe</code> process and try again.</p>
<p>Running the game through Steam also obviously requires you to start up a
dedicated Steam instance every time you play.</p>
<p>None of these problems are unresolvable, so at this point, we have a reasonably
working UT install suitable, suitable for installing mods and maps into,
playing online and offline, etc. and should last us for the next 20 years.</p>
<p>Part two will use this Wine installation to create a native Debian install
so we can free ourselves of the need for Steam, and create a cleaner running
environment.</p>
Sat, 03 Feb 2018 00:00:00 +0200http://shrimpworks.za.net/2018/02/03/ut-on-linux/
http://shrimpworks.za.net/2018/02/03/ut-on-linux/DebianLinuxUnreal TournamentLinuxGamingPublishing Server Status to StatsD with no additional software<p>I recently wanted to set up a couple of rough monitoring services to keep track
of simple server status, load, disk etc. While there are options available like
<a href="https://munin-monitoring.org/">Munin</a> which can do this by installing agents
on the machines to be monitored, I wanted something a little simpler and more
portable.</p>
<p>I’m quite fond of the StatsD + Graphite + Grafana stack, which is quite easy to
run thanks to <a href="https://hub.docker.com/r/kamon/grafana_graphite/">Kamon’s grafana_grafite</a>
Docker image, and I realised you can actually quite simply write counters,
gauges and timers to StatsD using nothing but the standard Linux tools <code class="highlighter-rouge">nc</code> and
<code class="highlighter-rouge">cron</code>.</p>
<p>For example, every minute on each server being monitored, a simple <code class="highlighter-rouge">cron</code> job
is executed which uses <code class="highlighter-rouge">nc</code> to write a bunch of information to my StatsD
service:</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="nv">HOST</span><span class="o">=</span><span class="k">$(</span>hostname<span class="k">)</span>
<span class="nv">STAT_HOST</span><span class="o">=</span><span class="s2">"statsd-host"</span>
<span class="nv">STAT_PORT</span><span class="o">=</span>8215
<span class="c"># load average</span>
<span class="nb">echo</span> <span class="s2">"load.</span><span class="nv">$HOST</span><span class="s2">.avg:</span><span class="sb">`</span>cat /proc/loadavg | cut -d <span class="s1">' '</span> -f 1 | awk <span class="s1">'{print $1*100}'</span><span class="sb">`</span><span class="s2">|g"</span> | nc -w 1 -u <span class="nv">$STAT_HOST</span> <span class="nv">$STAT_PORT</span>
<span class="c"># memory</span>
<span class="nb">echo</span> <span class="s2">"memory.</span><span class="nv">$HOST</span><span class="s2">.perc.free:</span><span class="sb">`</span>free | grep Mem | awk <span class="s1">'{print $3/$2 * 100.0}'</span><span class="sb">`</span><span class="s2">|g"</span> | nc -w 1 -u <span class="nv">$STAT_HOST</span> <span class="nv">$STAT_PORT</span>
<span class="nb">echo</span> <span class="s2">"memory.</span><span class="nv">$HOST</span><span class="s2">.bytes.total:</span><span class="sb">`</span>free -b | grep Mem | awk <span class="s1">'{print $2}'</span><span class="sb">`</span><span class="s2">|g"</span> | nc -w 1 -u <span class="nv">$STAT_HOST</span> <span class="nv">$STAT_PORT</span>
<span class="nb">echo</span> <span class="s2">"memory.</span><span class="nv">$HOST</span><span class="s2">.bytes.used:</span><span class="sb">`</span>free -b | grep Mem | awk <span class="s1">'{print $3}'</span><span class="sb">`</span><span class="s2">|g"</span> | nc -w 1 -u <span class="nv">$STAT_HOST</span> <span class="nv">$STAT_PORT</span>
<span class="c"># disk</span>
<span class="nb">echo</span> <span class="s2">"disk.</span><span class="nv">$HOST</span><span class="s2">.kbytes.total:</span><span class="sb">`</span>df -k --output<span class="o">=</span>size / | grep -v <span class="o">[</span>a-z]<span class="sb">`</span><span class="s2">|g"</span> | nc -w 1 -u <span class="nv">$STAT_HOST</span> <span class="nv">$STAT_PORT</span>
<span class="nb">echo</span> <span class="s2">"disk.</span><span class="nv">$HOST</span><span class="s2">.kbytes.used:</span><span class="sb">`</span>df -k --output<span class="o">=</span>used / | grep -v <span class="o">[</span>a-z]<span class="sb">`</span><span class="s2">|g"</span> | nc -w 1 -u <span class="nv">$STAT_HOST</span> <span class="nv">$STAT_PORT</span>
<span class="nb">echo</span> <span class="s2">"disk.</span><span class="nv">$HOST</span><span class="s2">.kbytes.avail:</span><span class="sb">`</span>df -k --output<span class="o">=</span>avail / | grep -v <span class="o">[</span>a-z]<span class="sb">`</span><span class="s2">|g"</span> | nc -w 1 -u <span class="nv">$STAT_HOST</span> <span class="nv">$STAT_PORT</span>
<span class="c"># mail queues</span>
<span class="k">for </span>i <span class="k">in </span>maildrop hold incoming active deferred bounce; <span class="k">do </span><span class="nb">echo</span> <span class="s2">"postfix.</span><span class="nv">$HOST</span><span class="s2">.queues.</span><span class="k">${</span><span class="nv">i</span><span class="k">}</span><span class="s2">:</span><span class="sb">`</span>find /var/spool/postfix/<span class="k">${</span><span class="nv">i</span><span class="k">}</span> -type f | wc -l<span class="sb">`</span><span class="s2">|c"</span>; <span class="k">done</span> | nc -w 1 -u <span class="nv">$STAT_HOST</span> <span class="nv">$STAT_PORT</span>
</code></pre>
</div>
<p>It’s perhaps a bit inefficient in places, but gets the job done fairly well.
One minute resolution may be a bit rough, but it’s sufficient for most of these
data points which don’t change too dramatically over time.</p>
<p>Some other more specific variations include HTTP accesses, ping times, etc.
Pretty much any parameter you can parse down to a single number can be
published as a counter, gauge or timer to StatsD, and then neatly
graphed over time.</p>
Sat, 27 Jan 2018 00:00:00 +0200http://shrimpworks.za.net/2018/01/27/linux-statsd/
http://shrimpworks.za.net/2018/01/27/linux-statsd/DebianStatsDMonitoringLinuxAurial, HTML5 Subsonic Music Player<p><img src="/assets/posts/2017-05-29-aurial.png" alt="" class="image-left" /></p>
<p>I have finally decided to <a href="https://github.com/shrimpza/aurial/releases">release version 1.0</a> of <a href="https://github.com/shrimpza/aurial">Aurial</a>, my implementation of a music player/client for the <a href="http://subsonic.org/">Subsonic</a> music server.</p>
<p>I started this around two years ago, some time after switching my primary desktop from Windows to Linux, and I really missed <a href="https://www.foobar2000.org/">foobar2000</a> - it has been my primary music player ever since. Unfortunately I have an irrational aversion to using Wine to run Windows applications, and none of the native music players on Linux felt good to me. As I already ran a Subsonic music server, I thought I’d just make use of that.</p>
<p>The existing browser-based clients for Subsonic were either too basic, or the state of their code and some implementation features made me uncomfortable. I just wanted a nice music player that allowed me to browse my collection similar to how I did in foobar2000 (using Subsonic’s ID3 tag based APIs, rather than the directory-based browsing offered by other clients), perhaps manage playlists, make ephemeral queues, and importantly, scrobble played tracks.</p>
<p>Podcasts, videos, and other things some clients support don’t interest me at all, and are a bit out of scope of a foobar2000-like client I beleive.</p>
<p>Aurial allows me to build a music player the way I prefer to browse, manage and play music (which admitedly, is quite heavily influenced by my prior foobar200 configuration and usage habits).</p>
<p><a href="/assets/posts/2017-05-29-aurial_shot.png"><img src="/assets/posts/2017-05-29-aurial_shot_t.png" alt="" class="image-centre" /></a></p>
<p>This was my first attempt at a <a href="https://facebook.github.io/react/">React</a> application, and it started off simply enough, with JSX transpiling and stuff happening directly in the browser. At some point <a href="https://babeljs.io/">Bable</a> was no longer available for browsers, which led to my adoption of <a href="https://webpack.js.org/">Webpack</a> (and eventually Webpack 2) for producing builds.</p>
<p>This also led to things like needing some sort of CI, and I’ve recently begun producing builds via <a href="https://travis-ci.org/shrimpza/aurial">TravisCI</a> which automates building the application, and <a href="https://shrimpza.github.io/aurial/">deploying it to GitHub Pages</a>, which I think is pretty neat.</p>
<p>I also got to play with HTML5’s <code class="highlighter-rouge">&lt;audio/&gt;</code> a bit, as the player library I was using previously had some reliance on Flash, and was occassionally tricky to coax into using HTML rather than that. The result is infinitely smaller and less complex audio playback implementation (it’s amazing how much easier life is when you ignore legacy support).</p>
<p>Anyway, altogether it’s been fun, and as I’m using it contantly, it’s always evolving bit by bit. Hopefully someone else finds it useful too.</p>
Mon, 29 May 2017 00:00:00 +0200http://shrimpworks.za.net/2017/05/29/aurial/
http://shrimpworks.za.net/2017/05/29/aurial/MusicJavaScriptReactSubsonicDevelopmentClient-Side Processing of Images with JavaScript Before Uploading<p>The title’s quite silly unfortunately, but I was recently doing some experimentation with uploading images to <a href="https://couchdb.apache.org/">CouchDB</a> directly from a browser. I needed to scale the images before storage, and since I was talking directly to the CouchDB service without any kind of in-between API services or server-side scripts, needed a way to achieve this purely on the client.</p>
<p>Thanks to modern APIs available in browsers, combined with a Canvas, it’s actually reasonably simple to process a user-selected image prior to uploading it to the server without the need for any third-party libraries or scripts.</p>
<!--more-->
<p>In the simple example below, as soon as the user selects an image using the file input, we use a <a href="https://developer.mozilla.org/en-US/docs/Web/API/FileReader"><code class="highlighter-rouge">FileReader</code></a> to load the image data, which then hands the data to an <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image"><code class="highlighter-rouge">Image</code></a>. As soon as the image has loaded, it creates a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API"><code class="highlighter-rouge">Canvas</code></a>, copies itself onto the canvas, and (for this example) simply draws some text over everything.</p>
<p>When the image has been sufficiently manimulated in the browser, the canvas is converted to a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob"><code class="highlighter-rouge">Blob</code></a>, placed into a <a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData"><code class="highlighter-rouge">FormData</code></a> instance, and uploaded to a basic server-side script via the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"><code class="highlighter-rouge">Fetch</code></a> API.</p>
<p>This example’s usage of drawing a text “watermark” over the selected image is incredibly basic, but the Canvas API is farirly comprehensive, allowing you to do everything from simply scaling the image for the purposes of thumbnail generation, to more in-depth image processing (use all the free image processing power on client machines, rather than post-processing these images on your servers).</p>
<p>In fact, there’s no need to use source images - you could generate images entirely in the browser and simply upload those using the same methods.</p>
<p>Here’s the client-sode code. Afterward is also a simple PHP script for the purposes of this example, to accept the uploaded image.</p>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="c">&lt;!-- upload.html --&gt;</span>
<span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// when the user selects an image</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"image"</span><span class="p">).</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">"change"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">image</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">files</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="c1">// assumes single selection</span>
<span class="c1">// draw a watermark over the image, and when we get the result back, upload it immediately</span>
<span class="nx">addWatermark</span><span class="p">(</span><span class="nx">image</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">img</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">form</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FormData</span><span class="p">();</span>
<span class="nx">form</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">"image"</span><span class="p">,</span> <span class="nx">img</span><span class="p">.</span><span class="nx">blob</span><span class="p">,</span> <span class="nx">img</span><span class="p">.</span><span class="nx">fileName</span><span class="p">);</span> <span class="c1">// create a form field "image" with the upload data and original file name</span>
<span class="c1">// post the file to our server script</span>
<span class="nx">fetch</span><span class="p">(</span><span class="s1">'upload.php'</span><span class="p">,</span> <span class="p">{</span>
<span class="na">method</span><span class="p">:</span> <span class="s1">'POST'</span><span class="p">,</span>
<span class="na">body</span><span class="p">:</span> <span class="nx">form</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">r</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// simply display the result from the server</span>
<span class="nx">r</span><span class="p">.</span><span class="nx">text</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="nx">text</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">})</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="kd">var</span> <span class="nx">addWatermark</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">file</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// the user-selected image will be loaded into this image</span>
<span class="kd">var</span> <span class="nx">img</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Image</span><span class="p">();</span>
<span class="c1">// when it's loaded, we can perform any kind of processing we need on it</span>
<span class="nx">img</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// create the canvas so we can draw stuff</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'canvas'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">ctx</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="s1">'2d'</span><span class="p">);</span>
<span class="c1">// for our purposes, scale the canvas to match the source image</span>
<span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">img</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
<span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">img</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
<span class="c1">// draw the source image on the canvas</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">drawImage</span><span class="p">(</span><span class="nx">img</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">img</span><span class="p">.</span><span class="nx">width</span><span class="p">,</span> <span class="nx">img</span><span class="p">.</span><span class="nx">height</span><span class="p">);</span>
<span class="c1">// just draw some watermark text over the image</span>
<span class="c1">// we could do anything else the canvas allows us to do (which is a lot)</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">font</span> <span class="o">=</span> <span class="s2">"40px sans-serif"</span><span class="p">;</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillStyle</span> <span class="o">=</span> <span class="s1">'#666'</span><span class="p">;</span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillText</span><span class="p">(</span><span class="s2">"The watermark or something"</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">40</span><span class="p">);</span>
<span class="c1">// convert the canvas to a Blob, and call a callback so the caller can do something with it</span>
<span class="nx">canvas</span><span class="p">.</span><span class="nx">toBlob</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">blob</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">callback</span><span class="p">({</span>
<span class="na">blob</span><span class="p">:</span> <span class="nx">blob</span><span class="p">,</span>
<span class="na">fileName</span><span class="p">:</span> <span class="nx">file</span><span class="p">.</span><span class="nx">name</span>
<span class="p">});</span>
<span class="p">},</span> <span class="nx">file</span><span class="p">.</span><span class="nx">type</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// the file reader triggers the whole process, once it's loaded from the user's selected image</span>
<span class="kd">var</span> <span class="nx">fileReader</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FileReader</span><span class="p">();</span>
<span class="nx">fileReader</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// setting the image source will trigger the image.onload event above</span>
<span class="nx">img</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">result</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// load the file data</span>
<span class="nx">fileReader</span><span class="p">.</span><span class="nx">readAsDataURL</span><span class="p">(</span><span class="nx">file</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;body&gt;</span>
Select image to upload:
<span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"file"</span> <span class="na">name=</span><span class="s">"image"</span> <span class="na">id=</span><span class="s">"image"</span> <span class="na">accept=</span><span class="s">"image/*"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre>
</div>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="c">&lt;!-- upload.php --&gt;</span>
<span class="cp">&lt;?php</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_FILES</span><span class="p">[</span><span class="s2">"image"</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$check</span> <span class="o">=</span> <span class="nb">getimagesize</span><span class="p">(</span><span class="nv">$_FILES</span><span class="p">[</span><span class="s2">"image"</span><span class="p">][</span><span class="s2">"tmp_name"</span><span class="p">]);</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$check</span> <span class="o">!==</span> <span class="kc">false</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$targetFile</span> <span class="o">=</span> <span class="s2">"/tmp/"</span> <span class="o">.</span> <span class="nb">basename</span><span class="p">(</span><span class="nv">$_FILES</span><span class="p">[</span><span class="s2">"image"</span><span class="p">][</span><span class="s2">"name"</span><span class="p">]);</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">move_uploaded_file</span><span class="p">(</span><span class="nv">$_FILES</span><span class="p">[</span><span class="s2">"image"</span><span class="p">][</span><span class="s2">"tmp_name"</span><span class="p">],</span> <span class="nv">$targetFile</span><span class="p">))</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"File stored at "</span> <span class="o">.</span> <span class="nv">$targetFile</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"Failed to store image"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"File is not an image"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"No image to upload"</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">?&gt;</span>
</code></pre>
</div>
Tue, 07 Mar 2017 00:00:00 +0200http://shrimpworks.za.net/2017/03/07/image-upload-javascript/
http://shrimpworks.za.net/2017/03/07/image-upload-javascript/JavaScriptPHPDevelopmentPS3 Sixaxis with Bluetooth on Debian Sid<p><img src="/assets/posts/2016-12-18-sixaxis.png" alt="" class="image-right" /></p>
<p>Continuing to <a href="/2016/12/16/lirc-and-kodi/">tweak</a> my <a href="/2016/06/10/kodi-on-debian-sid/">Kodi setup</a>, I thought it would be fun to attempt connecting a PS3 Sixaxis controller to it, since the HTPC I’m using has built-in bluetooth.</p>
<p>Contrary to what most of the internet seems to say on the subject for Debian/Ubuntu systems, which seems to involve third-party tools and sometimes compiling things, I found the process much simpler on a modern system.</p>
<!--more-->
<p>Here are the basics (since this is an HTPC I’m configuring over SSH, this is all non-visual stuff):</p>
<ul>
<li>First, if you haven’t used Bluetooth on the target system yet, make sure it’s set up and working:
<ul>
<li>execute <code class="highlighter-rouge">lsusb</code> and verify the presence of a Bluetooth device, and that it’s firmware is loaded (if not, you’ll see <code class="highlighter-rouge">(No firmware)</code> next to it’s name)</li>
<li>after making sure the device is available, install the <code class="highlighter-rouge">bluetooth</code> package via <code class="highlighter-rouge">apt-get</code> or <code class="highlighter-rouge">aptitude</code></li>
<li>make sure the Bluetooth service is running with <code class="highlighter-rouge">systemctl status bluetooth.service</code></li>
<li>as a quick test to make sure BT is working, turn on a bluetooth device and run <code class="highlighter-rouge">hcitool scan</code> to see if the PC finds it</li>
</ul>
</li>
<li>If you have working Bluetooth, the first step is to plug the Sixaxis controller into the PC using a USB cable and turn it on (hit the PS button). This will register/pair the controller.
<ul>
<li>to verify, you should be able to run <code class="highlighter-rouge">systemctl status bluetooth.service</code> again, and see notifications about the controller’s connection.</li>
</ul>
</li>
<li>After pairing via USB, unplug the controller, hit the PS button again to power it on, and execute <code class="highlighter-rouge">bluetoothctl</code>.
<ul>
<li>You should see an entry like <code class="highlighter-rouge">[NEW] Device 00:00:00:00:00:00 PLAYSTATION(R)3 Controller</code> (where <code class="highlighter-rouge">00:00:00:00:00:00</code> is the mac address of your controller).</li>
<li>If you’re seeing periodic entries like <code class="highlighter-rouge">[CHG] Device 00:00:00:00:00:00 Connected: yes/no</code>, execute the command <code class="highlighter-rouge">trust 00:00:00:00:00:00</code>, and it should flag the controller as a trusted device.</li>
</ul>
</li>
<li>Once done, you should have a working Bluetooth PS3 controller which you can use to control Kodi and play games with.</li>
</ul>
<p>My steps are a bit verbose for (hopefully) clarity, but should take no more than 5 minutes and you shouldn’t need to resort to the installation of 3rd party repositories or software, or compile anything yourself.</p>
Sun, 18 Dec 2016 00:00:00 +0200http://shrimpworks.za.net/2016/12/18/ps3-sixaxis-on-debian-sid/
http://shrimpworks.za.net/2016/12/18/ps3-sixaxis-on-debian-sid/DebianbluetoothsixaxisLinuxSoftwareHardwareLirc 0.9.4 and Kodi on Debian Sid<p>This is a small follow-on on from the <a href="/2016/06/10/kodi-on-debian-sid/">Kodi on Debian Sid guide</a> I did earlier this year to get <code class="highlighter-rouge">lirc</code> (IR remote support) working once more, following an upgrade to version 0.9.4, which changes how the <code class="highlighter-rouge">lirc</code> services and configuration work (<em>shakes fist at systemd</em>).</p>
<p>After upgrading and following all the instructions in <code class="highlighter-rouge">/usr/share/doc/lirc/README.Debian.gz</code>, I was left with the problem of Kodi not responding to any remote input at all.</p>
<p>Firstly, I had to re-source my remote’s configuration (<code class="highlighter-rouge">mceusb</code>) from the <a href="https://sourceforge.net/p/lirc-remotes/code/ci/master/tree/remotes/">lirc git repository</a>. Place the <code class="highlighter-rouge">*.lircd.conf</code> file from there into <code class="highlighter-rouge">/etc/lirc/lircd.conf.d/</code> and remove/rename other <code class="highlighter-rouge">.lircd.conf</code> files already in that directory.</p>
<p>Now, running <code class="highlighter-rouge">irw</code> and pressing some buttons on your remote should show you the button pressed and the configuration used.</p>
<p>Next up, Kodi fails to connect to the IR device. There are two trivial but non-obvious solutions:</p>
<p>Firstly, without changing any of the default configuration generated by the migration process outlined in the lirc README file, simply change your Kodi starup command as follows:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>kodi --lircdev /var/run/lirc/lircd
</code></pre>
</div>
<p>Alternatively, you may change the lirc configutation, to put the device file back where Kodi expects it:</p>
<div class="highlighter-rouge"><pre class="highlight"><code># in /etc/lirc/lirc_options.conf:
output = /dev/lircd
</code></pre>
</div>
<p>Then end result should be you happily continuing with your life.</p>
Fri, 16 Dec 2016 00:00:00 +0200http://shrimpworks.za.net/2016/12/16/lirc-and-kodi/
http://shrimpworks.za.net/2016/12/16/lirc-and-kodi/DebianKodiHTPClircLinuxSoftwareSydney Photos<p><img src="/assets/posts/2016-12-10-sydney.jpg" alt="" class="image-center" /></p>
<p>I recently spent some time in Australia, specifically Sydney and Melbourne, and took a bunch of photos from a few parks and interesting places in Sydney (unfortunately I was pretty ill and didn’t get out very far in Melbourne).</p>
<p>I really enjoyed the number of parks and amount of greenery around the city centres.</p>
<p><a href="/gallery/2016-10-sydney/">All the Sydney images are up here</a>.</p>
Sat, 10 Dec 2016 00:00:00 +0200http://shrimpworks.za.net/2016/12/10/sydney/
http://shrimpworks.za.net/2016/12/10/sydney/PhotosAustraliaRandomEclipse<p><a href="/assets/posts/2016-09-01.jpg"><img src="/assets/posts/2016-09-01_t.jpg" alt="" class="image-center full-width" /></a></p>
<p>Today’s solar eclipse, as viewed from Johannesburg, South Africa, through the lense of a Canon SX50 at 50x optical zoom, through some eclipse viewing eyeware from the 90s.</p>
Thu, 01 Sep 2016 00:00:00 +0200http://shrimpworks.za.net/2016/09/01/eclipse/
http://shrimpworks.za.net/2016/09/01/eclipse/PhotosSolar EclipseRandomKodi and Steam on Debian Sid<p><img src="/assets/posts/2016-06-10-debian-kodi-steam.png" alt="" class="image-right" /></p>
<p>I recently went through the process of reinstalling the media PC connected to my
TV, which I use to run Kodi for movies and TV, and Steam in Big Picture mode,
which allows me to stream Windows-only games from my desktop to the couch.</p>
<p>I thought it would be useful to describe my setup and the process to achieve it,
in case anyone else is interested in creating their own custom Kodi/Debian/Steam
builds.</p>
<!--more-->
<h3 id="the-setup">The Setup</h3>
<p>The PC is a several-years-old “Xtreamer” box, which is a small form-factor media
PC with a dual-core Atom CPU, NVidia mobile graphics, 4GB RAM, a 32GB SSD and a
built-in IR received for remotes. An XBox 360 controller is connected via USB
wireless adapter for gaming.</p>
<p>The ethernet port fried in a storm some time ago, so it now uses a USB ethernet
adapter.</p>
<p>All media is stored on a shared server elsewhere, and the machine was running
XBMCBuntu for several years.</p>
<h3 id="installing-debian">Installing Debian</h3>
<p>To keep things as light-weight as possible, I’ve gone with a fairly simple and
bare-bones installation. Also, since this is a multimedia machine, I would like
it to remain fairly up-to-date, so I’m going with Debian Unstable (Sid).</p>
<p>Since I need the USB ethernet adapter to work, I decided to go with an <a href="http://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/">ISO image
which includes non-free firmware</a>.
Since I’m also going to be installing Nvidia’s proprietary drivers, there’s no
point trying to stick to the 100% free and open model here.</p>
<p>After Debian’s installed, a few additional packages to make life easier are
required: <code class="highlighter-rouge">vim</code> and <code class="highlighter-rouge">sudo</code>.</p>
<p>I like to use <code class="highlighter-rouge">sudo</code> as a general Good Practice, rather than just doing
everything as root. Add your non-root user to the <code class="highlighter-rouge">sudo</code> group:</p>
<p><code class="highlighter-rouge">$ adduser username sudo</code></p>
<p>You can now log in as a normal user.</p>
<p>The next step is to upgrade the installation to the latest (sid). This is done
my editing <code class="highlighter-rouge">/etc/apt/sources.list</code> and changing <code class="highlighter-rouge">stretch</code>, <code class="highlighter-rouge">jessie</code> or whatever
default release name is listed to <code class="highlighter-rouge">sid</code>. Also enable <code class="highlighter-rouge">non-free</code> and <code class="highlighter-rouge">contrib</code>
sources at the same time.</p>
<p>After an <code class="highlighter-rouge">aptitude update</code> and <code class="highlighter-rouge">aptitude dist-upgrade</code>, a quick reboot makes
sure everything’s clean and ready for the next step.</p>
<h3 id="installing-a-desktop">Installing a desktop</h3>
<p>A display manager is required in order to launch Kodi and other applications in
a graphical environment. I’ve selected <code class="highlighter-rouge">lightdm</code> since it’s intended to be a
light-weight alternative to GDM (from Gnome), KDM (from KDE) and the like.</p>
<p>Since we also intend launching multiple applications (switching between Kodi and
Steam at the least), we’ll also need a “desktop” environment (a Window Manager
in Linux-land). Again, the simplest lightest one will do the trick here, since
the intent is to not actually use it as a desktop per se.</p>
<p>For this, I’m using <code class="highlighter-rouge">openbox</code>.</p>
<p>After those are installed, you may want to reboot, to ensure you actually get a
graphical login prompt, and after login, see an extremely basic desktop (right-
click to open a simple menu to do simple things).</p>
<p>Now is a good time to install and configure the Nvidia drivers. Thankfully
this process is fairly simple these days. Begin by installing and running
<code class="highlighter-rouge">nvidia-detect</code>, which suggests which driver package you need to install for
for particular GPU (unfortunately, there are now legacy and “current” driver
packages).</p>
<p>Following installation of the recommended driver, also install and run
<code class="highlighter-rouge">nvidia-xconfig</code>, which will configure X to use the proprietary driver for you.</p>
<p>Another reboot should show you the Nvidia splash screen when the graphical
environment initialises.</p>
<p>At this point you can either switch to one of the terminal windows via
<code class="highlighter-rouge">Ctrl+Alt+F1/F2</code>/etc, or install <code class="highlighter-rouge">openssh-server</code> and perform the remaining
configuration remotely (the latter is much easier).</p>
<h3 id="nicer-looking-startup">Nicer looking startup</h3>
<p>You might also want to install <code class="highlighter-rouge">plymoth</code> at this point, which replaces all the
text information at startup with a graphical splash screen. See the
<a href="https://wiki.debian.org/plymouth">Plymouth page</a> of the Debian Wiki for
configuration instructions.</p>
<p>Additionally, while making changes to the boot process, the 5 second delay
before Grub begins launching Linux may be eliminated by changing <code class="highlighter-rouge">GRUB_TIMEOUT</code>
to <code class="highlighter-rouge">0</code> in <code class="highlighter-rouge">/etc/default/grub</code>, followed by running <code class="highlighter-rouge">update-grub2</code>.</p>
<p>Finally, a login prompt on a media PC is completely useless, so you should
configure LightDM to automatically log in a user. This is achieved by editing
<code class="highlighter-rouge">/etc/lightdm/lightdm.conf</code>. Inside the <code class="highlighter-rouge">[Seat:*]</code> section, uncommment and set
the value of <code class="highlighter-rouge">autologin-user</code>.</p>
<p>Another quick reboot will confirm your Grub, Plymouth and LightDM configuration.
Note that once you’re automatically logged in now, the desktop is black, rather
than having a default wallpaper.</p>
<h3 id="installing-kodi-configuring-sound-and-remotes">Installing Kodi, configuring sound and remotes</h3>
<p>The very latest version of Kodi is easily installable via the official <code class="highlighter-rouge">kodi</code>
package - no extra downlods or custom builds needed.</p>
<p>You will also need to install <code class="highlighter-rouge">alsa</code> and <code class="highlighter-rouge">alsa-utils</code>. After installing, run
<code class="highlighter-rouge">alsamixer</code> and use the arrow keys to select outputs and adjust volumes.
Pressing <code class="highlighter-rouge">m</code> will toggle mute on specific outputs. <code class="highlighter-rouge">esc</code> will exit.</p>
<p>You can now test Kodi by launching it from a console or remotely:</p>
<p><code class="highlighter-rouge">$ DISPLAY=:0 kodi</code></p>
<p>It should launch in full-screen, and play sounds if you move between menu items
with the keyboard or mouse. Double-check the audio configuration at this time as
well.</p>
<p>If you have a remote, you will need to install and configure <code class="highlighter-rouge">lirc</code>, which I can
only describe as the most “open source” package I’ve used in a very long time.
A lot of trial and error led me to the following configuration (thankfully, I
have the fairly common MCE (Media Centre Edition) remote):</p>
<ul>
<li>Copy <code class="highlighter-rouge">/usr/share/lirc/remotes/mceusb/lircd.conf.mceusb</code> to
<code class="highlighter-rouge">/etc/lirc/lircd.conf</code> (change the source remote file based on your own model).</li>
<li>Modify <code class="highlighter-rouge">etc/lirc/hardware.conf</code>:
<ul>
<li>set <code class="highlighter-rouge">DRIVER=default</code></li>
<li>set <code class="highlighter-rouge">DEVICE=/dev/lirc0</code></li>
</ul>
</li>
<li>Restart the <code class="highlighter-rouge">lirc</code> service.</li>
</ul>
<p>If you have Kodi running while doing this, you will have to restart it. I gather
that it only looks for a running/working <code class="highlighter-rouge">lirc</code> instance on startup.</p>
<p>Once I had the above settings working, Kodi responded to all button presses as
expected, with no further configuration on that end. You mileage may and
probably will vary.</p>
<h3 id="installing-and-configuring-steam-xbox-controller">Installing and configuring Steam, Xbox controller</h3>
<p>Follow the instructions to
<a href="https://wiki.debian.org/Steam">enable 32bit architecture and install Steam on the Debian wiki</a>.
I also needed to install the <code class="highlighter-rouge">libgl1-nvidia-glx:i386</code> package before Steam would
start.</p>
<p>You can test that it runs by executing from a console or remotely:</p>
<p><code class="highlighter-rouge">DISPLAY=:0 steam -bigpicture</code></p>
<p>After the initial Steam download, it should launch in full-screen Big Picture
mode.</p>
<p>Next up, we need PulseAudio for Steam. Unfortunately Kodi prefers <code class="highlighter-rouge">alsa</code> and
Steam prefers <code class="highlighter-rouge">pulseaudio</code>, so we need to do some juggling between the two.</p>
<p>Install the <code class="highlighter-rouge">pulseaudio</code> package, and then modify the following in
<code class="highlighter-rouge">etc/pulse/client.conf</code>:</p>
<ul>
<li>set <code class="highlighter-rouge">autospawn = no</code></li>
<li>set <code class="highlighter-rouge">daemon-binary = /bin/true</code></li>
</ul>
<p>This prevents Pulse from starting up at boot time, allowing us to start it up
and terminate it only when required for Steam.</p>
<p>Test it out by doing the following:</p>
<ul>
<li>Restart</li>
<li>run <code class="highlighter-rouge">pulseaudio --start</code></li>
<li>run Steam as per the command shown earlier</li>
<li>In Steam settings, reconfigure the audio (I find it helps to enable/turn up
ambient sounds during this process as you can hear it working)</li>
<li>Close Steam and run <code class="highlighter-rouge">pulseaudio -k</code></li>
<li>run Kodi, make sure audio settings are still correct and that sounds are
happening.</li>
</ul>
<p>The final step in the Steam setup process if required, is to install the XBox
controller driver. This can be done by simply installing <code class="highlighter-rouge">xboxdrv</code>. Your
controller should be able to control Kodi and Steam once installed.</p>
<h3 id="kodi-auto-start-final-touches">Kodi auto-start, final touches</h3>
<p>To finally tie it all together, Kodi should be set up auto-start. This is done
quite easily by creating <code class="highlighter-rouge">~/.config/openbox/autostart</code> for the auto-login user,
and adding the following: <code class="highlighter-rouge">kodi &amp;</code></p>
<p>Now, if you restart the PC it should whizz past Grub, show you a graphical boot
splash, automatically log in a user, and launch Kodi, ready to start doing
multimedia things.</p>
<p>For launching Steam, there may be Kodi Program add-ons available, or you may
use on of the more generic launcher add-ons.</p>
<p>For my purposes with the PulseAudio setup described here, I created my own
launcher add-on, which you may find useful with the above configuration.</p>
<ul>
<li><a href="/assets/files/steam.zip">Steam Launcher Add-on</a></li>
<li><a href="/assets/files/firefox.zip">Firefox Launcher Add-on</a></li>
<li><a href="/assets/files/minecraft.zip">Minecraft Launcher Add-on</a></li>
</ul>
<p>All the above may be installed by going into Settings -&gt; Add-ons and selecting
to install from a .zip file. Once installed they appear in the Programs menu.</p>
<p>The source for all of these is
<a href="https://github.com/shrimpza/kodi-addons">available on GitHub</a>, should you wish
to make your own modifications.</p>
Fri, 10 Jun 2016 00:00:00 +0200http://shrimpworks.za.net/2016/06/10/kodi-on-debian-sid/
http://shrimpworks.za.net/2016/06/10/kodi-on-debian-sid/DebianKodiHTPCSteamLinuxSoftwareGaming