<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>pyradio/stations.csv</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -2,7 +2,10 @@
 
 # PyRadio: Curses based Internet Radio Player
 # http://www.coderholic.com/pyradio
-# Ben Dowling - 2008
+# Ben Dowling - 2009
+
+# TODO: 
+# - Allow CSV stations file path to be provided as a command line argument
 
 import os
 import sys
@@ -10,28 +13,6 @@ import curses
 import thread
 import subprocess
 
-stations = [
-	(&quot;Afterhours.FM (Trance/Progressive)&quot;, &quot;http://at2.ah.fm:80&quot;),	
-	(&quot;BBC Radio 1&quot;, &quot;mms://wmlive-acl.bbc.co.uk/wms/radio1/radio1_nb_e1s1&quot;),
-	(&quot;Digitally Imported: Chillout&quot;, &quot;http://di.fm/mp3/chillout.pls&quot;),
-	(&quot;Digitally Imported: Trance&quot;, &quot;http://di.fm/mp3/trance.pls&quot;),
-	(&quot;Digitally Imported: Classic Techno&quot;, &quot;http://di.fm/mp3/classictechno.pls&quot;),
-	(&quot;Electronic Culture&quot;, &quot;http://www.shouted.fm/tunein/electro-dsl.m3u&quot;),
-	(&quot;Frequence 3 (Pop)&quot;, &quot;http://streams.frequence3.net/hd-mp3.m3u&quot;),
-	(&quot;Mostly Classical&quot;, &quot;http://www.sky.fm/mp3/classical.pls&quot;),
-	(&quot;Proton Radio (House/Dance)&quot;, &quot;http://www.protonradio.com:8000&quot;),
-	(&quot;Ragga Kings&quot;, &quot;http://www.raggakings.net/listen.m3u&quot;),
-	(&quot;Secret Agent (Downtempo)&quot;, &quot;http://somafm.com/secretagent.pls&quot;),
-	(&quot;Slay Radio (C64 Remix)&quot;, &quot;http://sc.slayradio.org:8000/listen.pls&quot;),
-	(&quot;Smooth FM (Jazz)&quot;, &quot;http://66.55.143.195:9028&quot;),
-	(&quot;SomaFM: Groove Salad&quot;, &quot;http://somafm.com/startstream=groovesalad.pls&quot;),
-	(&quot;SomaFM: Beat Blender&quot;, &quot;http://somafm.com/startstream=beatblender.pls&quot;),
-	(&quot;SomaFM: Cliq Hop&quot;, &quot;http://somafm.com/startstream=cliqhop.pls&quot;),
-	(&quot;SomaFM: Sonic Universe&quot;, &quot;http://somafm.com/startstream=sonicuniverse.pls&quot;),
-	(&quot;SomaFM: Tags Trance Trip&quot;, &quot;http://somafm.com/tagstrance.pls&quot;),
-	(&quot;Virgin Radio (Pop)&quot;, &quot;http://www.smgradio.com/core/audio/mp3/live.pls?service=vrbb&quot;),
-]
-
 class Log(object):
 	&quot;&quot;&quot; Log class that outputs text to a curses screen &quot;&quot;&quot;	
 
@@ -87,11 +68,21 @@ class Player(object):
 			os.kill(self.process.pid, 15)
 			self.process.wait()
 		self.process = None
+        
+	def volumeUp(self):
+		self.sendCommand(&quot;*&quot;)
+
+	def volumeDown(self):
+		self.sendCommand(&quot;/&quot;)
 
 class PyRadio(object):
 	startPos = 0
 	selection = 0
-
+	playing = -1
+	
+	def __init__(self, stations):
+		self.stations = stations
+	
 	def setup(self, stdscr):
 		self.stdscr = stdscr
 
@@ -107,7 +98,9 @@ class PyRadio(object):
 		curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_BLACK)
 		curses.init_pair(6, curses.COLOR_BLACK, curses.COLOR_MAGENTA)
 		curses.init_pair(7, curses.COLOR_BLACK, curses.COLOR_GREEN)
-
+		curses.init_pair(8, curses.COLOR_MAGENTA, curses.COLOR_BLACK)	
+		curses.init_pair(9, curses.COLOR_BLACK, curses.COLOR_GREEN)	
+		
 		self.maxY, self.maxX = stdscr.getmaxyx()
 
 		self.headWin = curses.newwin(1, self.maxX, 0, 0)
@@ -125,7 +118,7 @@ class PyRadio(object):
 		self.run()
 
 	def initHead(self):
-		info = &quot; PyRadio 0.1 &quot;
+		info = &quot; PyRadio 0.2 &quot;
 		self.headWin.addstr(0, 0, info, curses.color_pair(4))
 		rightStr = &quot;www.coderholic.com/pyradio&quot;
 		self.headWin.addstr(0, self.maxX - len(rightStr) - 1, rightStr, curses.color_pair(2))
@@ -154,11 +147,18 @@ class PyRadio(object):
 		for idx in range(maxDisplay - 1):
 			if(idx &gt; maxDisplay): break			
 			try:
-				station = stations[idx + self.startPos]
+				station = self.stations[idx + self.startPos]
 				col = curses.color_pair(5)
-				if idx + self.startPos == self.selection: 
+
+				if idx + self.startPos == self.selection and self.selection == self.playing: 
+					col = curses.color_pair(9)
+					self.bodyWin.hline(idx + 1, 1, ' ', self.bodyMaxX - 2, col)
+				elif idx + self.startPos == self.selection: 
 					col = curses.color_pair(6)
 					self.bodyWin.hline(idx + 1, 1, ' ', self.bodyMaxX - 2, col)
+				elif idx + self.startPos == self.playing:
+					col = curses.color_pair(4)
+					self.bodyWin.hline(idx + 1, 1, ' ', self.bodyMaxX - 2, col)
 				self.bodyWin.addstr(idx + 1, 1, station[0], col)
 
 			except IndexError:
@@ -174,35 +174,89 @@ class PyRadio(object):
 				break
 
 	def keypress(self, char):
+		# Number of stations to change with the page up/down keys
+		pageChange = 5
+		# Maximum number of stations that fit on the screen at once
+		maxDisplayedItems = self.bodyMaxY - 2
+
 		if char == curses.KEY_EXIT or char == ord('q'):
 			self.player.close()
 			return -1
-
 		elif char in (curses.KEY_ENTER, ord('\n'), ord('\r')):
-			name = stations[self.selection][0]
-			url = stations[self.selection][1]
+			self.playing = self.selection
+			name = self.stations[self.selection][0]
+			url = self.stations[self.selection][1].strip()
 			self.log.write('Playing ' + name)
 			self.player.play(url)
+			self.refreshBody()
 			return
 		elif char == curses.KEY_DOWN or char== ord('j'):
-			if self.selection &lt; len(stations) - 1:
-				if self.selection - self.startPos &gt; (self.bodyMaxY - 4):
-					self.startPos += 1				
+			if self.selection &lt; len(self.stations) - 1:
 				self.selection += 1
+				if self.selection - self.startPos &gt;= maxDisplayedItems:
+					self.startPos += 1								
 				self.refreshBody()
 			return
 		elif char == curses.KEY_UP or char == ord('k'):
-			# Scroll stories up by one
 			if self.selection &gt; 0:
 				self.selection -= 1
 				if self.selection &lt; self.startPos:
 					self.startPos -= 1
 				self.refreshBody()
 			return
+		elif char == ord('+'):
+			self.player.volumeUp()
+			return
+		elif char == ord('-'):
+			self.player.volumeDown()
+			return            
+		elif char == curses.KEY_PPAGE:
+			self.selection = max(0, self.selection - pageChange)
+			if self.selection &lt; self.startPos:
+				self.startPos = self.selection
+			self.refreshBody()
+			return
+		elif char == curses.KEY_NPAGE:
+			self.selection = min(len(self.stations) - 1, self.selection + pageChange)
+			if self.selection - self.startPos &gt;= maxDisplayedItems:
+				self.startPos = self.selection - maxDisplayedItems + 1
+			self.refreshBody()
+			return
 		elif char == ord('m'):
 			self.player.mute()
 			return
 
 if __name__ == &quot;__main__&quot;:
-	pyRadio = PyRadio()
+	# Default stations list
+	stations = [
+		(&quot;Digitally Imported: Chillout&quot;, &quot;http://di.fm/mp3/chillout.pls&quot;),
+		(&quot;Digitally Imported: Trance&quot;, &quot;http://di.fm/mp3/trance.pls&quot;),
+		(&quot;Digitally Imported: Classic Techno&quot;, &quot;http://di.fm/mp3/classictechno.pls&quot;),
+		(&quot;Frequence 3 (Pop)&quot;, &quot;http://streams.frequence3.net/hd-mp3.m3u&quot;),
+		(&quot;Mostly Classical&quot;, &quot;http://www.sky.fm/mp3/classical.pls&quot;),
+		(&quot;Ragga Kings&quot;, &quot;http://www.raggakings.net/listen.m3u&quot;),
+		(&quot;Secret Agent (Downtempo)&quot;, &quot;http://somafm.com/secretagent.pls&quot;),
+		(&quot;Slay Radio (C64 Remix)&quot;, &quot;http://sc.slayradio.org:8000/listen.pls&quot;),
+		(&quot;SomaFM: Groove Salad&quot;, &quot;http://somafm.com/startstream=groovesalad.pls&quot;),
+		(&quot;SomaFM: Beat Blender&quot;, &quot;http://somafm.com/startstream=beatblender.pls&quot;),
+		(&quot;SomaFM: Cliq Hop&quot;, &quot;http://somafm.com/startstream=cliqhop.pls&quot;),
+		(&quot;SomaFM: Sonic Universe&quot;, &quot;http://somafm.com/startstream=sonicuniverse.pls&quot;),
+		(&quot;SomaFM: Tags Trance Trip&quot;, &quot;http://somafm.com/tagstrance.pls&quot;),
+	]
+
+	try:
+		csv = open(&quot;stations.csv&quot;, &quot;r&quot;)
+		stations = []
+		for line in csv.readlines():
+			line = line.strip()
+			if not line: continue	
+			try:
+				(name, url) = line.split(&quot;,&quot;)
+				stations.append((name, url))
+			except:
+				print &quot;Error, skipping &quot;, line
+	except IOError:
+		print &quot;No stations.csv file exists in the current directory. Using default stations list&quot;
+		
+	pyRadio = PyRadio(stations)
 	curses.wrapper(pyRadio.setup)</diff>
      <filename>pyradio/pyradio</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>b2713491ec72b1a48f702c3d7a92edd289e33b24</id>
    </parent>
  </parents>
  <author>
    <name>Ben</name>
    <email>ben@coderholic.com</email>
  </author>
  <url>http://github.com/coderholic/pyradio/commit/8e84db9f83c2b38075a6af2e886985b4e748ded6</url>
  <id>8e84db9f83c2b38075a6af2e886985b4e748ded6</id>
  <committed-date>2009-06-12T07:49:49-07:00</committed-date>
  <authored-date>2009-06-12T07:49:49-07:00</authored-date>
  <message>Added support for external CSV stations file.
PageUp/Down keys now move 5 stations at a time.
+/- changes the volume.
Other minor fixes.</message>
  <tree>3fb7601c7ac51d101b92e9d5f6f27cde140508e5</tree>
  <committer>
    <name>Ben</name>
    <email>ben@coderholic.com</email>
  </committer>
</commit>
