<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Richard Jones, Esq. &#187; hacks</title>
	<atom:link href="http://www.metabrew.com/article/category/hacks/feed" rel="self" type="application/rss+xml" />
	<link>http://www.metabrew.com</link>
	<description>Erlang, PHP, C, C++, Java, PostgreSQL, MySQL, Hadoop, Linux, awk, bash, sed, grep, screen, vim, irc, ssh etc...</description>
	<lastBuildDate>Sun, 20 Dec 2009 18:59:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>ssh hack: connect directly to machine via a firewall box</title>
		<link>http://www.metabrew.com/article/ssh-hack-connect-directly-to-machine-via-a-firewall-box/</link>
		<comments>http://www.metabrew.com/article/ssh-hack-connect-directly-to-machine-via-a-firewall-box/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 17:44:44 +0000</pubDate>
		<dc:creator>RJ</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://www.metabrew.com/?p=196</guid>
		<description><![CDATA[UPDATED 23/03/2009: added &#8220;-q0&#8243; option to clean up netcat after session terminates, and left another useful ssh tip in the comments. It&#8217;s common to have to ssh to firewall / gateway machine, then ssh to the machine you want to work on within a server network. Typically you&#8217;d do this from your local machine: $ [...]]]></description>
			<content:encoded><![CDATA[<p><strong>UPDATED 23/03/2009:</strong> added &#8220;-q0&#8243; option to clean up netcat after session terminates, and left another useful ssh tip in the comments.</p>
<p>It&#8217;s common to have to ssh to firewall / gateway machine, then ssh to the machine you want to work on within a server network.<br />
Typically you&#8217;d do this from your local machine:<br />
<code>$ ssh firewall.example.com<br />
Password:<br />
$ ssh my-private-host</code></p>
<p>I finally got bored of doing this, and created the following file, <strong><code>/usr/bin/sssh</code></strong></p>
<pre>#!/bin/bash
ssh -oproxycommand="ssh -q firewall.example.com nc -q0 %h %p" $*</pre>
<p>Now I can use the <code>sssh</code> command to connect to hosts using the firewall machine as a proxy. Like most good hacks, this uses netcat.</p>
<p>Eg:<br />
<code>$ sssh 10.1.2.3</code><br />
Will connect me directly to a machine on the server network, via the firewall box. Seeing as it passes all parameters to ssh (the <code>$*</code> bit) you can do port forwards and X-forwarding as usual too:</p>
<pre>$ sssh -L 5432:localhost:5432 my-vm</pre>
<p>This lets me tunnel the port for a PostgreSQL running on my development vm (<code>my-vm</code>) in a single command. I have all my keys installed, so no passwords needed &#8211; I estimate this will save me about 60 seconds every day.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabrew.com/article/ssh-hack-connect-directly-to-machine-via-a-firewall-box//feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>On bulk loading data into Mnesia</title>
		<link>http://www.metabrew.com/article/on-bulk-loading-data-into-mnesia/</link>
		<comments>http://www.metabrew.com/article/on-bulk-loading-data-into-mnesia/#comments</comments>
		<pubDate>Mon, 13 Oct 2008 20:08:49 +0000</pubDate>
		<dc:creator>RJ</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[erlang]]></category>
		<category><![CDATA[mnesia]]></category>

		<guid isPermaLink="false">http://www.metabrew.com/?p=82</guid>
		<description><![CDATA[Consider this a work-in-progress; I will update this post if I find a &#8216;better&#8217; way to do fast bulk loading The time has come to replace my ets-based storage backend with something non-volatile. I considered a dets/ets hybrid, but I really need this to be replicated to at least a second node for HA / [...]]]></description>
			<content:encoded><![CDATA[<p><i>Consider this a work-in-progress; I will update this post if I find a &#8216;better&#8217; way to do fast bulk loading</i></p>
<p>The time has come to replace my ets-based storage backend with something non-volatile. I considered a dets/ets hybrid, but I really need this to be replicated to at least a second node for HA / failover. Mnesia beckoned. </p>
<p>The problem:</p>
<ul>
<li>15 million [fairly simple] records</li>
<li>1 Mnesia table: bag, disc_copies, just 1 node, 1 additional index</li>
<li>Hardware is a quad-core 2GHz CPU, 16GB Ram, 8x 74Gig 15k rpm scsi disks in RAID-6</li>
<li>Takes ages* to load and spews a load of &#8220;Mnesia is overloaded&#8221; warnings</li>
</ul>
<p><b>* My definition of &#8216;takes ages&#8217;:</b> Much longer than PostgreSQL <code>\copy</code> or MySQL <code>LOAD DATA INFILE</code></p>
<p>At this point all I want is a quick way to bulk-load some data into a disc_copies table on a single node, so I can get on with running some tests.</p>
<p>Here is the table creation code:<br />
<code>    mnesia:create_table(subscription,<br />
            [<br />
                {disc_copies, [node()]},<br />
                {attributes, record_info(fields, subscription)},<br />
                {index, [subscribee]}, %index subscribee too<br />
                {type, bag}<br />
            ]<br />
            )</code><br />
The <code>subscription</code> record is fairly simple:<br />
<code>{subscription, subscriber={resource, user, 123}, subscribee={resource, artist, 456}}</code></p>
<p>I&#8217;m starting erlang like so:<br />
<code>erl +A 128 -mnesia dir '"/home/erlang/mnesia_dir"' -boot start_sasl</code></p>
<p>The interesting thing there is really the <code>+A 128</code> &#8211; this spreads the cpu load better between the 4 cores.</p>
<h3>Attempt 0) &#8216;by the book&#8217; one transaction to rule them all</h3>
<p>Something like this:<br />
<code>mnesia:transaction(fun()-> [ mnesia:write(S) || S <- Subs ] end)</code></p>
<p>Time taken: <b>Too long, I gave up after 12 hours</b><br />
Number of &#8220;Mnesia overloaded&#8221; warnings: <b>lots</b><br />
Conclusion: <b>Must be a better way</b><br />
TODO: actually run this test and time it.</p>
<h3>Attempt 1) dirty_write</h3>
<p>There isn&#8217;t really any need to do this in a transaction, so I tried dirty_write.<br />
<code>[ mnesia:dirty_write(S) || S <- Subs ]</code></p>
<p>And here&#8217;s the warning in full:<br />
<code>=ERROR REPORT==== 13-Oct-2008::16:53:57 ===<br />
Mnesia('mynode@myhost'): ** WARNING ** Mnesia is overloaded: {dump_log,<br />
                                                                       write_threshold}</code></p>
<p>Time taken: <b>890 secs</b><br />
Number of &#8220;Mnesia overloaded&#8221; warnings: <b>lots</b><br />
Conclusion: <b>Workable, but nothing to boast about. Those warnings are annoying</b></p>
<h3>Attempt 2) dirty_write, defer index creation</h3>
<p>A common trick with traditional RDBMS would be to bulk load the data into the table and add the indexes afterwards. In some scenarios you can avoid costly incremental index update operations. If you are doing this in one gigantic transaction it shouldn&#8217;t matter, and I&#8217;m not really sure how mnesia works under the hood (something I plan to rectify if I end up using it for real).<br />
I tried a similar approach by commenting out the <code>{index, [subscribee]}</code> line above, doing the load, then using <code>mnesia:add_table_index(subscriber, subscribee)</code> afterwards to add the index once all the data was loaded. Note that mnesia was still building the primary index on the fly, but that can&#8217;t be helped.<br />
Time taken: <b>883 secs</b> (679s load + 204s index creation)<br />
Number of &#8220;Mnesia overloaded&#8221; warnings: <b>lots</b><br />
Conclusion: <b>Insignificant, meh</b></p>
<h3>Attempt 3) mnesia:ets() trickery</h3>
<p>This is slightly perverted, but I tried it because I was suspicious that incrementally updating the on-disk data wasn&#8217;t especially optimal. The idea is to make a ram_only table and use the mnesia:ets() function to write directly to the ets table (doesn&#8217;t get much faster than ets). The table can then be converted to disc_copies. There are caveats &#8211; to quote The Fine Manual:</p>
<blockquote><p>Call the Fun in a raw context which is not protected by a transaction. The Mnesia function call is performed in the Fun are performed directly on the local ets tables on the assumption that the local storage type is ram_copies and the tables are not replicated to other nodes. Subscriptions are not triggered and checkpoints are not updated, but it is extremely fast.</p></blockquote>
<p>I can live with that. I don&#8217;t mind if replication takes a while to setup when I put this into production &#8211; I&#8217;ll gladly take any optimisations I can get at this stage (testing/development).</p>
<p>Loading a list of <code>subscriptions</code> looks like this:<br />
<code>mnesia:ets(fun()-> [mnesia:dirty_write(S) || S <- Subs] end).</code><br />
And to convert this into disc_copies once data is loaded in:<br />
<code>mnesia:change_table_copy_type(subscription, node(), disc_copies).</code></p>
<p>Time taken: <b>745 secs</b> (699s load + 46s convert to disc_copies)<br />
Number of &#8220;Mnesia overloaded&#8221; warnings: <b>none!</b><br />
Conclusion: <b>Fastest yet, bit hacky</b></p>
<h2>Summary</h2>
<p>At least the ets() trick doesn&#8217;t spew a million warnings. I also need to examine the output of <code>mnesia:dump_to_textfile</code> and see if loading data from that format is any faster.</p>
<p>TODO:</p>
<ul>
<li>Examine / test using the dum_to_textfile method</li>
<li>Run full transactional load and time it</li>
<li>Try similar thing with PostgreSQL</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.metabrew.com/article/on-bulk-loading-data-into-mnesia//feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Updated bash PS1</title>
		<link>http://www.metabrew.com/article/updated-bash-ps1/</link>
		<comments>http://www.metabrew.com/article/updated-bash-ps1/#comments</comments>
		<pubDate>Sat, 11 Oct 2008 00:33:01 +0000</pubDate>
		<dc:creator>RJ</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[bash]]></category>

		<guid isPermaLink="false">http://www.metabrew.com/?p=72</guid>
		<description><![CDATA[Made a minor tweak to my .bashrc after browsing dotfiles.org for some ideas. One neat trick I gleaned was detecting when the exit code of the last command ($?) was non-zero and altering the prompt. This will be useful for quickly seeing at a glance if some enormous load of output from make was successful [...]]]></description>
			<content:encoded><![CDATA[<p>Made a minor tweak to my <code>.bashrc</code> after browsing <a href="http://www.dotfiles.org/">dotfiles.org</a> for some ideas. One neat trick I gleaned was detecting when the exit code of the last command (<code>$?</code>) was non-zero and altering the prompt. This will be useful for quickly seeing at a glance if some enormous load of output from make was successful or not.</p>
<div id="attachment_73" class="wp-caption alignnone" style="width: 408px"><a href="http://www.metabrew.com/wp-content/uploads/2008/10/ps1.png"><img class="size-full wp-image-73" title="Bash prompt" src="http://www.metabrew.com/wp-content/uploads/2008/10/ps1.png" alt="Note the prompt goes red on failure" width="398" height="285" /></a><p class="wp-caption-text">Note the prompt goes red on failure</p></div>
<p>Here are the bits from my updated <code>.bashrc</code>:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re3"># define useful aliases <span class="kw1">for</span> color codes</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_norm=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_black=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0;30m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_darkgray=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[1;30m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="re2">sh_blue=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0;34m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_light_blue=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[1;34m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_green=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0;32m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_light_green=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[1;32m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_cyan=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0;36m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="re2">sh_light_cyan=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[1;36m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_red=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0;31m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_light_red=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[1;31m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_purple=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0;35m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_light_purple=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[1;35m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="re2">sh_brown=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0;33m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_yellow=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[1;33m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_light_gray=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[0;37m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">sh_white=</span><span class="st0">&quot;<span class="es0">\[</span><span class="es0">\0</span>33[1;37m<span class="es0">\]</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">case</span> `<span class="kw2">hostname</span>` <span class="kw1">in</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="st0">&quot;livehost&quot;</span>|<span class="st0">&quot;production_server&quot;</span>|<span class="st0">&quot;sauron&quot;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re2">HOSTCOLOUR=</span><span class="re0">$<span class="br0">&#123;</span>sh_red<span class="br0">&#125;</span></span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; ;;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="st0">&quot;staging-node&quot;</span><span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp;<span class="re2">HOSTCOLOUR=</span><span class="re0">$<span class="br0">&#123;</span>sh_yellow<span class="br0">&#125;</span></span> ;;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; *<span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="re2">HOSTCOLOUR=</span><span class="re0">$<span class="br0">&#123;</span>sh_green<span class="br0">&#125;</span></span> ;;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">esac</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">export</span> <span class="re2">PROMPT_COMMAND=</span><span class="st0">&#8216;if [ $? -ne 0 ]; then ERROR_FLAG=1; else ERROR_FLAG=; fi; &#8216;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">export</span> <span class="re2">PS1=</span><span class="re0">$<span class="br0">&#123;</span>sh_white<span class="br0">&#125;</span></span><span class="st0">&#8216;<span class="es0">\u</span>@&#8217;</span><span class="re0">$<span class="br0">&#123;</span>HOSTCOLOUR<span class="br0">&#125;</span></span><span class="st0">&#8216;<span class="es0">\h</span>&#8216;</span><span class="re0">$<span class="br0">&#123;</span>sh_norm<span class="br0">&#125;</span></span><span class="st0">&#8216; <span class="es0">\w</span><span class="es0">\n</span>&#8216;</span><span class="re0">$<span class="br0">&#123;</span>sh_norm<span class="br0">&#125;</span></span><span class="st0">&#8216;${ERROR_FLAG:+&#8217;</span><span class="re0">$<span class="br0">&#123;</span>sh_light_red<span class="br0">&#125;</span></span><span class="st0">&#8216;}<span class="es0">\$</span>${ERROR_FLAG:+&#8217;</span><span class="re0">$<span class="br0">&#123;</span>sh_norm<span class="br0">&#125;</span></span><span class="st0">&#8216;} &#8216;</span></div>
</li>
</ol>
</div>
<p><br/><br />
I&#8217;m also using the hostname to decide what colour the host appears in the prompt. My home directory, and thus .bashrc, is mounted on most hosts I log in to, and this serves as a reminder if I&#8217;m logged in to a production host. Green is the default, and it&#8217;s overridden for various special hosts.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabrew.com/article/updated-bash-ps1//feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Transcoding HTTP mp3 streaming proxy in bash</title>
		<link>http://www.metabrew.com/article/transcoding-http-mp3-streaming-proxy-in-bash/</link>
		<comments>http://www.metabrew.com/article/transcoding-http-mp3-streaming-proxy-in-bash/#comments</comments>
		<pubDate>Mon, 29 Sep 2008 21:01:09 +0000</pubDate>
		<dc:creator>RJ</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[netcat]]></category>
		<category><![CDATA[streaming]]></category>

		<guid isPermaLink="false">http://www.metabrew.com/?p=58</guid>
		<description><![CDATA[Here&#8217;s how to make a proxy for streaming mp3s. It transcodes on-the-fly to 64kpbs MP3 using lame. When transcoding is finished, it calls the ./posthandler.sh script, which can either just delete the file, or potentially archive it so you don&#8217;t need to transcode it again. #!/bin/bash read method url version &#160; method=&#34;${method%$CR}&#34; url=&#34;${url%$CR}&#34; version=&#34;${version%$CR}&#34; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s how to make a proxy for streaming mp3s. It transcodes on-the-fly to 64kpbs MP3 using lame. When transcoding is finished, it calls the ./posthandler.sh script, which can either just delete the file, or potentially archive it so you don&#8217;t need to transcode it again.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re3">#!/bin/bash</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">read</span> method url version</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re2">method=</span><span class="st0">&quot;${method%$CR}&quot;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="re2">url=</span><span class="st0">&quot;${url%$CR}&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">version=</span><span class="st0">&quot;${version%$CR}&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">echo</span> -ne <span class="st0">&quot;HTTP/1.0 200 OK<span class="es0">\r</span><span class="es0">\n</span>Content-type: audio/mpeg<span class="es0">\r</span><span class="es0">\n</span><span class="es0">\r</span><span class="es0">\n</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="re2">BR=</span><span class="nu0">64</span> <span class="re3">#birate to transcode to.</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">PIPE=</span><span class="st0">&quot;/tmp/$$.pipe&quot;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">mkfifo</span> <span class="st0">&quot;$PIPE&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re2">OUTFILE=</span><span class="st0">&quot;./tmp.$$.$BR.mp3&quot;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="kw2">rm</span> <span class="re1">$OUTFILE</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re2">url=</span>`<span class="kw3">echo</span> <span class="st0">&quot;$url&quot;</span> | <span class="kw2">sed</span> <span class="st0">&#8216;s/<span class="es0">\/</span>//&#8217;</span>`</div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">echo</span> <span class="st0">&quot;** GET $url&quot;</span> &gt;&amp;<span class="nu0">2</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">nohup</span> <span class="kw2">lynx</span> &#8211;<span class="kw3">source</span> <span class="st0">&quot;$url&quot;</span> \</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; | <span class="br0">&#40;</span>lame &#8211;preset cbr <span class="re1">$BR</span> &#8211;mp3input &#8211; - <span class="nu0">2</span>&gt;/dev/null \</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &amp;&amp; <span class="br0">&#40;</span><span class="kw3">echo</span> <span class="st0">&quot;** Finished transcoding $url&quot;</span> &gt;&amp;<span class="nu0">2</span> ; \</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ./posthandler.<span class="kw2">sh</span> <span class="st0">&quot;$OUTFILE&quot;</span>&amp;<span class="br0">&#41;</span><span class="br0">&#41;</span>\</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; | <span class="kw2">tee</span> -i <span class="st0">&quot;$PIPE&quot;</span> &gt; <span class="re1">$OUTFILE</span> &amp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="kw2">cat</span> &lt; <span class="re1">$PIPE</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">rm</span> <span class="re1">$PIPE</span></div>
</li>
</ol>
</div>
<p><br/></p>
<p>One interesting limitation seems to be the buffer size of a fifo pipe in linux. Even though the transcoding step is pretty quick, if a client is connected the transcoding only manages to fill the pipe a couple of hundred k ahead of what is being read. </p>
<p>The -i flag to `tee` means it ignores interrupts, and will finish transcoding the file and call the posthandler even if the client disconnects.</p>
<p>Run is like this:</p>
<p><code>while [ 1 ]; do nc -vlp 8080 -c './transstreamer.sh' ; done</code></p>
<p>Then hit up a url of your choice using your awesome new proxy:</p>
<p><code>mpg321 "http://localhost:8080/http://freedownloads.last.fm/download/105468518/Letters%2BFrom%2BThe%2BBoatman.mp3"</code></p>
<p>Not the most scalable solution, but a mildly amusing quick hack.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabrew.com/article/transcoding-http-mp3-streaming-proxy-in-bash//feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
