27 Sep

a few improvements in the guitar thing

try it out – you need to log in to get a proper feel for it.

New items: a metronome, external tabs are shown in an iframe (makes it easier to use with the metronome and keeps the song within the context of the site), you can edit the songs you added and you can add a video of the song being played.

In the backend, I have a few architectural improvements (better class structure, etc), and the beginnings of the rating system which will eventually be able to figure out how difficult songs are in comparison with each other.

The metronome was very simple to create – I used the sound manager 2 library to manage the sound production, and a very small piece of javascript to do the timing. There are minor hiccups in the timing, but I think that’s due to the interaction between JavaScript and Flash (and JS is probably not supposed to be used for precision timing anyway).

stand-alone demo of the metronome, source files

Anyway – please try the guitar application – I know it’s a bit bare at the moment, but whenever I get the time, I add to it, and the more people use it, the more complete it will appear. feature requests and bug reports go here.

19 Sep

guitar project started

Couldn’t wait, so I wrote the beginnings of the project yesterday.

Click here to try it.

So far, you can create a user, login, name the chords you know (simple chords only – for now, this is for beginners), find songs with those chords, or songs with 1 2 or 3 extra chords you don’t yet know.

If you log in, you can add songs. I am hoping that people will find this useful, as I can’t begin to measure the relative difficulties of each song until I have a reasonable amount of data.

I’ve set up a project for it on my issue tracker – if you want to see ‘x’ feature, or you spot ‘y’ bug, please report them.

I hope you find this useful.

I’m debating with myself about whether to release the code for this – I want to share, but I also don’t want someone taking my code and building a huge money-printing site with it and leaving me in the cold (and Monaghan gets cold this time of year). Maybe I’ll release code for “old” versions – like if I’m on version 1.3, I’ll release 1.1 for other people to take.

18 Sep

guitar site project

Bronwyn is learning guitar. One headache we’ve already encountered is that there doesn’t appear to be a site which allows you to simply enter the chords you know, and have a list of matching songs returned.

So I’m thinking of writing one.

And, because I’m not really interested in chords myself, I’m going to make this into a sort of competitive site where songs and players can be ranked by difficulty/skill.

Bronwyn’s requirements will be easy to meet:

  • login
  • record the chords you know (or choose them from a list)
  • search a database of songs that match that list.
  • The songs will either show the tab/chords for the song in a page on the site, or will link to an external source if I can’t put them on the site for some reason (copyright, etc).
  • record the songs you know/are learning, so you can easily keep track of them.

For myself, and I suspect a lot of others, there’s a more complex list:

  • rank songs according to how many people know it vs are learning it (simple difficulty algorithm)
  • allow people to link to youtube/etc videos of themselves playing the song
  • allow people to optionally be ranked according to the songs they’ve mastered – this adds a bit of competition and therefore interest to the site
  • people with high ranks need to prove it. allow other high-ranked people to request a specific song that the person says they know – that person then has a week to upload a video of them playing it or they lose credibility.
  • credibility is ranked 0-100, and measures how much a person can be believed. it’s only shown in cases where a person is obviously lying.

Anything else i should try to place in the requirements list before I start writing?

05 Sep

moving email from qmail to postfixadmin

Yesterday we had to move about 300 domains from one machine to another. We bought a new machine recently and are taking this opportunity to move from Qmail (difficult to use, in my opinion) towards Postfix.

After doing one or two by hand, i decided that’s stupid – why not just automate the whole thing.

So I whipped up a script that reads details from vqadmin and uses those details to create postfix emails using mailadmin.

Please note that this does not handle forwards and other weirdness – just plain old email accounts. After running it, you need to check the accounts for forwards. I /could/ adapt it, but am too lazy.

<?php

$vqadmin_url='http://1.2.3.4/cgi-bin/vqadmin/vqadmin.cgi';
$vqadmin_auth='username:password';
$postfixmailadmin_url='http://5.6.7.8/mailadmin/';
$postfixmailadmin_username='your@email.address';
$postfixmailadmin_password='password';

ob_start();

// { get all domains
	$ch=curl_init($vqadmin_url);
	curl_setopt($ch, CURLOPT_USERPWD,$vqadmin_auth);
	curl_setopt($ch, CURLOPT_POST, true );
	curl_setopt($ch, CURLOPT_POSTFIELDS, 'nav=list_domains' );
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
	curl_exec($ch);
	$page=join('',explode("\n",curl_multi_getcontent($ch)));
	preg_match_all('#<a href=vqadmin.cgi\?nav=view_domain&dname=([^>]*)>[^<]*</a>#',$page,$domains);
	curl_close($ch);
// }

$numdomains=0; $numemails=0;
foreach($domains[1] as $domain){
	$numdomains++;
	echo '<h2>'.$numdomains.' - '.$domain.'</h2>';
	// { get password page
		$ch=curl_init($vqadmin_url);
		curl_setopt($ch, CURLOPT_USERPWD,$vqadmin_auth);
		curl_setopt($ch, CURLOPT_POST, true );
		curl_setopt($ch, CURLOPT_POSTFIELDS, 'dname='.$domain.'&Submit=Show Users&nav=show_users' );
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
		curl_exec($ch);
		$page=join('',explode("\n",curl_multi_getcontent($ch)));
		curl_close($ch);
	// }
	// { extract passwords
		preg_match_all('#<tr><td><FONT face=Verdana color="\#FFFFFF"><a href=[^>]*>[^<]*</a></FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">[^<]*</FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">[^<]*</FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">[^<]*</FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">[^<]*</FONT></td><td align=middle><FONT face=Verdana color=\#FFFFFF>(<B>)?[^<]*(</B>)?</FONT></td><td align=middle><FONT face=Verdana color=\#FFFFFF>[^<]*</font></td></tr>#',$page,$matches);
		$matches=$matches[0];
		$emails=array();
		foreach($matches as $match){
			$username=preg_replace('#<tr><td><FONT face=Verdana color="\#FFFFFF"><a href=[^>]*>([^<]*)<.*#','$1',$match);
			$password=preg_replace('#<tr><td><FONT face=Verdana color="\#FFFFFF"><a href=[^>]*>[^<]*</a></FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">([^<]*)<.*#','$1',$match);
			$emails[]=array('username'=>$username,'password'=>$password);
		}
	// }
	// { log into postfix mailadmin
		$ch=curl_init($postfixmailadmin_url.'login.php');
		curl_setopt($ch, CURLOPT_POST, true );
		curl_setopt($ch, CURLOPT_POSTFIELDS, 'fUsername='.$postfixmailadmin_username.'&fPassword='.urlencode($postfixmailadmin_password).'&lang=en&submit=Login');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
		curl_setopt($ch, CURLOPT_AUTOREFERER, true );
		curl_setopt($ch, CURLOPT_COOKIEJAR, 'tmp/cookies.txt');
		curl_exec($ch);
		curl_close($ch);
	// }
	// { create domain
		$ch=curl_init($postfixmailadmin_url.'create-domain.php');
		curl_setopt($ch, CURLOPT_COOKIEFILE, 'tmp/cookies.txt');
		curl_setopt($ch, CURLOPT_POST, true );
		curl_setopt($ch, CURLOPT_POSTFIELDS, 'fDomain='.$domain.'&fAliases=25&fMailboxes=25&submit=Add Domain');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
		curl_exec($ch);
		curl_close($ch);
	// }
	// { create email accounts
		foreach($emails as $email){
			$ch=curl_init($postfixmailadmin_url.'create-mailbox.php');
			curl_setopt($ch, CURLOPT_COOKIEFILE, 'tmp/cookies.txt');
			curl_setopt($ch, CURLOPT_POST, true );
			curl_setopt($ch, CURLOPT_POSTFIELDS, 'fDomain='.$domain.'&fUsername='.$email['username'].'&fPassword='.$email['password'].'&fPassword2='.$email['password'].'&fActive=on&fMail=on&submit=Add Mailbox');
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
			curl_exec($ch);
			$numemails++;
			echo $numemails.':'.$email['username'].'@'.$domain.' ';
			curl_close($ch);
		}
	// }
	flush();
	ob_flush();
}

Make sure to up the timeout length of your PHP scripts – it took me about 10 minutes to transfer 1607 emails.

Also, be aware that this does not transfer the /contents/ of the email accounts – just recreates them on the other server – I don’t even want to touch that particular problem…