Skip to content

Tag Archives: command line

Managing Music from the Command Line

30-Jun-09

Okay. I've been curious for a while about trying to manage my music from the command line. All the media managers I have used so far have been a bit too bloated for my tastes. Because of this I decided to try out MPD (Music Player Daemon). It looked pretty cool, but I didn't have a good way to quickly queue up a bunch of songs I wanted to listen to. After trying out a few solutions by others, I wrote two of my own solutions.

The first was a fuzzy matching system, and the second was a "blob" matching system. Both allow me to queue up an entire album by typing something short.

Because I haven't finished tweaking the first solution, and the second one is working impressively, I'll be posting about it only.

What You'll Need:

  • mpd
  • mpc
  • Python 2.6

Here is the code:

?View Code PYTHON
#!/usr/bin/python
from subprocess import Popen, PIPE
import sys
 
class Database:
	def __init__(self, terms=None):
		self.terms = set()
		self.tree = (set(), dict())
		if terms is not None:
			self.populate(terms)
 
	def populate(self, terms):
		for term in terms:
			self.add(term)
 
	def variations(self, word):
		result = set([word])
		if word.startswith("0") and word != "0":
			#This allows "02" to be found as "2"
			result.add(word)
		elif word in frozenset(["i", "ii", "iii"]):
			#This allows "II" to be found as "2"
			result.add(str(len(word)))
		return result
 
	def words(self, term):
		term = term.lower()
		words = set()
		buf = ""
		for char in term:
			if char.isalnum():
				buf += char
			else:
				if buf != "":
					words = words.union(self.variations(buf))
					buf = ""
		if buf != "":
			words = words.union(self.variations(buf))
		return words
 
	def add(self, term):
		self.terms.add(term)
		for word in self.words(term):
			current = self.tree
			for char in word:
				if char not in current[1]:
					current[1][char] = (set(), dict())
				current = current[1][char]
			current[0].add(term)
 
	def search(self, blob, union=False):
		#This is for excluding words from a search
		if "~" in blob:
			#Excludes titles with ANY words from exclude
			blob, remove = blob.lower().split("~")
			mode = True
		elif "#" in blob:
			#Excludes titles with ALL words from exclude
			blob, remove = blob.lower().split("#")
			mode = False
		else:
			remove = None
			blob = blob.lower()
		found = dict()
		current = self.tree
		i = 0
		for char in blob:
			if char in current[1]:
				current = current[1][char]
				i += 1
				if len(current[0]) > 0:
					found[blob[i:]] = current[0]
			else:
				break
		final = set()
		for k, v in found.items():
			if k == "":
				final |= v
			else:
				if union:
					final |= v | self.search(k)
				else:
					final |= v & self.search(k)
		if remove is not None:
			remove = self.search(remove, mode)
			final -= remove
		return final
 
	def __contains__(self, other):
		return other in self.terms
 
#Initialize and populate album database
db = Database()
#with open("/var/lib/mpd/tag_cache") as f:
#	for line in f:
#		if line.startswith("Album: "):
#			album = line[7:-1]
#			if album not in db:
#				db.add(album)
#We'll get the album list from mpc instead of the tag_cache file. I haven't done a benchmark.
p1 = Popen(["mpc", "list", "album"], stdout=PIPE)
p1.wait()
with p1.stdout as f:
	for line in f:
		album = line[:-1]
		if album != "":
			db.add(album)
 
#Parse arguments
if len(sys.argv) == 2:
	searches = [sys.argv[1]]
else:
	print "No album specified. Exiting..."
	sys.exit()
 
#Perform search
r = db.search(searches[0])
r = list(r)
 
#If more than one album is returned, ask the user to choose which one we will play.
if len(r) > 1:
	for i in xrange(len(r)):
		print " " + str(i+1) + ")", r[i]
	r = r[int(raw_input("Enter a number: ")) - 1]
elif len(r) == 1:
	r = r[0]
else:
	print "No albums found. Exiting..."
	sys.exit()
 
print "Playing album '" + r + "'"
 
#Find the tracks in the album
p1 = Popen(['mpc', 'find', 'album', r], stdout=PIPE)
p1.wait()
 
#Clear the current playlist
Popen(['mpc', 'clear'], stdout=PIPE).wait()
 
#Queue up all the tracks in the album
with p1.stdout as f:
	for line in f:
		Popen(['mpc', 'add', line[:-1]], stdout=PIPE).wait()
 
#Let MPC print a list of the tracks we have queued
Popen(['mpc', 'playlist']).wait()
 
#Start playback
Popen(['mpc', 'play'], stdout=PIPE).wait()

Save that as "album" or whatever you would like. Put it in your home directory or wherever you would like. Finally, open ~/.bashrc (for Ubuntu users, at least), and add an alias pointing to the script. I use "alias album='~/album'".

Make sure you set the script to executable.

Finally, because I enjoy having my listening history available on last.fm, I also installed lastmp to scrobble songs played with MPD.

Oh yeah. I almost forgot usage instructions. With the setup described above, one could just type "album wolfsrain" to play the Wolf's Rain OST (the script would prompt you to select either the first or second volume) or "album fiction" to play Yuki Kajiura's solo album "Fiction".

I call this album search method a "blob search" because you can type any words from an album title, in any order and without spaces, and still find the album. For instance, both "album wishyou" and "album hereyouwish" will start the playback of Wish You Were Here in my library.

Embed Terminal Into Desktop

28-May-09

There are some neat things that I have been looking into for customizing my installation of Ubuntu 9.04, one of which is embedding a terminal into the desktop so that I don't have to worry about closing it on accident (not to mention that it looks cool, too). Seeing as I have had to do this multiple times, I decided to write down the steps. While I know there are other tutorials, I spent too long looking for one that worked correctly (read: to my needs). This is cross-posted from The League of Magnificent Scoundrels.

Software Required

  • Compiz must be running. You'll also need CompizConfig, as detailed below.
  • Terminal (duh)

1. Getting Software

The first thing we will do is install CompizConfig. For this we will open up the Add/Remove application. For those new to Ubuntu, you click Applications, and select Add/Remove. After this opens, search for compiz and check Advanced Desktop Effects Settings (ccsm). Now search for irssi and check it. Click apply, and when the programs are finished installing, you can close the window.

2. Creating a Terminal Profile

For the embedding to work, we need to create a new profile for terminal. We need to do this because Compiz will change the behavior of the terminal depending on it's title.

Open up a terminal (press Alt+F2 and type gnome-terminal). On the menu bar, select Edit, then Profiles. Click New and name it "deskie" (or whatever else you want to as long as it's a unique name).

Under the General tab, uncheck "Show menubar by default". Moving over to the Title tab, name it deskie (or what you named it before, if different) and set to "keep initial title". Under the Colors tab, select White on Black, or whatever will suit your theme. Next we will move to Background. Set the Transparency to 0% or whatever fits your theme. Under the Scrolling tab, disable the scrollbar. After you've done what you want with this, close out of the profile editor.

3. Setting up CompizConfig

Now open CompizConfig (under System -> Preferences -> CompizConfig). The first thing we'll do here is search for Window Decoration, and click on it. Under Decoration Window, we'll replace "any" with "!title=deskie", without the quotes. Now search for Window Rules. Enable it, then click on it. We'll be adding "title=deskie" (without quotes) to:

  • Skip taskbar
  • Skip pager
  • Below
  • Sticky
  • Non resizable windows
  • Non minimizable windows
  • Non maximizable windows
  • Non closable windows

After these are filled in, go to the Size rules tab. Click New and add "title=deskie" and set the height and width you want the window to be. When you are satisfied, close CompizConfig.

4. The Aftermath

If you want to see what you've done, press Alt+F2 and type "gnome-terminal --window-with-profile=deskie" as the command and hit enter. You should now have a neat "embedded" terminal. To move it where you want, hold Alt, then click and drag.

If you want one to load on startup, go to System -> Preferences -> Startup Applications, and click Add. Name it "Embedded Terminal" and put "gnome-terminal --window-with-profile=deskie" as the command.

That should work, as it has for me. If you have any questions, comments, or concerns, feel free to let me know!

Empty Trash with Permissions

16-Jan-09

If you ever send something to the trash without sufficient user privileges to delete it (an issue which used to annoy me very often), you can use sudo rm -rf ~/.local/share/Trash/files/* to empty the trash with super user privileges.

And now you know where your trash is stored (if you run Gnome, at least)!