Bembel-B Blog

2009/04/26

My FTPSync.pl Native Windows Build

I needed a Windows command line tool for syncing local files with an FTP server and couldn’t find any lightweight ones. There’s FTPSync.pl for Unix/Linux with a Cygwin build available (seems to be gone now). Instead of using that, I built an EXE of FTPSync.pl with ActivePerl for Windows.

Main reason for not using the Cygwin build is that using different versions of cygwin.dll simultaneously isn’t possible, which could happen easily when for example additionally having a full Cygwin install with running services. Stand alone Cygwin builds need to be shipped with the cygwin.dll which it is linked to.
Also that Cygwin build is outdated.

So, to make short things short, here you can download ftpsync-1.3.01.W32.zip (and my previous build ftpsync-1.2.33.W32.zip).

As far as I remember the build was straight forward. I installed ActivePerl 5.10, added a 3rd party PPM Repository (bribes.org I think) for installing the PAR Packer. Then all I had to do was issuing pp -o ftpsync.pl.exe ftpsync.pl in the directory with the FTPSync.pl sources.
You can reduce the EXE file size using UPX if you need to.
So far the EXE is working without problems.

ChangeLog

[2009-04-27: New build of latest version.]

2008/03/26

Neo Diggler Actions I Find Useful

Neo Diggler is a Firefox Add-on that lets you define and run actions based on your current URL, like jumping to parent folders. It’s the successor of Diggler compatible with newer browser versions. It’s a very useful Add-on, I’d say. I’ll provide some actions I hacked together over the time. I guess there’s be much room for improvement, but they are indeed working real nice for me.Firefox 2

Reload the current page from CoralCDN.

Name: CoralCDN
Matching Regular Expression: ^http://(.+)$
Show Action as Menu Entry: no
Action: http://$h.nyud.net$p

Opens the BugMeNot entries for the current domain in another window. Doesn’t work in Windows.

Name: BugMeNot
Matching Regular Expression: ^(.+)$
Show Action as Menu Entry: no
Action: javascript:window.open("http://www.bugmenot.com/view/$h", "$h"); javascript:window.reload();

Loads the current page with an www subdomain (http://some.example.com/foobar.php becomes http://www.example.com/foobar.php).

Name: www Subdomain
Matching Regular Expression: ^(.+//)([\d\w]+\.|)(.+)$
Show Action as Menu Entry: yes
Action: $1www.$3

Loads the current page’s base address with a www subdomain (http://some.example.com/dig/around/here.html becomes http://www.example.com/).

Name: www Subdomain Index
Regular Expression: ^(.+//)([\d\w]+\.|)([\d\w\.]+\.[\w]+/)(.*)$
Show Action as Menu Entry: yes
Action: $1www.$3

Loads a current http page as https (ssl).

Name: https
Regular Expression: ^http([^s].+)$
Show Action as Menu Entry: yes
Action: https$1

Click the left thumbnail to see how these actions appear in Neo Digglers context menu next to the Firefox address bar.

A great help when building Regular Expressions is KDE’s kregexpeditor, part of kdeutils. You can visually compose and analyse your regexes and match them against desired text.
And well, while this regex might seem like black magic at first (and second ;) sight, and it can be kind of mind boggling oftentimes, it’s really worth learning it! The syntax is being used in so many places (tools, programming languages) and will come very handy for parsing and substituting texts.

ChangeLog

[2008-03-30: Fix https action. BugMeNot not working in Windows.]

2008/03/11

Scrobbling Everywhere All the Time

I must confess I’ve become quite a Last.fm fanboy. :) So what would be more important than keeping track of as much music playing as possible. Scrobbling the plays of my PC audioplayer Amarok and Foobar2000 ain’t that spectacular, but feeding statistics of my mobile MP3 Player SanDisk Sansa e200 and my stand-alone player Pinnacle SoundBridge HomeMusic (licensed by Roku) I consider being more of that kind.Last.fm Social Music Revolution

Scrobbling Sansa e200 with Rockbox

Precondition is using the great alternative Firmware Rockbox. It already has the Audioscrobbler logging built in. To submit the logs I use the PC application QTScrobbler under Linux (and occasionally Windows). That’s very easy and convenient. Just be sure to set your Sansa’s clock somewhat correct.

Scrobbling SoundBridge with Firefly Mediaserver

To gain access to my whole music collection without having a PC running, I’m using the fine Linksys NSLU2 NAS running the Firefly Mediaserver (aka. mt-daapd) with a cheapo 160 GB USB HDD (Storage) and a 2 GB USB Flash Drive (OS) attached. I’ve had a working setup using the alternative NSLU2 firmware Unslung, but soon switched to Debian ARM, for its greater versatility and more straight forward configuration.

I’ll write more detailed posts on the NSLU2 soon, especially regarding Firefly and fixed-point Transcoding and Last.fm Radio. But for now a quick overview on the setup, which should be possible on other platforms and for any streaming client too.

I obtained the Firefly Mediaserver prebuilt from the Firefly website. Installation is quite easy and well documented.

Submission to Last.fm is done by the Python application Lastfmsubmitd. As the name suggests it’s a daemon permanently waiting for data to be submitted. That data is gathered from text files placed e.g. in /var/spool/lastfm. Under Unslung I had to manually install it from source (python setup.py install), and for Debian it’s in the apt repo (but I built a deb package of the recent version found in Debian unstable).

Creating the data files is done periodically by a shell script based on what I found in the Firefly Forum. It’s run every 5 minutes by cron and queries the “last played field” of Firefly’s collection database and outputs results to Lastfmsubmitd’s spool directory.
That’s my current shell script (converting GMT+1 timestamps to UTC by substracting 3600 seconds):

#!/bin/bash

# fetch newly played songs from fireflydb and write
# into lastfmsubmitd readable format

# config
SQLITE=sqlite3
DATABASE=/var/cache/mt-daapd/songs3.db
LASTFILE=/var/cache/mt-daapd/lastfmsubmit.date
DBLSFILE=/var/cache/mt-daapd/lastfmsubmit.ls
TMPDIR=/tmp
SPOOLDIR=/var/spool/lastfm


# get last run time
if [ -e "$LASTFILE" ]
then
  . "$LASTFILE"
else
  LASTRUN=0
fi

# get last database file date
if [ -e "$DBLSFILE" ]
then       
  . "$DBLSFILE"
else     
  DBLSRUN=
fi

# exit when database file unchanged
DBLSNOW=`ls -l "$DATABASE"`
if [ "$DBLSRUN" == "$DBLSNOW" ]
then
  exit
fi

# log file date
echo "DBLSRUN=\"$DBLSNOW\"" > "$DBLSFILE"

# query database
OUTFILE=$(mktemp "$TMPDIR"/mt-daapd-XXXXXXXX)
"$SQLITE" "$DATABASE" 'SELECT artist,album,title,track,song_length,time_played FROM songs where time_played > '"$LASTRUN"' ORDER BY time_played ASC;' | gawk -F '|' '{ printf "---\nartist: \"%s\"\nalbum: \"%s\"\ntitle: \"%s\"\ntrack: %s\nlength: %d\ntime: !timestamp %s\n",$1,$2,$3,$4,$5/1000,strftime("%Y-%m-%d %T",$6-3600) }' > "$OUTFILE"

# place non-zero result into spool, else drop file
if [ -s "$OUTFILE" ]
then
  chmod 664 "$OUTFILE"
  mv "$OUTFILE" "$SPOOLDIR"
else
  rm "$OUTFILE"
fi

# log query date
echo "LASTRUN="`date +%s` > "$LASTFILE"

Downside of this solution is, Firefly will only consider a track as played, if it has been completely and continuously been played. So skipping or pausing a track will cause it to not be submitted.
Also there’s no separation between Podcasts and the rest of my music collection. What I haven’t tried yet, is the behaviour when playing web radio via Firefly playlists, as I do all radio streaming directly through the SoundBridge user interface.
To iron out the downsides using the same approach, the first one would need changes to the Firefly code I guess, the others could probably be fixed modifying the shell script.

2008/01/21

Firefox Add-ons galore!

Time for some boring list of my currently used Firefox Add-ons. :) This one is for my Linux Firefox, but it’s about the same collection in Windows (except for Auto Copy). And sorry for these half-hearted descriptions of the Add-ons. :)

Firefox 2

UserAgent-String: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11

Adblock Filterset.G Updater 0.3.1.3 – Updater for Adblock Plus filterlists
Adblock Plus 0.7.5.3 – Block advertisements etc. from being shown
All-in-One Gestures 0.18.0 – Mouse gestures and shortcuts
Bookmark Duplicate Detector 0.6.3 – Warning, when trying to add the same bookmark twice
Bookmarks LinkChecker 0.6.8.4 – Check bookmarks for dead links
Bookmarks Synchronizer SE SiteBar Edition 1.1.8.0.4 – Sync your bookmarks as XBEL files e.g. for SiteBar
Boox 1.1.0.0 – Extended tooltips in bookmarks sidebar
Clippings 2.6 – Manage text snippets
CoLT 2.3.0 – Copy link text with URL
CookieCuller 1.3.1 – Advanced Cookie management
Copy Links 0.1.4 – Copy all selected links
CustomizeGoogle 0.69 – Many options for customizing Google. Remove advertisement, gain privacy, add links to other searchengines..
Dict 0.6.71 – Dictionary search
Enhanced Bookmark Search 0.1.4.04.1 – Search bookmarks with various criteria
FEBE 5.1.1 – Backup tool
Firebug 1.05 – HTML/CSS/JavaScript inspector, (step-) debugger and profiler
Firefox Companion für eBay 1.1.1 – eBay Sidebar
FlashGot 0.7.5 – Downlad manager integration and tools
Foxmarks Bookmark Synchronizer 2.0.41 – Sync your bookmarks at foxmarks.com
Greasemonkey 0.7.20070607.0 – Custom JavaScript to change loaded websites on-the-fly
keyconfig 20060828.1 – Configure key shortcuts
Locate in Bookmark Folders 0.2.5 – Jump from a bookmark search result to its place in the full bookmark list (useful to access its context menu)
MediaPlayerConnectivity 0.8.3 – Open various embedded media files in your preferred standalone media player
MIME Edit 0.60 – Configure MIME type handling
MR Tech Local Install 5.3.2.6 – Better management for Add-ons and Themes
Neo Diggler 1.0.3 – Jump to a parent of your currently loaded URL and other shortcuts
OpenBook 1.3.4.1 – Extended options when adding bookmarks
Paste and Go 2 0.8 – Load URL or use search engine with your clipboard content
QuoteURLText 1.0.6 – Quotation from a website with URL and Title etc. copied into clipboard
SmartSearch 3.7 – Integrate keyword search bookmarks for searching a highlighted text from the context menu
Tab Mix Plus 0.3.6 – Great extension to tabs and link opening behaviour
Update Bookmark 0.0.4.1 – Overwrite a bookmark with the currently loaded website
User Agent Switcher 0.6.10 – Change the useragent string
wmlbrowser 0.7.17 – Support for WML documents
XHTML Mobile Profile 0.5.2 – Support for Mobile Profile XHTML documents

2007/12/06

Downloading Artist Images from Discogs with Python

In my previous post I told about foobar2000 and album art, but there are also artist images to be shown with the FofR Theme. For reasons explained later and just for fun and learning Python, I started to write a Python script for downloading artist images from Discogs through their Web API.

Discogs Logo
There’s already some application for downloading artist images, but the server it depends on is currently offline. Then there’s the Discogs component for foobar2000, which can be used for tagging and downloading album art and artist images. But at least for the artist images these will be named with the Discogs artist id, and not the artist names. That’s not useful for me, except I’d retag all my audiofiles to contain this ID. A thing I don’t dare to do.

So this is my first approach on writing a Python application. I’m very impressed how easy and fast it went, combining some tutorials’ code (sorry, can’t remember them all for credit and copyright :/) and some peeks at the code reference.
The only complications were charset issues: Firstly because I didn’t know about the inner workings of Python with special chars (it’s Unicode :). Secondly because I was using Cygwin’s Python which don’t seem to handle (output/input) any special chars at all, as its native charset is set to us-ascii (only 7 Bit chars).
Well, and one other confusion came from using tabs to indent the sourcecode, resulting in “weird” interpreter errors.
So now I switched to Windows Python (charset cp850) and all is fine. This script should also run nicely under Linux and alike.

This script is very, very ugly and totally not failsafe. It’s just a starting point and as I told above, I’m a total beginner in Python. Just for your amusement, here’s the code so far. Expect updates sometime. :)

#!/usr/bin/python
# -*- coding: iso-8859-15 -*-

import urllib2, gzip, cStringIO
import urllib
import re
import xml.sax.handler
import getopt, sys

apikey = "111"

#artistname = u"DJ Ötzi"
           
stdout_encoding = sys.stdout.encoding or sys.getfilesystemencoding()
fs_encoding = sys.getfilesystemencoding()
print stdout_encoding

def xml2obj(src):
    """
    A simple function to converts XML data into native Python object.
    """

    non_id_char = re.compile('[^_0-9a-zA-Z]')
    def _name_mangle(name):
        return non_id_char.sub('_', name)

    class DataNode(object):
        def __init__(self):
            self._attrs = {}    # XML attributes and child elements
            self.data = None    # child text data
        def __len__(self):
            # treat single element as a list of 1
            return 1
        def __getitem__(self, key):
            if isinstance(key, basestring):
                return self._attrs.get(key,None)
            else:
                return [self][key]
        def __contains__(self, name):
            return self._attrs.has_key(name)
        def __nonzero__(self):
            return bool(self._attrs or self.data)
        def __getattr__(self, name):
            if name.startswith('__'):
                # need to do this for Python special methods???
                raise AttributeError(name)
            return self._attrs.get(name,None)
        def _add_xml_attr(self, name, value):
            if name in self._attrs:
                # multiple attribute of the same name are represented by a list
                children = self._attrs[name]
                if not isinstance(children, list):
                    children = [children]
                    self._attrs[name] = children
                children.append(value)
            else:
                self._attrs[name] = value
        def __str__(self):
            return self.data or ''
        def __repr__(self):
            items = sorted(self._attrs.items())
            if self.data:
                items.append(('data', self.data))
            return u'{%s}' % ', '.join([u'%s:%s' % (k,repr(v)) for k,v in items])

    class TreeBuilder(xml.sax.handler.ContentHandler):
        def __init__(self):
            self.stack = []
            self.root = DataNode()
            self.current = self.root
            self.text_parts = []
        def startElement(self, name, attrs):
            self.stack.append((self.current, self.text_parts))
            self.current = DataNode()
            self.text_parts = []
            # xml attributes --> python attributes
            for k, v in attrs.items():
                self.current._add_xml_attr(_name_mangle(k), v)
        def endElement(self, name):
            text = ''.join(self.text_parts).strip()
            if text:
                self.current.data = text
            if self.current._attrs:
                obj = self.current
            else:
                # a text only node is simply represented by the string
                obj = text or ''
            self.current, self.text_parts = self.stack.pop()
            self.current._add_xml_attr(_name_mangle(name), obj)
        def characters(self, content):
            self.text_parts.append(content)

    builder = TreeBuilder()
    if isinstance(src,basestring):
        xml.sax.parseString(src, builder)
    else:
        xml.sax.parse(src, builder)
    return builder.root._attrs.values()[0]

def downloadartistimage(uri, filename):
    fp = urllib2.urlopen(uri)
    op = open(filename, "wb")
    n = 0
    while 1:
        s = fp.read(8192)
        if not s:
            break
        op.write(s)
        n = n + len(s)
    fp.close()
    op.close()
    for k, v in fp.headers.items():
        print k, "=", v
    print "copied", n, "bytes from", fp.url
    return 0

try:
    opts, args = getopt.getopt(sys.argv[1:], "ha:v", ["help", "artist="])
except getopt.GetoptError:
    # print help information and exit:
    print("no argument given")
    sys.exit(2)
verbose = False
for o, a in opts:
    if o == "-v":
        verbose = True
    if o in ("-h", "--help"):
        print("no argument given")
        sys.exit()
    if o in ("-a", "--artist"):
        artistname = a.decode(fs_encoding)

requesturi = "http://www.discogs.com/artist/%s?f=xml&api_key=%s" % (urllib.quote_plus(artistname.encode('utf-8')), apikey)
print "Requesting: %s" % requesturi
request = urllib2.Request(requesturi)
request.add_header('Accept-Encoding', 'gzip')
response = urllib2.urlopen(request)
data = response.read()
unzipped_data = gzip.GzipFile(fileobj = cStringIO.StringIO(data)).read()
# print(unzipped_data)

data_obj = xml2obj(unzipped_data)
images = data_obj.artist.images

primaryfound = False
bigsecondarysize = 0
for image in images.image:
    print "Type: %s URL: %s" % (image.type, image.uri)
    if image.type == "primary":
        primaryfound = True
        fn = u"%s.%s" % (artistname, image.uri.rpartition('.')[2])
        print u"Downloading primary image as %s from %s".encode(stdout_encoding) % (fn, image.uri)
        downloadartistimage(image.uri, fn)
        continue
    if image.type == "secondary":
        if (image.width + image.height) > bigsecondarysize:
            bigsecondarysize = image.width + image.height
            bigsecondary = image
        continue

if not primaryfound:
    fn = u"%s.%s" % (artistname, bigsecondary.uri.rpartition('.')[2])
    print u"Falling back to secondary as %s sized %sx%s at %s".encode(stdout_encoding) % (fn, bigsecondary.width, bigsecondary.height, bigsecondary.uri)
    downloadartistimage(bigsecondary.uri, fn)

print "All done! :)"

And now two usage examples:

C:\Dokumente und Einstellungen\scheff\Eigene Dateien\python\pydiscogs>example-04.py -a "Aphex Twin"
cp850
Requesting: http://www.discogs.com/artist/Aphex+Twin?f=xml&api_key=111
Type: secondary URL: http://www.discogs.com/image/A-45-005.jpg
Type: secondary URL: http://www.discogs.com/image/A-45-1094774583.jpg
Type: secondary URL: http://www.discogs.com/image/A-45-1097005597.jpg
Type: secondary URL: http://www.discogs.com/image/A-45-1098171105.jpg
Type: secondary URL: http://www.discogs.com/image/A-45-1107949060.jpg
Type: secondary URL: http://www.discogs.com/image/A-45-1122852930.jpg
Type: secondary URL: http://www.discogs.com/image/A-45-1126949071.jpeg
Type: secondary URL: http://www.discogs.com/image/A-45-1126949078.jpeg
Type: secondary URL: http://www.discogs.com/image/A-45-1126949085.jpeg
Type: secondary URL: http://www.discogs.com/image/A-45-1126949091.jpeg
Type: secondary URL: http://www.discogs.com/image/A-45-1129512422.jpeg
Type: primary URL: http://www.discogs.com/image/A-45-1176664580.jpeg
Downloading primary image as Aphex Twin.jpeg from http://www.discogs.com/image/A-45-1176664580.jpeg
content-length = 141117
set-cookie = sid=5c3847142265e10e296934b877585749; path=/; expires=Sun, 03-Dec-2017 00:07:28 GMT; domain=.discogs.com
server = Apache
connection = close
reproxy-status = yes
date = Thu, 06 Dec 2007 00:07:28 GMT
content-type = image/jpeg
copied 141117 bytes from http://www.discogs.com/image/A-45-1176664580.jpeg
All done! :)

C:\Dokumente und Einstellungen\scheff\Eigene Dateien\python\pydiscogs>example-04.py -a "Black Sabbath"
cp850
Requesting: http://www.discogs.com/artist/Black+Sabbath?f=xml&api_key=111
Type: secondary URL: http://www.discogs.com/image/A-144998-1098725461.jpg
Type: secondary URL: http://www.discogs.com/image/A-144998-1147641856.jpeg
Falling back to secondary as Black Sabbath.jpeg sized 528x531 at http://www.discogs.com/image/A-144998-1147641856.jpeg
content-length = 45353
set-cookie = sid=e47b9acbe8257ca4ad7fe6944a36fef1; path=/; expires=Sun, 03-Dec-2017 00:07:08 GMT; domain=.discogs.com
server = Apache
connection = close
reproxy-status = yes
date = Thu, 06 Dec 2007 00:07:08 GMT
content-type = image/jpeg
copied 45353 bytes from http://www.discogs.com/image/A-144998-1147641856.jpeg
All done! :)

C:\Dokumente und Einstellungen\scheff\Eigene Dateien\python\pydiscogs>

Alternative Album Art with foobar2000 and PanelsUI

Filed under: Album Art,Cover Art,FofR,foobar2000,PanelsUI,software,Windows — FrankZabbath @ 01:52

Recently I took a second look at the foobar2000 Audioplayer for Windows and explored the gigantic possibilities of visual customization. After playing around a bit I was stuck with PanelsUI User Interface and especially the FofR Theme. It took me over an hour to figure out how to be able to use a list of alternative album art filename patterns, instead of the default folder.jpg.
Foobar2000 Logo
General information can be found at the FofR Configuration Guide.

The result isn’t quite optimal yet, as for the selection and priorities of the actual filename filters. But that’s a thing to be fine tuned. My solution works by checking if the filenames defined by the filters (from first line to the last) are existing. It stops if one file is found.

Here’s the complete code for User Globals (only coverPath lines are relevant for this regard of course):

$puts(coverPath,$replace(%path%,%filename_ext%,folder.*))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,cover.*)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*front.jpg)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*front*.jpg)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*cover.jpg)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*cover*.jpg)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,00*.jpg)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*%album%.jpg)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*%album%*.jpg)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*.jpg)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*.png)))
$if($not($fileexists($get(coverPath))),$puts(coverPath,$replace(%path%,%filename_ext%,*.bmp)))
$puts(artistPath,C:\Programme\foobar2000\artist_images\%artist%.*)
$puts(userFont,Tahoma)
$puts(userFontSize,9)

This also defines the artist images to be found in C:\Programme\foobar2000\artist_images\%artist%.*, instead of the default %path%\artist.*.

2007/06/19

Watching Stage6 Video Streams Without DivX Web Player Plugin With Firefox

Trying to watch a DivX video stream like hosted by Stage6 you’re prompted to install the DivX Web Player Browser Plugin. It’s only available for Windows and Mac and certainly is a bit of a bloat just for viewing videos whose codec you already have installed. Luckily there’s a Firefox Add-On called MediaPlayerConnectivity available which saves you from the need installing that Web Player Plugin.
Firefox 2
You can get the MediaPlayerConnectivity Add-On at Mozilla. It will modify webpages adding a playback icon that will open the stream URL in the configured standalone media player like VLC or Xine. Works quite nicely. I only chose DivX streams to be handled by the Add-On so that’ll catch the DivX Web Player streams. Have fun!

2007/04/29

Preparing MP3s and Cover Art for SanDisk Sansa e200 Portable Audio Player

Last year I purchased a flash based 2 GB DAP SanDisk Sansa e250 to join my good ole 20 GB HDD player Creative Nomad Jukebox Zen Firewire. Sadly the Sansa is quite picky when it comes to ID3 tags.

SanDisk Sansa e200

By experimenting and reading up I found out how to retag my MP3s using Linux (and probably also Windows using Cygwin) so that they all will be fully recognized. I also found a procedure to nicely resize cover scans which can be displayed when playing a corresponding track.

Prerequisites

For ID3 tagging I’m using the command line application eyeD3, as it handles ID3v2.4 and – yes – it’s commandline driven. I made an RPM for Fedora Core 5. The original spec file didn’t work because of using the wrong python version. I’ve put my edited spec file and the RPM into my box.net share.

To handle the cover scans I use ImageMagick.

Preparation

For better performance one should copy the files to be uploaded to your player somewhere on your harddrive.

Copy your MP3s to some working directory and finally cd into it

mkdir -p ~/wrk/mp3new
cd /windows/g/mp3
cp -r _electronic/Aphex\ Twin/Aphex_Twin-...I_Care_Because_You_Do-1995/ /windows/g/mp3
cp -r _metal/Colonel\ Claypool\'s\ Bucket\ of\ Bernie\ Brains\ -\ Big\ Eyeball\ in\ the\ Sky/ /windows/g/mp3
cp -r _metal/Primus/primus-pork_soda-1993/ /windows/g/mp3
cd ~/wrk/mp3new

Retagging

The Sansa preferres ID3v2 tags over ID3v1 and can read up to ID3v2.3 tags. But it doesn’t seem to like some of the special fields possible with ID3v2.3 and therefore these will have to be removed. The following steps may seem a bit complicated, but it’s the only way to do the cleanup with eyeD3 currently.

1.) Convert to v1.x

find -type f -and  \( -name "*.mp3" -or -name "*.MP3" \) -print0 | xargs -0 eyeD3 --to-v1

2.) Remove v2

find -type f -and  \( -name "*.mp3" -or -name "*.MP3" \) -print0 | xargs -0 eyeD3 --remove-v2

3.) Convert to v2.3

find -type f -and  \( -name "*.mp3" -or -name "*.MP3" \) -print0 | xargs -0 eyeD3 --to-v2.3

4.) Remove v1

find -type f -and  \( -name "*.mp3" -or -name "*.MP3" \) -print0 | xargs -0 eyeD3 --remove-v1

To make things easier, I’ll try to condense all this to one single command next time. So stay tuned..

Cover Art

My procedure will only keep the front cover scans, where available. If you’d like to keep other images too, you’d have to follow the alternative procedure 1b/2b instead of 1a/2a.
Please note: even png images will be renamed to folder.jpg ImageMagick will correctly recognize them as pngs when converting.

If you’d prefer not to use folder.jpg for the resized cover images you may instead use Album Art.jpg as filename.

1a.) List all jpegs and png files. Then manually delete all unneeded files!

find -type f -and \( -name "*.jpg" -or -name "*.JPG" -or -name "*.png" \)

2a.) Rename cover images to folder.jpg

OLDIFS=$IFS ; IFS=$'\n' ; \
for fn in `find -type f -and \( -name "*.jpg" -or -name "*.JPG" -or -name "*.png" \) -not -name "folder.jpg"` ; \
do mv -v "$fn" "${fn/`basename "$fn"`/folder.jpg}" ; \
done ; IFS=$OLDIFS

1b/2b.) Alternative: To keep other images as well, you’d have to manually rename (or copy to keep the original) the front cover images to folder.jpg

3.) Proportionally resize cover images to max 200 x 200 px

OLDIFS=$IFS ; IFS=$'\n' ; \
for fn in `find -type f -name folder.jpg` ; \
do mogrify -verbose -resize '200x200>' "$fn" ; \
done ; IFS=$OLDIFS

I must admit this isn’t the most elegant way. Maybe I’ll manage to make some little GUI and trying to automatically chose the front cover image files. We’ll see..

Uploading to the Player

Nothing special here. Just plug in your Sansa in MSC mode. Then move the files to the player.

mv -v * /media/Sansa\ e250/MUSIC

If you’re replacing files on your player, you’ll have to purge the tag database in order to let the player recognize the changes.

rm /media/Sansa\ e250/SYSTEM/DATA/PP5000.DAT

ChangeLog

[070923 Fix backslashes (“\\” markup was meanwhile rendered as “\\” and not “\” as before.]
[080120 Add “Sansa e200” category and link to it.]

2006/04/22

The SATAnic Power of State-of-the-Art OSes and Installing Them

I recently did a clean install of Windows XP and Fedora Core 5 on my SATA HDD and it was quite an odyssey to get it working. I’ll briefly describe the odds I was confronted with. The real problem was to get Windows NTLDR/boot.ini bootstrap and the GRUB bootloader installed and configured correctly. One source of trouble seems to be that I had my old (even though unpartitioned) IDE HDD still plugged in and it could not be disabled in the BIOS. I am using an Asus A7N8X-E Deluxe mainboard.

Installing Windows XP

Of course one needed to have the Sil SATA driver on a floppy disk and press F6 when the Windows XP Install CD got booted. I knew this already. But downloading that 20+ MB driver package from the Asus website took over 30 minutes with about 13KB/s.. Very frustrating!
The strange thing with the Windows install was that it wouldn’t let me install on the SATA HDD without having enough free space on the IDE HDD. I had to create some partition on the IDE HDD and then the first step of installation continued.
Funny enough, the Windows bootloader got installed on that IDE HDD. So I had my Windows installed on drive C: (SATA) and the bootloader on drive D: (IDE) with a boot.ini configured to load Windoze from the second (SATA) HDD.
To fix that, I had to change the boot.ini to use the first HDD. I edited the file using a Linux Live-CD and copied it to a floppy disk (as there is no text editor included in the Windows Recovery Console AFAIK). Then I booted the Windows Recovery Console and copied all files from the IDE drive and the fixed boot.ini from the floppy disk to the SATA drive. This of course only was sufficient, as I wanted to use GRUB as my bootloader. Quite interesstingly, the drive letters using the Recovery Console where different, i.e. C: was IDE and D: was SATA.. Stupid drive letters anachronism I say!

Installing Fedora Core 5

The installation process was quite straight forward. Only thing that was annoying: There was only the option to install GRUB into the boot sector of the IDE drive or into the beginning of the first Linux partition (SATA). So I had to reinstall GRUB giving the desired destination after the OS was installed.
But this wasn’t enough. The problem is that I booted from CD and therefore the CD-ROM drive was seen as first boot drive and the HDD was considered the second drive. So I had to edit /boot/grub/system.map and define the HDD to be the first boot drive and do a reinstall of GRUB (grub-install /dev/sda).

Conclusion

Some part of problems I think were caused because I had that IDE HDD still installed. On the other hand the installer programs should be smart enough to automagically get around these problems. Sadly I didn’t find the solution as directly as it may sound. Searching the web I didn’t find anything describing my case, so this is why I wrote this..
My description of problems and how I solved them is surely very compressed for such a complex and confusing topic. So feel free to ask for clarification etc. by commenting.

ChangeLog

[2006-04-23: Add tags.]

2006/01/23

My favoured Firefox Extensions arsenal

Filed under: Firefox,Firefox Extensions,Linux,Mozilla,software,Windows — FrankZabbath @ 22:27

Mozilla applications allow to extend their functionality by installing so called Extensions. Here you’ll find a quick write-up on my choice for Firefox 1.0.6 on Linux. Most Extensions are also running under Windows and should be available for Firefox 1.5 meanwhile.
I used German localized versions when available. These are often not (yet) included in the original Extension versions and were found at erweiterungen.de. Theses non-official German locales are marked with [de] in the list below.

Upgrade to Firefox 1.5!

Bookmarks

Bookmark Duplicate Detector [de] 0.0.1
When trying to add an already existent URL to your bookmarks, a dialog box will pop up asking you whether you really want to create a duplicate bookmark.

Bookmarks Synchronizer 1.0.1
Lets you upload and synchronize your whole bookmarks or just a certain bookmarks folder via FTP or WebDAV using the XBEL XML format. A great tool! You can also use it, to sync your bookmarks with SiteBar servers (after installing an XBEL addon on the SiteBar server).

Enhanced Bookmark Search [de] 0.1.4.03
Extends the very basic bookmark search function to searching for URL, description, keywords even with logical operators like “begins with”, “contains not” etc.

Flat Bookmark Editing [de] 0.7
Now you can edit bookmark’s properties in the bookmark manager directly in a bottom window pane, so you won’t have to open a popup window for each bookmark.

Locate in Bookmark Folders [de] 0.2.4
Circumvents the annoying fact, that in a bookmark search result listing you can’t edit nor view bookmark properties nor see its hierarchical folder location. Now you can rightclick on a bookmark search result to open the full bookmarks view with the chosen bookmark focused.

OpenBook [de] 1.3.4
When creating a new bookmark you can edit its URL and also specify description and keywords and choose its folder location.

Search Engines

Advanced Search Sidebar 0.1.7.4
A Search Sidebar as found in the Mozilla Browser. You can define and group search engines. The search result listing will be displayed in the Sidebar.

Search Engine Ordering [de] 0.5.2
Lets you order and delete the search engines directly in the search bar dropdown menu.

SmartSearch [de] 2.8
Firefox keyword searches, normally only available through the address bar, can be triggered for highlighted text in a website via the context menu. Very useful!

Navigation and Usability

All-in-One Gestures [de] 0.17.4
Customizable mouse gestures support for many of Firefoxes functions plus new functions like removing any object from a website. You can also directly access the history for the current tab.

Enhanced History Manager 0.5.8.04
Similar to the Enhanced Bookmark Search this Extension adds a second History Manager with advanced search functionality, detailed listing, editing.

FlashGot 0.5.9.99
Provides integration for dozens of download managers. You can highlight multiple links and let them get downloaded in one bunch. Has many other features!

Image Zoom 0.2.3
Images and text of a website can be resized with the mousewheel.

Open Long Url [de] 0.2.2
Adds a dialog to open URLs spanning multiple lines. You can define characters to be removed from an URL like “>” used as quotation marks in e-mails.

Paste and Go [de] 0.4.3
Lets you paste an URL from the clipboard to the address bar and submit it in one single operation via Ctl+Sh+V or the context menu. This also works for the search bar (Ctl+Sh+S).

Show Image [de] 0.3
Images get a context menu item to reload only that image (and not the entire page). Useful for handling “broken” images.

Tab Mix Plus [de] 0.3
A powerful tabbed browsing Extension. Complex configuration of when and how tabs will be opened. Multiple tab header lines, x-symbol to close a specific tag, disable javascript or plugins etc. for a tab, prevent a tag from changing/reloading, mark unread tabs, mouse navigation through tabs, tab history and recovery. Many more features. Seems to be the best tabbed browsing Extension around!

Configuration Utilities

Locale Switcher 0.3
Define the locale (language) Firefox should run with.

Mimetype Editor [de] 0.2
Edit and add MIME types and their handling.

Mozex 1.07.1
A modded version of the official mozex Extension specially for use with Firefox. You can easily define external applications to be used for certain protocols (news://, irc:// etc.), an application to view site source, and also integrate your favorite text-editor for forms’ textareas.

MR Tech Local Install [de] 4.0
Heavily simplifies the use of the Extension Manager. Sorting of Extensions, easy installation of saved Extensions via a file open dialog, generate a report of installed Extensions.

Tweak Network Settings [de] 1.0
You can set maximum number of simultaneous connections and HTTP pipelining support.

User Agent Switcher [de] 0.6.7
Chose the user agent string to be sent from a editable list. Newer be bored with websites telling you “You must use Internet Exploder to access this website”!

Miscellaneous

BugMeNot [de] 0.9
Integration of the BugMeNot database. Login forms are filled and optionally even submitted.

CuteMenus [de] 0.4
Additional menu icons. I use the Smoke CuteMenus icons (had to be installed manually) with the Smoke Firefox Theme. Get smoky at Aaron Spuler’s website.

Get File Size [de] 1.1.3
Shows you the file size and date of a linked URL in the Link Properties when available. You can also display the raw HTTP server headers.

Greasemonkey 0.5.3
A genius Extension allowing you to change webpages’ sourcecode on the fly adding javascript commands on the client-side.

Sitebar Sidebar 1.01
A Sidebar for displaying a SiteBar webinterface.

Other Extensions that might be useful for you (but not me)

As I filter advertisements and other annoyances with Squid in combination with adzapper under Linux as well as under Windows/Cygwin, I don’t need an extra ad blocking Extension. But the following seems to be a good choice for browser side ad blocking.

Adblock Plus
Extended version of Adblock ad blocker with whitelist support.

Adblock Filterset.G Updater
Periodical automatic download and import of Filterset.G filterlists (including whitelists).

Caveats

Installing that many Extensions will result in a longer startup time and slightly less performance. But my Firefox (on an Athlon XP 2500+) starts in a few seconds and still many times faster than the good ole Mozilla Browser.
Incompatibilities and conflicts between Extensions is an issue. Some Extensions won’t run correctly at the same time, others have to be configured not to hookup the same functions. An example is tabbed browsing configuration and mouse handling.
The worst case caused by Extensions going mad is that Firefox not starting up. In that case use the -safe-mode parameter to skip loading any Extension and Themes.

Where to get Extensions

ChangeLog

[2006-04-23: Add tags.]

Next Page »

Blog at WordPress.com.