Add Python-WiFi-Radio (as deprecated code)
This commit is contained in:
parent
606d35129f
commit
47e3c8a275
3 changed files with 594 additions and 0 deletions
527
Python-WiFi-Radio/PiPhi.py
Executable file
527
Python-WiFi-Radio/PiPhi.py
Executable file
|
|
@ -0,0 +1,527 @@
|
|||
#! /usr/bin/python
|
||||
|
||||
# UI wrapper for 'pianobar' client for Pandora, using Adafruit 16x2 LCD
|
||||
# Pi Plate for Raspberry Pi.
|
||||
# Written by Adafruit Industries. MIT license.
|
||||
#
|
||||
# Required hardware includes any internet-connected Raspberry Pi
|
||||
# system, any of the Adafruit 16x2 LCD w/Keypad Pi Plate varieties
|
||||
# and either headphones or amplified speakers.
|
||||
# Required software includes the Adafruit Raspberry Pi Python Code
|
||||
# repository, pexpect library and pianobar. A Pandora account is
|
||||
# also necessary.
|
||||
#
|
||||
# Resources:
|
||||
# http://www.adafruit.com/products/1109 RGB Positive 16x2 LCD + Keypad
|
||||
# http://www.adafruit.com/products/1110 RGB Negative 16x2 LCD + Keypad
|
||||
# http://www.adafruit.com/products/1115 Blue & White 16x2 LCD + Keypad
|
||||
|
||||
import atexit, pexpect, pickle, socket, time, subprocess
|
||||
from Adafruit_I2C import Adafruit_I2C
|
||||
from Adafruit_MCP230xx import Adafruit_MCP230XX
|
||||
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate
|
||||
|
||||
|
||||
# Constants:
|
||||
RGB_LCD = False # Set to 'True' if using color backlit LCD
|
||||
HALT_ON_EXIT = False # Set to 'True' to shut down system when exiting
|
||||
MAX_FPS = 6 if RGB_LCD else 4 # Limit screen refresh rate for legibility
|
||||
VOL_MIN = -20
|
||||
VOL_MAX = 15
|
||||
VOL_DEFAULT = 0
|
||||
HOLD_TIME = 3.0 # Time (seconds) to hold select button for shut down
|
||||
PICKLEFILE = '/home/pi/.config/pianobar/state.p'
|
||||
|
||||
# Global state:
|
||||
volCur = VOL_MIN # Current volume
|
||||
volNew = VOL_DEFAULT # 'Next' volume after interactions
|
||||
volSpeed = 1.0 # Speed of volume change (accelerates w/hold)
|
||||
volSet = False # True if currently setting volume
|
||||
paused = False # True if music is paused
|
||||
staSel = False # True if selecting station
|
||||
volTime = 0 # Time of last volume button interaction
|
||||
playMsgTime = 0 # Time of last 'Playing' message display
|
||||
staBtnTime = 0 # Time of last button press on station menu
|
||||
xTitle = 16 # X position of song title (scrolling)
|
||||
xInfo = 16 # X position of artist/album (scrolling)
|
||||
xStation = 0 # X position of station (scrolling)
|
||||
xTitleWrap = 0
|
||||
xInfoWrap = 0
|
||||
xStationWrap = 0
|
||||
songTitle = ''
|
||||
songInfo = ''
|
||||
stationNum = 0 # Station currently playing
|
||||
stationNew = 0 # Station currently highlighted in menu
|
||||
stationList = ['']
|
||||
stationIDs = ['']
|
||||
|
||||
# Char 7 gets reloaded for different modes. These are the bitmaps:
|
||||
charSevenBitmaps = [
|
||||
[0b10000, # Play (also selected station)
|
||||
0b11000,
|
||||
0b11100,
|
||||
0b11110,
|
||||
0b11100,
|
||||
0b11000,
|
||||
0b10000,
|
||||
0b00000],
|
||||
[0b11011, # Pause
|
||||
0b11011,
|
||||
0b11011,
|
||||
0b11011,
|
||||
0b11011,
|
||||
0b11011,
|
||||
0b11011,
|
||||
0b00000],
|
||||
[0b00000, # Next Track
|
||||
0b10100,
|
||||
0b11010,
|
||||
0b11101,
|
||||
0b11010,
|
||||
0b10100,
|
||||
0b00000,
|
||||
0b00000]]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Exit handler tries to leave LCD in a nice state.
|
||||
def cleanExit():
|
||||
if lcd is not None:
|
||||
time.sleep(0.5)
|
||||
lcd.backlight(lcd.OFF)
|
||||
lcd.clear()
|
||||
lcd.stop()
|
||||
if pianobar is not None:
|
||||
pianobar.kill(0)
|
||||
|
||||
|
||||
def shutdown():
|
||||
lcd.clear()
|
||||
if HALT_ON_EXIT:
|
||||
if RGB_LCD: lcd.backlight(lcd.YELLOW)
|
||||
lcd.message('Wait 30 seconds\nto unplug...')
|
||||
# Ramp down volume over 5 seconds while 'wait' message shows
|
||||
steps = int((volCur - VOL_MIN) + 0.5) + 1
|
||||
pause = 5.0 / steps
|
||||
for i in range(steps):
|
||||
pianobar.send('(')
|
||||
time.sleep(pause)
|
||||
subprocess.call("sync")
|
||||
cleanExit()
|
||||
subprocess.call(["shutdown", "-h", "now"])
|
||||
else:
|
||||
exit(0)
|
||||
|
||||
|
||||
# Draws song title or artist/album marquee at given position.
|
||||
# Returns new position to avoid global uglies.
|
||||
def marquee(s, x, y, xWrap):
|
||||
lcd.setCursor(0, y)
|
||||
if x > 0: # Initially scrolls in from right edge
|
||||
lcd.message(' ' * x + s[0:16-x])
|
||||
else: # Then scrolls w/wrap indefinitely
|
||||
lcd.message(s[-x:16-x])
|
||||
if x < xWrap: return 0
|
||||
return x - 1
|
||||
|
||||
|
||||
def drawPlaying():
|
||||
lcd.createChar(7, charSevenBitmaps[0])
|
||||
lcd.setCursor(0, 1)
|
||||
lcd.message('\x07 Playing ')
|
||||
return time.time()
|
||||
|
||||
|
||||
def drawPaused():
|
||||
lcd.createChar(7, charSevenBitmaps[1])
|
||||
lcd.setCursor(0, 1)
|
||||
lcd.message('\x07 Paused ')
|
||||
|
||||
|
||||
def drawNextTrack():
|
||||
lcd.createChar(7, charSevenBitmaps[2])
|
||||
lcd.setCursor(0, 1)
|
||||
lcd.message('\x07 Next track... ')
|
||||
|
||||
|
||||
# Draw station menu (overwrites fulls screen to facilitate scrolling)
|
||||
def drawStations(stationNew, listTop, xStation, staBtnTime):
|
||||
last = len(stationList)
|
||||
if last > 2: last = 2 # Limit stations displayed
|
||||
ret = 0 # Default return value (for station scrolling)
|
||||
line = 0 # Line counter
|
||||
msg = '' # Clear output string to start
|
||||
for s in stationList[listTop:listTop+2]: # For each station...
|
||||
sLen = len(s) # Length of station name
|
||||
if (listTop + line) == stationNew: # Selected station?
|
||||
msg += chr(7) # Show selection cursor
|
||||
if sLen > 15: # Is station name longer than line?
|
||||
if (time.time() - staBtnTime) < 0.5:
|
||||
# Just show start of line for half a sec
|
||||
s2 = s[0:15]
|
||||
else:
|
||||
# After that, scrollinate
|
||||
s2 = s + ' ' + s[0:15]
|
||||
xStationWrap = -(sLen + 2)
|
||||
s2 = s2[-xStation:15-xStation]
|
||||
if xStation > xStationWrap:
|
||||
ret = xStation - 1
|
||||
else: # Short station name - pad w/spaces if needed
|
||||
s2 = s[0:15]
|
||||
if sLen < 15: s2 += ' ' * (15 - sLen)
|
||||
else: # Not currently-selected station
|
||||
msg += ' ' # No cursor
|
||||
s2 = s[0:15] # Clip or pad name to 15 chars
|
||||
if sLen < 15: s2 += ' ' * (15 - sLen)
|
||||
msg += s2 # Add station name to output message
|
||||
line += 1
|
||||
if line == last: break
|
||||
msg += '\n' # Not last line - add newline
|
||||
lcd.setCursor(0, 0)
|
||||
lcd.message(msg)
|
||||
return ret
|
||||
|
||||
|
||||
def getStations():
|
||||
lcd.clear()
|
||||
lcd.message('Retrieving\nstation list...')
|
||||
pianobar.expect('Select station: ', timeout=20)
|
||||
# 'before' is now string of stations I believe
|
||||
# break up into separate lines
|
||||
a = pianobar.before.splitlines()
|
||||
names = []
|
||||
ids = []
|
||||
# Parse each line
|
||||
for b in a[:-1]: # Skip last line (station select prompt)
|
||||
# Occasionally a queued up 'TIME: -XX:XX/XX:XX' string or
|
||||
# 'new playlist...' appears in the output. Station list
|
||||
# entries have a known format, so it's straightforward to
|
||||
# skip these bogus lines.
|
||||
# print '\"{}\"'.format(b)
|
||||
if (b.find('playlist...') >= 0) or (b.find('Autostart') >= 0):
|
||||
continue
|
||||
# if b[0:5].find(':') >= 0: continue
|
||||
# if (b.find(':') >= 0) or (len(b) < 13): continue
|
||||
# Alternate strategy: must contain either 'QuickMix' or 'Radio':
|
||||
# Somehow the 'playlist' case would get through this check. Buh?
|
||||
if b.find('Radio') or b.find('QuickMix'):
|
||||
id = b[5:7].strip()
|
||||
name = b[13:].strip()
|
||||
# If 'QuickMix' found, always put at head of list
|
||||
if name == 'QuickMix':
|
||||
ids.insert(0, id)
|
||||
names.insert(0, name)
|
||||
else:
|
||||
ids.append(id)
|
||||
names.append(name)
|
||||
return names, ids
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Initialization
|
||||
|
||||
atexit.register(cleanExit)
|
||||
|
||||
lcd = Adafruit_CharLCDPlate()
|
||||
lcd.begin(16, 2)
|
||||
lcd.clear()
|
||||
|
||||
# Create volume bargraph custom characters (chars 0-5):
|
||||
for i in range(6):
|
||||
bitmap = []
|
||||
bits = (255 << (5 - i)) & 0x1f
|
||||
for j in range(8): bitmap.append(bits)
|
||||
lcd.createChar(i, bitmap)
|
||||
|
||||
# Create up/down icon (char 6)
|
||||
lcd.createChar(6,
|
||||
[0b00100,
|
||||
0b01110,
|
||||
0b11111,
|
||||
0b00000,
|
||||
0b00000,
|
||||
0b11111,
|
||||
0b01110,
|
||||
0b00100])
|
||||
|
||||
# By default, char 7 is loaded in 'pause' state
|
||||
lcd.createChar(7, charSevenBitmaps[1])
|
||||
|
||||
# Get last-used volume and station name from pickle file
|
||||
try:
|
||||
f = open(PICKLEFILE, 'rb')
|
||||
v = pickle.load(f)
|
||||
f.close()
|
||||
volNew = v[0]
|
||||
defaultStation = v[1]
|
||||
except:
|
||||
defaultStation = None
|
||||
|
||||
# Show IP address (if network is available). System might be freshly
|
||||
# booted and not have an address yet, so keep trying for a couple minutes
|
||||
# before reporting failure.
|
||||
t = time.time()
|
||||
while True:
|
||||
if (time.time() - t) > 120:
|
||||
# No connection reached after 2 minutes
|
||||
if RGB_LCD: lcd.backlight(lcd.RED)
|
||||
lcd.message('Network is\nunreachable')
|
||||
time.sleep(30)
|
||||
exit(0)
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(('8.8.8.8', 0))
|
||||
if RGB_LCD: lcd.backlight(lcd.GREEN)
|
||||
else: lcd.backlight(lcd.ON)
|
||||
lcd.message('My IP address is\n' + s.getsockname()[0])
|
||||
time.sleep(5)
|
||||
break # Success -- let's hear some music!
|
||||
except:
|
||||
time.sleep(1) # Pause a moment, keep trying
|
||||
|
||||
# Launch pianobar as pi user (to use same config data, etc.) in background:
|
||||
print('Spawning pianobar...')
|
||||
pianobar = pexpect.spawn('sudo -u pi pianobar')
|
||||
print('Receiving station list...')
|
||||
pianobar.expect('Get stations... Ok.\r\n', timeout=60)
|
||||
stationList, stationIDs = getStations()
|
||||
try: # Use station name from last session
|
||||
stationNum = stationList.index(defaultStation)
|
||||
except: # Use first station in list
|
||||
stationNum = 0
|
||||
print 'Selecting station ' + stationIDs[stationNum]
|
||||
pianobar.sendline(stationIDs[stationNum])
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Main loop. This is not quite a straight-up state machine; there's some
|
||||
# persnickety 'nesting' and canceling among mode states, so instead a few
|
||||
# global booleans take care of it rather than a mode variable.
|
||||
|
||||
if RGB_LCD: lcd.backlight(lcd.ON)
|
||||
lastTime = 0
|
||||
|
||||
pattern_list = pianobar.compile_pattern_list(['SONG: ', 'STATION: ', 'TIME: '])
|
||||
|
||||
while pianobar.isalive():
|
||||
|
||||
# Process all pending pianobar output
|
||||
while True:
|
||||
try:
|
||||
x = pianobar.expect(pattern_list, timeout=0)
|
||||
if x == 0:
|
||||
songTitle = ''
|
||||
songInfo = ''
|
||||
xTitle = 16
|
||||
xInfo = 16
|
||||
xTitleWrap = 0
|
||||
xInfoWrap = 0
|
||||
x = pianobar.expect(' \| ')
|
||||
if x == 0: # Title | Artist | Album
|
||||
print 'Song: "{}"'.format(pianobar.before)
|
||||
s = pianobar.before + ' '
|
||||
n = len(s)
|
||||
xTitleWrap = -n + 2
|
||||
# 1+ copies + up to 15 chars for repeating scroll
|
||||
songTitle = s * (1 + (16 / n)) + s[0:16]
|
||||
x = pianobar.expect(' \| ')
|
||||
if x == 0:
|
||||
print 'Artist: "{}"'.format(pianobar.before)
|
||||
artist = pianobar.before
|
||||
x = pianobar.expect('\r\n')
|
||||
if x == 0:
|
||||
print 'Album: "{}"'.format(pianobar.before)
|
||||
s = artist + ' < ' + pianobar.before + ' > '
|
||||
n = len(s)
|
||||
xInfoWrap = -n + 2
|
||||
# 1+ copies + up to 15 chars for repeating scroll
|
||||
songInfo = s * (2 + (16 / n)) + s[0:16]
|
||||
elif x == 1:
|
||||
x = pianobar.expect(' \| ')
|
||||
if x == 0:
|
||||
print 'Station: "{}"'.format(pianobar.before)
|
||||
elif x == 2:
|
||||
# Time doesn't include newline - prints over itself.
|
||||
x = pianobar.expect('\r', timeout=1)
|
||||
if x == 0:
|
||||
print 'Time: {}'.format(pianobar.before)
|
||||
# Periodically dump state (volume and station name)
|
||||
# to pickle file so it's remembered between each run.
|
||||
try:
|
||||
f = open(PICKLEFILE, 'wb')
|
||||
pickle.dump([volCur, stationList[stationNum]], f)
|
||||
f.close()
|
||||
except:
|
||||
pass
|
||||
except pexpect.EOF:
|
||||
break
|
||||
except pexpect.TIMEOUT:
|
||||
break
|
||||
|
||||
|
||||
# Poll all buttons once, avoids repeated I2C traffic for different cases
|
||||
b = lcd.buttons()
|
||||
btnUp = b & (1 << lcd.UP)
|
||||
btnDown = b & (1 <<lcd.DOWN)
|
||||
btnLeft = b & (1 <<lcd.LEFT)
|
||||
btnRight = b & (1 <<lcd.RIGHT)
|
||||
btnSel = b & (1 <<lcd.SELECT)
|
||||
|
||||
# Certain button actions occur regardless of current mode.
|
||||
# Holding the select button (for shutdown) is a big one.
|
||||
if btnSel:
|
||||
|
||||
t = time.time() # Start time of button press
|
||||
while lcd.buttonPressed(lcd.SELECT): # Wait for button release
|
||||
if (time.time() - t) >= HOLD_TIME: # Extended hold?
|
||||
shutdown() # We're outta here
|
||||
# If tapped, different things in different modes...
|
||||
if staSel: # In station select menu...
|
||||
pianobar.send('\n') # Cancel station select
|
||||
staSel = False # Cancel menu and return to
|
||||
if paused: drawPaused() # play or paused state
|
||||
else: # In play/pause state...
|
||||
volSet = False # Exit volume-setting mode (if there)
|
||||
paused = not paused # Toggle play/pause
|
||||
pianobar.send('p') # Toggle pianobar play/pause
|
||||
if paused: drawPaused() # Display play/pause change
|
||||
else: playMsgTime = drawPlaying()
|
||||
|
||||
# Right button advances to next track in all modes, even paused,
|
||||
# when setting volume, in station menu, etc.
|
||||
elif btnRight:
|
||||
|
||||
drawNextTrack()
|
||||
if staSel: # Cancel station select, if there
|
||||
pianobar.send('\n')
|
||||
staSel = False
|
||||
paused = False # Un-pause, if there
|
||||
volSet = False
|
||||
pianobar.send('n')
|
||||
|
||||
# Left button enters station menu (if currently in play/pause state),
|
||||
# or selects the new station and returns.
|
||||
elif btnLeft:
|
||||
|
||||
staSel = not staSel # Toggle station menu state
|
||||
if staSel:
|
||||
# Entering station selection menu. Don't return to volume
|
||||
# select, regardless of outcome, just return to normal play.
|
||||
pianobar.send('s')
|
||||
lcd.createChar(7, charSevenBitmaps[0])
|
||||
volSet = False
|
||||
cursorY = 0 # Cursor position on screen
|
||||
stationNew = 0 # Cursor position in list
|
||||
listTop = 0 # Top of list on screen
|
||||
xStation = 0 # X scrolling for long station names
|
||||
# Just keep the list we made at start-up
|
||||
# stationList, stationIDs = getStations()
|
||||
staBtnTime = time.time()
|
||||
drawStations(stationNew, listTop, 0, staBtnTime)
|
||||
else:
|
||||
# Just exited station menu with selection - go play.
|
||||
stationNum = stationNew # Make menu selection permanent
|
||||
print 'Selecting station: "{}"'.format(stationIDs[stationNum])
|
||||
pianobar.sendline(stationIDs[stationNum])
|
||||
paused = False
|
||||
|
||||
# Up/down buttons either set volume (in play/pause) or select station
|
||||
elif btnUp or btnDown:
|
||||
|
||||
if staSel:
|
||||
# Move up or down station menu
|
||||
if btnDown:
|
||||
if stationNew < (len(stationList) - 1):
|
||||
stationNew += 1 # Next station
|
||||
if cursorY < 1: cursorY += 1 # Move cursor
|
||||
else: listTop += 1 # Y-scroll
|
||||
xStation = 0 # Reset X-scroll
|
||||
elif stationNew > 0: # btnUp implied
|
||||
stationNew -= 1 # Prev station
|
||||
if cursorY > 0: cursorY -= 1 # Move cursor
|
||||
else: listTop -= 1 # Y-scroll
|
||||
xStation = 0 # Reset X-scroll
|
||||
staBtnTime = time.time() # Reset button time
|
||||
xStation = drawStations(stationNew, listTop, 0, staBtnTime)
|
||||
else:
|
||||
# Not in station menu
|
||||
if volSet is False:
|
||||
# Just entering volume-setting mode; init display
|
||||
lcd.setCursor(0, 1)
|
||||
volCurI = int((volCur - VOL_MIN) + 0.5)
|
||||
n = int(volCurI / 5)
|
||||
s = (chr(6) + ' Volume ' +
|
||||
chr(5) * n + # Solid brick(s)
|
||||
chr(volCurI % 5) + # Fractional brick
|
||||
chr(0) * (6 - n)) # Spaces
|
||||
lcd.message(s)
|
||||
volSet = True
|
||||
volSpeed = 1.0
|
||||
# Volume-setting mode now active (or was already there);
|
||||
# act on button press.
|
||||
if btnUp:
|
||||
volNew = volCur + volSpeed
|
||||
if volNew > VOL_MAX: volNew = VOL_MAX
|
||||
else:
|
||||
volNew = volCur - volSpeed
|
||||
if volNew < VOL_MIN: volNew = VOL_MIN
|
||||
volTime = time.time() # Time of last volume button press
|
||||
volSpeed *= 1.15 # Accelerate volume change
|
||||
|
||||
# Other logic specific to unpressed buttons:
|
||||
else:
|
||||
if staSel:
|
||||
# In station menu, X-scroll active station name if long
|
||||
if len(stationList[stationNew]) > 15:
|
||||
xStation = drawStations(stationNew, listTop, xStation,
|
||||
staBtnTime)
|
||||
elif volSet:
|
||||
volSpeed = 1.0 # Buttons released = reset volume speed
|
||||
# If no interaction in 4 seconds, return to prior state.
|
||||
# Volume bar will be erased by subsequent operations.
|
||||
if (time.time() - volTime) >= 4:
|
||||
volSet = False
|
||||
if paused: drawPaused()
|
||||
|
||||
# Various 'always on' logic independent of buttons
|
||||
if not staSel:
|
||||
# Play/pause/volume: draw upper line (song title)
|
||||
if songTitle is not None:
|
||||
xTitle = marquee(songTitle, xTitle, 0, xTitleWrap)
|
||||
|
||||
# Integerize current and new volume values
|
||||
volCurI = int((volCur - VOL_MIN) + 0.5)
|
||||
volNewI = int((volNew - VOL_MIN) + 0.5)
|
||||
volCur = volNew
|
||||
# Issue change to pianobar
|
||||
if volCurI != volNewI:
|
||||
d = volNewI - volCurI
|
||||
if d > 0: s = ')' * d
|
||||
else: s = '(' * -d
|
||||
pianobar.send(s)
|
||||
|
||||
# Draw lower line (volume or artist/album info):
|
||||
if volSet:
|
||||
if volNewI != volCurI: # Draw only changes
|
||||
if(volNewI > volCurI):
|
||||
x = int(volCurI / 5)
|
||||
n = int(volNewI / 5) - x
|
||||
s = chr(5) * n + chr(volNewI % 5)
|
||||
else:
|
||||
x = int(volNewI / 5)
|
||||
n = int(volCurI / 5) - x
|
||||
s = chr(volNewI % 5) + chr(0) * n
|
||||
lcd.setCursor(x + 9, 1)
|
||||
lcd.message(s)
|
||||
elif paused == False:
|
||||
if (time.time() - playMsgTime) >= 3:
|
||||
# Display artist/album (rather than 'Playing')
|
||||
xInfo = marquee(songInfo, xInfo, 1, xInfoWrap)
|
||||
|
||||
# Throttle frame rate, keeps screen legible
|
||||
while True:
|
||||
t = time.time()
|
||||
if (t - lastTime) > (1.0 / MAX_FPS): break
|
||||
lastTime = t
|
||||
4
Python-WiFi-Radio/README.md
Normal file
4
Python-WiFi-Radio/README.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Python-WiFi-Radio
|
||||
|
||||
DEPRECATED CODE, originally to accompany this guide:
|
||||
https://learn.adafruit.com/pi-wifi-radio
|
||||
63
Python-WiFi-Radio/config
Normal file
63
Python-WiFi-Radio/config
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# This is an example configuration file for pianobar. You may remove the # from
|
||||
# lines you need and copy/move this file to ~/.config/pianobar/config
|
||||
# See manpage for a description of the config keys
|
||||
#
|
||||
# User
|
||||
user = YOUR_EMAIL_ADDRESS
|
||||
password = YOUR_PASSWORD
|
||||
# or
|
||||
#password_command = gpg --decrypt ~/password
|
||||
|
||||
# Proxy (for those who are not living in the USA)
|
||||
#control_proxy = http://127.0.0.1:9090/
|
||||
|
||||
# Keybindings
|
||||
act_help = ?
|
||||
act_songlove = +
|
||||
act_songban = -
|
||||
act_stationaddmusic = a
|
||||
act_stationcreate = c
|
||||
act_stationdelete = d
|
||||
act_songexplain = e
|
||||
act_stationaddbygenre = g
|
||||
act_songinfo = i
|
||||
act_addshared = j
|
||||
act_songmove = m
|
||||
act_songnext = n
|
||||
act_songpause = p
|
||||
act_quit = q
|
||||
act_stationrename = r
|
||||
act_stationchange = s
|
||||
act_songtired = t
|
||||
act_upcoming = u
|
||||
act_stationselectquickmix = x
|
||||
act_voldown = (
|
||||
act_volup = )
|
||||
|
||||
# Misc
|
||||
#audio_quality = low
|
||||
autostart_station = 123456
|
||||
|
||||
#event_command = /home/pi/.config/pianobar/scripts/eventcmd.sh
|
||||
#fifo = /home/pi/.config/pianobar/ctl
|
||||
#sort = quickmix_10_name_az
|
||||
#love_icon = [+]
|
||||
#ban_icon = [-]
|
||||
volume = -20
|
||||
|
||||
# Format strings
|
||||
format_nowplaying_song = SONG: %t | %a | %l
|
||||
format_nowplaying_station = STATION: %n | %i
|
||||
format_msg_time = TIME: %s
|
||||
# No special prefix on songs, stations or info
|
||||
format_msg_nowplaying = %s
|
||||
format_msg_info = %s
|
||||
|
||||
# high-quality audio (192k mp3, for Pandora One subscribers only!)
|
||||
#audio_quality = high
|
||||
#rpc_host = internal-tuner.pandora.com
|
||||
#partner_user = pandora one
|
||||
#partner_password = TVCKIBGS9AO9TSYLNNFUML0743LH82D
|
||||
#device = D01
|
||||
#encrypt_password = 2%3WCL*JU$MP]4
|
||||
#decrypt_password = U#IO$RZPAB%VX2
|
||||
Loading…
Reference in a new issue