VIP |
Subscribe to become a VIP member of SST!
· Request More Often
· Unshared Requests
· Request Countdown Timer
· Request Ready Indicator
· Your Request History
· Access To The VIP Forum
· Add More Favorites
:: Click Here To Upgrade ::
:: Give VIP as a Gift ::
|
|
View previous topic ::
View next topic
|
Author |
Message |
tbttfox
Cadet 1
![Cadet 1 Cadet 1](images/ranks/SCUC-Dress-AC1.gif)
![](modules/Forums/images/avatars/325664992260d6d5e8.gif)
Joined: Jul 28, 2008
Member#: 22030
Posts: 4
Location: Los Angeles
![tbttfox's Favorites are Private tbttfox's Favorites are Private](/images/favorites/heart-forum-disabled.png)
|
Posted:
Thu Feb 05, 2009 1:45 pm Post subject: Ask SST.com for playlist and time remaining |
|
I'm working on a Linux "widget" (python script) to display artist/song/time in my command line while playing the stream through mplayer.
Upon looking through the source for the live365 page, I found an xml file that posted the current song with time remaining. I set up my script to query that, and everything worked great ... UNTIL!
This file has now been whacked out for the past two days. It only displays that this station is playing the ID/PSA, and I miss being able to see the current song/time at a keystroke.
My question is:
Is there a way to ask SST directly for the current song and time remaining on the current song? Perhaps an xml file like live365? |
|
![](themes/default/forums/images/spacer.gif) |
Nate
Captain
![Captain Captain](images/ranks/W-R-0000.gif)
![](modules/Forums/images/avatars/313845a72551e2edc.jpg)
Joined: Dec 12, 2004
Member#: 8729
Posts: 1425
Location: Here and NOT There
![View Nate's Favorites View Nate's Favorites](/images/favorites/heart-forum.png)
|
|
![](themes/default/forums/images/spacer.gif) |
tbttfox
Cadet 1
![Cadet 1 Cadet 1](images/ranks/SCUC-Dress-AC1.gif)
![](modules/Forums/images/avatars/325664992260d6d5e8.gif)
Joined: Jul 28, 2008
Member#: 22030
Posts: 4
Location: Los Angeles
![tbttfox's Favorites are Private tbttfox's Favorites are Private](/images/favorites/heart-forum-disabled.png)
|
Posted:
Thu Feb 05, 2009 2:07 pm Post subject: |
|
That is, in fact, EXACTLY what I was looking for.
Now to figure out how to use SOAP and the .wsdl |
|
![](themes/default/forums/images/spacer.gif) |
j2brown ![VIP (subscribed member) VIP (subscribed member)](images/vip.gif)
Commodore
![Commodore Commodore](images/ranks/W-R-A0.gif)
![](modules/Forums/images/avatars/121074d3acf57da168.jpg)
Joined: Feb 22, 2002
Member#: 9
Posts: 3188
Location: Sterling, VA
![View j2brown's Favorites View j2brown's Favorites](/images/favorites/heart-forum.png)
|
Posted:
Thu Feb 05, 2009 3:02 pm Post subject: |
|
Linux widget? I'd be very interested in playing with that. Let me know when you've got something you're willing to share. I'm OK with alpa release stuff, I won't think less of you if it doesn't work perfectly. Hit me up via PM/IM if you don't want to post here.
jeff
sdg |
|
![](themes/default/forums/images/spacer.gif) |
tbttfox
Cadet 1
![Cadet 1 Cadet 1](images/ranks/SCUC-Dress-AC1.gif)
![](modules/Forums/images/avatars/325664992260d6d5e8.gif)
Joined: Jul 28, 2008
Member#: 22030
Posts: 4
Location: Los Angeles
![tbttfox's Favorites are Private tbttfox's Favorites are Private](/images/favorites/heart-forum-disabled.png)
|
Posted:
Tue Feb 10, 2009 7:42 pm Post subject: |
|
I just finished doing a major overhaul, and now all the functionality that I use is set in one large class.
Now it's not actually a real widget, but some of this could prove useful.
Some background info:
I'm using OpenSUSE Linux with KDE.
The program that's getting updated tabs is called Yakuake.
It's a terminal emulator that drops down from the top of the screen (much like in the game Quake)
I'm updating the tabs using DCOP (which I think is KDE only)
And I think that the only module you'd have to download is SOAPpy from HERE
[EDIT]: Removed code so there's not 40 versions of it clogging up the forum.
Last edited by tbttfox on Thu Feb 12, 2009 7:10 pm; edited 1 time in total |
|
![](themes/default/forums/images/spacer.gif) |
Alchemist ![VIP (subscribed member) VIP (subscribed member)](images/vip.gif)
Vice Admiral (Moderator)
![Vice Admiral (Moderator) Vice Admiral (Moderator)](images/ranks/W-R-A000.gif)
![](http://animannecy.free.fr/misc/cebeavatar.gif)
Joined: Dec 30, 2003
Member#: 4272
Posts: 1621
Location: Annecy
![View Alchemist's Favorites View Alchemist's Favorites](/images/favorites/heart-forum.png)
|
Posted:
Wed Feb 11, 2009 1:47 am Post subject: |
|
Thanks a lot for sharing this, tbttfox! ![Cool](modules/Forums/images/smiles/icon_cool.gif) _________________ "I've seen things you people wouldn't believe" - Blade Runner |
|
![](themes/default/forums/images/spacer.gif) |
Dutchbat
Captain
![Captain Captain](images/ranks/W-R-0000.gif)
![](modules/Forums/images/avatars/319934b20e1dc40657.jpg)
Joined: Aug 09, 2008
Member#: 22196
Posts: 1875
Location: Roosendaal
![View Dutchbat's Favorites View Dutchbat's Favorites](/images/favorites/heart-forum.png)
|
Posted:
Wed Feb 11, 2009 3:59 am Post subject: |
|
Well I'm glad I don't have any knowledge in this area at all. But I like the way people can be into it real bad. As long as it for the benefit of SST-use I will give my sympathy but make sure that it should be available for nitwits like me under max. 1 keyclick. ![Wink](modules/Forums/images/smiles/icon_wink.gif) _________________
take a look at my collection: My album list |
|
![](themes/default/forums/images/spacer.gif) |
tbttfox
Cadet 1
![Cadet 1 Cadet 1](images/ranks/SCUC-Dress-AC1.gif)
![](modules/Forums/images/avatars/325664992260d6d5e8.gif)
Joined: Jul 28, 2008
Member#: 22030
Posts: 4
Location: Los Angeles
![tbttfox's Favorites are Private tbttfox's Favorites are Private](/images/favorites/heart-forum-disabled.png)
|
Posted:
Wed Feb 11, 2009 1:04 pm Post subject: |
|
Dutchbat wrote: |
... but make sure that it should be available for nitwits like me under max. 1 keyclick. ![Wink](modules/Forums/images/smiles/icon_wink.gif) |
If you don't know how to use it, you're going to have to wait till somebody else makes an easy to use version. I'm sure not going to make a pretty GUI for it. Sorry.
It's not written for anybody else but me, though I wrote it like I did so that it would be easily portable and extensible if anybody else with programming experience wanted to make something out of it, but that's just good practice.
Also, this is nowhere near completed. There's still a lot of stuff I want to add.
[EDIT 2] A link!!
http://www.mediafire.com/?sharekey=db4225d8d1ee491d24a64199ac7f73e5e04e75f6e8ebb871
[EDIT] Here's a new version of the code with a "mute" feature. The other day, there was a ... rather annoying song. Rather than guess when the song ended, I figured I could just shut the music off for a single song and turn it back on when it was done.
Code: |
#!/usr/bin/python
import threading,os,time,commands,re,urllib
from SOAPpy import WSDL
from math import ceil
class sstQue:
"""
This is a Class for reading and parsing information from StreamingSoundtracks.com
Included Methods:
updateQue => reads the queue directly from sst.com. This function specifically doesn't use the API so it can query the entire queue.
queStep => removes the first song off the que. Useful so you don't have to continually check sst.com. Call after a current song update.
quePrint => displays & returns the Nth item in the queue. It will automatically update the que if not all entries are present (from queStep)
updateCurrentSong => updates the current song information.
printCurrentSong => displays and returns the current song information
decTime => decrement the currentSong's time remaining
unescape => internal function to remove HTML escape sequences
addTimes => internal function to sum two times in min:sec format. Used to calculate time until for quePrint
timeStruct => internal function to parse the sst API's timecodes
Included data:
que => the upcoming songs. Stored in this 2d array format: que[number][number,time,album,song,requestedBy,message]
remSec => the seconds remaining in the current song
remMin => the minutes remaining in the current song
curSongLength => the length of the current song
curSongRemain => the time remaining in the current song
curSong => the Title of the current song
curAlbum => the Album of the current song
curArtist => the Artist of the current song
listenCount => the number of current listeners
curRequestedBy => the member who requested the current song
coverLink => link to the album art
siteLink => link to sst.com album
"""
def __init__(self):
self.que = []
self.server = WSDL.Proxy('http://www.streamingsoundtracks.com/soap/FM24seven.wsdl')
self.curSong = ''
def updateQue(self):
url = 'http://www.streamingsoundtracks.com/modules/Queue_Played/Queue_Played.php'
f = urllib.urlopen(url)
s = f.read()
f.close()
#get everything in first <table> tag, and remove all special characters
partsplit = s[s.find("<table"):s.find("</table")].replace("\r\n","").replace("\t","")
partsplit = partsplit.split("<tr>")
self.que = []
for part in partsplit:
#split at tags
testing = re.split(r'<[a-zA-Z\/][^>]*>',part)
info = [self.unescape(a).strip() for a in testing if a != '']
self.que.append(info)
self.que = self.que[3:]
checkCur = self.unescape(self.curSong)
first = self.que[0][3]
if checkCur == first:
self.que = self.que[1:]
def queStep(self):
if len(self.que) > 1:
self.que = self.que[1:]
elif len(self.que) == 1:
self.que = []
def quePrint(self,n):
length = len(self.que)
if n > length:
self.updateQue()
length = len(self.que)
if n > length:
print "Index out of Range"
return
#add all time values together
if n > 1:
times = [time[1] for time in self.que[:n-1]]
timeTill = reduce(lambda x,y:self.addTimes(x,y),times)
timeSplit = timeTill.split(":")
if int(timeSplit[0])>= 60:
min = int(timeSplit[0]) % 60
hour = (int(timeSplit[0]) - min) / 60
timeTill = str(hour) + ":" + str(min).rjust(2,"0") + ":" + timeSplit[1]
else:
timeTill = "Next"
song = self.que[n-1]
#[number,time,album,song,requestedBy,message]
print "\nQueue: " + str(n) + "\nTime Till: " + timeTill + "\nAlbum: " + song[2] + "\nSong: " + song[3] + "\nRequested By:" + song[4] + "\nMessage: " + song[5] + "\n"
return (str(n), timeTill, song[2], song[3], song[4], song[5])
def updateCurrentSong(self):
tempCurSong = self.server.GetCurrentlyPlaying(False)
tempCurTitle = self.unescape(tempCurSong['Track'])
if tempCurTitle == self.curSong:
return -1
songStart = self.timeStruct(tempCurSong['PlayStart'])
serverTime = self.timeStruct(tempCurSong['SystemTime'])
songLength = ceil(tempCurSong['Length'] / 1000)
rawTime = songLength - (time.mktime(serverTime) - time.mktime(songStart))
self.remSec = int(rawTime % 60)
self.remMin = int((rawTime - self.remSec) / 60)
self.curSongLength = songLength
self.curSongRemain = str(self.remMin) + ":" + str(self.remSec).rjust(2,"0")
self.curSong = tempCurTitle
self.curAlbum = self.unescape(tempCurSong['Album'])
self.curArtist = self.unescape(tempCurSong['Artist'])
self.listenCount = tempCurSong['ListenerCount']
self.curRequestedBy = tempCurSong['RequestedBy']
self.coverLink = tempCurSong['CoverLink']
self.siteLink = tempCurSong['SiteLink']
return 0
def printCurrentSong(self):
print "\nAlbum: " + self.curAlbum + "\nArtist: " + self.curArtist + "\nSong: " + self.curSong + "\n"
return (self.curAlbum, self.curArtist, self.curSong, self.curRequestedBy)
def decTime(self):
self.remSec = self.remSec - 1
if self.remSec < 0:
self.remMin = self.remMin - 1
self.remSec = 59
def unescape(self,s):
s = s.replace("<", "<")
s = s.replace(">", ">")
s = s.replace(""", "\\\"")
s = s.replace(" ", " ")
s = s.replace("ñ", "n")
s = s.replace("&", "&")
return s
def addTimes(self,a,b):
a = a.split(":")
b = b.split(":")
c = [int(a[0]) + int(b[0]),int(a[1]) + int(b[1])]
if c[1] >= 60:
c[1] = c[1] - 60
c[0] = c[0] + 1
sec = str(c[1])
return str(c[0]) + ":" + sec.rjust(2,"0")
def timeStruct(self,a):
b = str(a[0]) + ' ' + str(a[1]) + ' ' + str(a[2]) + ' ' + str(a[3]) + ' ' + str(a[4]) + ' ' + str(int(a[5]))
return time.strptime(b,'%Y %m %d %H %M %S')
#This function updates the tab name within Yakuake to include album, artist, and timeRemaining.
def yakuakeUpdate():
cmd = gdcopi + "slotRenameSession " + str(gSes) + " \""
songAlbum = gQue.curSong + "--" + gQue.curAlbum + " "
songAlbum = songAlbum[:60]
cmd = cmd + songAlbum + "--" + str(gQue.remMin) + ":" + str(gQue.remSec).rjust(2,"0") + "\""
os.system(cmd)
#This is a thread that starts my command line media player
class playSST(threading.Thread):
def run(self):
os.system('mplayer -msglevel all=-1 -quiet http://PATH/TO/YOUR/STREAM.ogg > /dev/null')
#This is a thread that takes care of telling the sstQue class to update correctly
class updateTab(threading.Thread):
def run(self):
self.dirtySong = True
self.mute = True
dirtyTime = True
while True:
if self.dirtySong:
print "================================="
self.dirtySong = False
if gQue.updateCurrentSong() == -1 and self.mute == False:
#if there was no update, wait 1 second and retry
self.dirtySong = True
time.sleep(1)
continue
gQue.printCurrentSong()
gQue.queStep()
if self.mute == True:
self.mute = False
psst = playSST()
psst.setDaemon(True)
psst.start()
if dirtyTime:
dirtyTime = False
myTime = time.localtime()
gQue.decTime()
yakuakeUpdate()
if gQue.remMin <=0 and gQue.remSec <=0:
self.dirtySong = True
#use internal clock to do time calculations
timecheck = time.localtime()
if timecheck != myTime:
dirtyTime = True
#fifth second tick for checking
time.sleep(0.2)
def main():
#find the Yakuake tab where I'll print the updated information
sessionList = commands.getoutput(gdcopi + "sessionIdList").split(",")
for session in sessionList:
name = commands.getoutput(gdcopi + "slotSessionName " + session)
if name == 'mplayer':
global gSes
gSes = int(session)
#start the threads. Daemon threads exit when the main program exits
ut = updateTab()
ut.setDaemon(True)
ut.start()
#check for user input
while True:
input = raw_input("Command? \n")
if input == 'q':
break
elif input == 'r':
ut.dirtySong = True
elif input == 'm':
os.system('killall mplayer')
ut.mute = True
elif input == 'f':
os.system('killall mplayer')
ut.mute = True
ut.dirtySong = True
elif len(input) > 0:
if input[0] == 'n':
if len(input) == 1:
gQue.quePrint(1)
else:
number = input[1:]
if number.isdigit():
gQue.quePrint(int(number))
#once everything ends kill mplayer and remove the info from the Yakuake tab.
os.system("killall mplayer")
cmd = gdcopi + "slotRenameSession " + str(gSes) + " \"mplayer\""
os.system(cmd)
#set global variables
gSes = -1
gdcopi = "dcop yakuake DCOPInterface "
gQue = sstQue()
main()
|
|
|
![](themes/default/forums/images/spacer.gif) |
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|
|
|
|
|
|