Jump to content

Grooveshark


Zimmer

Recommended Posts

  • Replies 199
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Posted Images

mplayer had much more stable playback and there was a lot of hacks to get wx Media Player working, so with the revised playback organization with the backend code, it was a LOT easier to use mplayer. Notice though it still does not support scrobbling :(.

Link to comment
Share on other sites

Hi all GrooveShark gurus.

I've written a small java api to grooveshark and I'm noticed that when using the "getSearch..." method I get crappy song ids back. If I use tinysong to give me the song id I can download the song perfectly. I noticed that groovewalrus (tnx btw for an super program) uses tinyosng. Is tinysong to be perfered?

Link to comment
Share on other sites

http://tinysong.com/s/bob+dylan (for example) which is what goovewalrus uses. This gives you a page of format:

http://tinysong.com/gGgN; 8637707; Blowing In The Wind; 138; Bob Dylan; 209948; Bob Dylan; http://tinysong.com/ktXq; 304051; House Of The Risin' Sun; 138; Bob Dylan; 209948; Bob Dylan; http://tinysong.com/gC8F; 2780646; Jokerman; 138; Bob Dylan; 209948; Bob Dylan; http://tinysong.com/ktXd; 10437640; Everyone Must Get Stoned; 138; Bob Dylan; 209948; Bob Dylan; http://tinysong.com/6HR3; 8014340; Fixin' to Die; 138; Bob Dylan; 209948; Bob Dylan; http://tinysong.com/7gLe; 22130287; Like a Rolling Stone (live); 138; Bob Dylan; 209948; Bob Dylan; http://tinysong.com/6HRg; 8601216; House of the Rising Sun; 138; Bob Dylan; 209948; Bob Dylan; http://tinysong.com/dOIA; 185832; Blowin In The Wind; 138; Bob Dylan; 187269; Bob Dylan's Greatest Hits; http://tinysong.com/6HRa; 7605302; Song to Woody; 138; Bob Dylan; 209948; Bob Dylan;http://tinysong.com/ktX8; 303990; In My Time Of Dyin'; 138; Bob Dylan; 209948; Bob Dylan;

Now you can search direct to grooveshark by sending a message with method "getSearchResults". This works gives you a page there are zillions of more options (like rank etc) per song. However if I use the songIDs from that search I get songs which is gibbrish, if i use the songID from teh tinysong search I get the correct song.

Link to comment
Share on other sites

im having the same problem as mrs_sheep

im using htmlunit for the communication, but when i send my json request, like:

{"method":"getCommunicationToken","header":{"session":"6ee9e3d3a6a885306c59d22736a7c406","clientRevision":"20100412.02","client":"gslite","uuid":"72CE6638-6F0F-4A0F-B9AF-36B63299022F"},"parameters":{"secretKey":"531619cee4e544839638fef531ae3f36"}}

i just get

{"header":{"session":"8e28ca85830e02580f1ca231daded8f0","alerts":[{"AlertID":"2","Text":"woot","Type":"1","Target":"1","TSExpires":null},{"AlertID":"3","Text":"woot","Type":"1","Target":"1","TSExpires":null}]},"result":"4bfbabf92eff1"}

does anyone have an idea what this could be or how to fix it?

i even sniffed the json string from firefox and used it in my IDE while debugging (of course firefox was open at this time and not 10 seconds past until i send the IDE request), to see if this may helps, but it doesnt

so i think there's something else going on

edit: ignore the different session, my error - they are now equal (request+response), but still the same error

edit #2: @Zimmer could you help me a little bit? i just downloaded your tool and i see that there's something going on in the log with that json result. Or could you offer me the current source? :)

my mistake... didnt notice that sha thing...

Edited by kaputtmacher
Link to comment
Share on other sites

FYI... I use Grooveshark's search and not tinysong simply because it returns more results (200 vs 32max), however, it seems that tingsong somehow filters out songs that don't work on Grooveshark's main site... for example, if you search "linkin park" on Grooveshark's website and try playing the first two entries for the song "In the end" they will not work... tinysong, though, will not even return these songs as valid SongIDs... y this is the case tho I do not know...

Edited by TornadoChaser
Link to comment
Share on other sites

I just check the json. If it's empty then I don't add it to the song keys or servers and so it is essentially skipped . I am thinking of adding some checking when I return the search results or something like that.

Link to comment
Share on other sites

New Release of Sharky

Download here for all systems (note for mac replace mplayer.exe with mplayer.app and for linux replace mplayer.exe with whatever mplayer binary you use (and name it mplayer, no extenstion (cause unlike windows or mac I don't know the executable extension (plus they probably vary))

http://www.mediafire.com/download.php?ti3njknyuwy

How do I get this working with Linux? I have wxPython installed, but I can't figure out which file I am supposed to run. Also, you can't name the mplayer binary as "mplayer" as it conflicts with the mplayer directory.

I tried Sharky.exe in wine as well, and it launched, but it won't let me check any boxes (and it fails with an error when I try to "Play Selected").

Thanks for the app in any case, I hope we get can this working on Linux :)

Edited by pking55
Link to comment
Share on other sites

Oops thought I had both linux (and macosx) and windows versions in there, I will upload the new version.

Also can you paste the grooveshark.log (in the app folder) here

Edited by Zimmer
Link to comment
Share on other sites

I'm completely ignorant on a lot of this stuff but I have a lot of admiration for this project and I thought I'd try to help. That said please bear with me as I'm not knowledgeable about Python at all.

For the New version I simply downloaded it and the previous sharky.exe. I then moved the files from "Sharky Version 6.4.2010.1.7z" into the older ~10MB folder and overwrote the files. I think this is how you would update but I'm not positive at all.

Anyway: These were my experiences:

-I would search for a song and get a list of results

-I couldn't download the songs however

-When I selected one song to play it did indeed play correctly (black mplayer window in the background and a "player" window saying "loading audio" with a bar indicating progress.

-When I selected two songs to play it only played one and then stopped.

Just a quick suggestion:

I'm not sure if it is possible but ideally the player window would be able to be moved behind sharky itself so in the future we could be playing something and continue adding things to the queue.

If I can help in any other way by testing builds or whatever please tell me! I'd love to help.

Thanks for your work.

Link to comment
Share on other sites

I ran Sharky on Fedora 13 after running:

su -c "yum install p7zip python-simplejson python-httplib2 wxPython python-twisted PyYAML python-BeautifulSoup"
7za x Sharky\ Version\ 6.4.2010.1.7z
cd Sharky\ Version\ 6.4.2010.1
python Twisted_Grooveshark_Gui.py

I use VLC instead of mplayer so I decided to see if i could download the song instead. The download failed though. I attached grooveshark.log in this post: http://pastebay.com/102337

Link to comment
Share on other sites

It seems your using an older version of twisted

Update.

If you were having issue replace your Twisted_Grooveshark_GUI.py file with this (this WILL NOT work with Sharky.exe)

Please note this may not FIX the issue, if so please re post the log. Thank You and sorry for the inconvenience

#!/usr/bin/python

#python imports
import sys
import os
import urllib

#Twisted Stuff
import twisted
from twisted.internet import wxreactor
wxreactor.install()
from twisted.internet import reactor
from twisted.python import log

#wx python libaries
import wx
from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin
from SimpleDialog import SimpleDialog

# app libaries
from Settings import Settings
from Player import Player, DownloadManager, URLObject
from twisted_Grooveshark import Grooveshark, EmptyJSONList
from twisted_update import update, CurrentVersion, NoUpdate

LEGAL = '''\
This application could be considered illegal for a number of reasons, please contact a lawyer for further information.
We (the authors) are not responsible for any legal (or any other) trouble that results from the use of this application.
'''


VERSION = '2010.6.4.1'

class StandardError(Exception):
    '''Standard Error for anything that doesn't fit for another error, or that error would be extremely specific.'''

class SettingsError(Exception):
    ''' An Error for Settings'''

class StartGroovesharkError(Exception):
    '''Error Starting Grooveshark'''

#Begin WX CODE
# Defined subclass for list types in popular and search tabs
class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
    'This class is for the check box list in both the popular and search tabs'
    def __init__(self, parent, size, pos):
        wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT, size = size, pos = pos)
        CheckListCtrlMixin.__init__(self)
        ListCtrlAutoWidthMixin.__init__(self)

# About Me Panel
class AboutMe(wx.Panel):
    def __init__(self, parent, size, pos):
        log.msg('Setting up about page')
        log.msg('__init__ of wx.Panel')
        wx.Panel.__init__(self, parent, -1, size = size, pos = pos)
        # Grooveshark Image
        log.msg('Creating image')
        image = wx.Image('grooveshark_about.png', wx.BITMAP_TYPE_ANY)
        height = image.GetHeight()
        width = image.GetWidth()
        image = image.Scale(height/7.0, width/7.0)
        height = image.GetHeight()
        width = image.GetWidth()
        log.msg('wx.StaticBitmap - Grooveshark Icon')
        wx.StaticBitmap(self, -1, image.ConvertToBitmap(), pos = (250 - (width/2.0),100 - (height/2.0)))
        wx.StaticText(self, -1, '     Author: Zimmer', pos = (200, 175))
        wx.StaticText(self, -1, '   App Name: Sharky', pos = (200, 190))
#Searh Panel
class Search(wx.Panel):
    def __init__(self, parent, size, pos):
        log.msg('Accessing Grooveshark and Settings')
        self.settings = parent.s
        self.g = parent.g
        log.msg('__init__ of wx.Panel')
        wx.Panel.__init__(self, parent, -1, size = size, pos = pos)
        #Search Bar
        log.msg('Setting up Search Bar and Search Button')
        self.search_bar = wx.TextCtrl(self, -1, size = (400, 20), pos = (20,10), style = wx.TE_PROCESS_ENTER)
        self.search_bar.SetValue('Search')
        #Search Button
        self.search_button = wx.Button(self, -1, size = (60,20), pos = (425, 10), label = 'Search')
        #Search Result Listings
        log.msg('Creating CheckListCtrl')
        self.search_results = CheckListCtrl(self, size =(465,160), pos = (20,50))
        self.search_results.InsertColumn(0, ' ', width = 20)
        self.search_results.InsertColumn(1, 'Song Name', width = 170)
        self.search_results.InsertColumn(2, 'Album Name', width = 170)
        self.search_results.InsertColumn(3, 'Artist', width = 100)
        #Play and Download Buttons
        log.msg('Creating Play and Download Button')
        self.play = wx.Button(self, -1, "Play Selected", size = (100,20), pos = (275, 215))
        self.download = wx.Button(self, -1, "Download Selected", size = (100,20), pos = (385, 215))
        #info text
        log.msg('Creating info text and search progress gauge')
        self.info_text = wx.StaticText(self, -1, 'Please Input a Search Above', pos = (20, 35))
        #progress bar
        self.prog_bar = wx.Gauge(self, -1, 1, (220, 30), (100, 15))
        self.prog_bar.Hide()
        self.timer = wx.Timer(self)
        # Bind Events
        log.msg('binding search tab events')
        self.Bind(wx.EVT_TIMER, self.on_timer)
        self.Bind(wx.EVT_TEXT_ENTER, self.on_search, self.search_bar)
        self.Bind(wx.EVT_BUTTON, self.on_search, self.search_button)
        self.Bind(wx.EVT_BUTTON, self.on_play, self.play)
        self.Bind(wx.EVT_BUTTON, self.on_download, self.download)
        self.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_list_item_focus)


    def on_list_item_focus(self, event):
        print 'on_focus called'
        print event.GetLabel()
        print event.GetPoint()
        print event.GetIndex()
        
    def start_grooveshark(self):
        grooveshark_dialog = Start_Grooveshark(self.GetParent())
        r = grooveshark_dialog.ShowModal()
        if r == wx.ID_CLOSE:
            # ask to retry
            r = self.grooveshark_retry()
            if r == wx.ID_YES:
                self.start_grooveshark()
            else:
                self.GetParent().ChangeSelection(0)
        else:
            self.settings.grooveshark_started = True
                
    def grooveshark_retry(self):
        log.msg('Asking User if they want to try and get all the Grooveshark Data again.')
        g_dlg = SimpleDialog(self, 'Could not start Grooveshark\nTry Again?\n\n Note: Grooveshark cannot be used if you click no  \nuntil you click retry in the about tab.', 'Retry?', wx.YES_NO | wx.ICON_QUESTION)
        result = g_dlg.ShowModal()
        if result == wx.ID_YES:
            log.msg('User Clicked Yes')
            return wx.ID_YES
        elif result == wx.ID_NO:
            log.msg('User Clicked No')
            return wx.ID_NO
        else:
            log.msg('Listen We Have Problems, when asking the user whether or not to retry getting grooveshark data, the user neither pressed YES OR NO')        

# HELPER METHOD
    def start_progress_bar(self):
        self.timer.Start(50)
        self.prog_bar.Show()

    def stop_progress_bar(self):
        self.timer.Stop()
        self.prog_bar.Hide()

    def error(self, error):
        self.info_text.SetLabel('Error: %s' % error)

    def set_info_text(self, information):
        self.info_text.SetLabel(information)

    def search_error(self, error):
        self.error('Could not complete search. Check log for details.')
        self.stop_progress_bar()
        log.msg('******Search Error******')
        log.err(error)
        log.msg('=================')
        log.msg('\n')

    def play_error(self, error):
        self.set_info_text('There was an error during playback or while preparing for playback. Check log for details.')
        log.msg('******Playback Error******')
        log.err(error)
        log.msg('=================\n')

    def download_error(self, error):
        self.set_info_text('There was an error downloading.')
        log.msg('******Playback Error******')
        log.err(error)
        log.msg('=================\n')
# /HELPER METHODS
#Events
    def on_timer(self, event):
        self.prog_bar.Pulse()

    def on_search(self, event):
        #Start Progress Bar
        self.start_progress_bar()
        #Notify the user
        self.set_info_text('Searching...')
        #
        log.msg('Search String: %s' % self.search_bar.GetValue())
        #Callbacks
        search = self.search_bar.GetValue().lower()
        d = self.g.search(search)
        d.addCallback(self.display_search)
        d.addErrback(self.search_error)
    def on_play(self, event):
        log.msg('User Clicked Play Button.')
        if self.settings.mplayer == 'download':
            dlg = SimpleDialog(None, 'Please download MPlayer and put it in either the application folder, or set where MPlayer in the Options Tab', 'MPlayer Error', style = wx.OK)
            result = dlg.ShowModal()
            print 'Result (AFTER) %s' % result
        else:
            log.msg('Getting Checked Songs')
            # get checked songs
            try:
                song_names, ids = self.get_checked_songs()
            except StandardError:
                log.err()
                dlg = SimpleDialog(None, 'Error: Unable to start playback due to an unknow error, please try again.\n\nSorry for the inconvience', 'Playback Error', style = wx.OK)
                dlg.ShowModal()
            else:#if there was success
                log.msg('Got checked songs: %s' % len(song_names))
                d = self.g.get_song_urls(ids)# passes stream data
                d.addCallback(self.stream_handler, song_names)
                d.addErrback(self.play_error)
    def on_download(self, event):
        log.msg('User Clicked Download Button.')
        log.msg('Getting Checked Songs')
        #get checked songs
        try:
            song_names, ids = self.get_checked_songs()
        except StandardError:
            # Stops it so it doesn't error saying that None is unpackable, but we have already dealt with the error so we don't need to do anything here either.
            pass
        else:#if there was success
            log.msg('Got checked songs: %s' % len(song_names))
            d = self.g.get_song_urls(ids)# passes stream data
            d.addCallback(self.download_handler, song_names)
            d.addErrback(self.download_error)
    def stream_handler(self, _data, song_names):
        # _data is a tuple of the urls and data, check we have atleast one url
        if len(_data[0]) < 1:
            dlg = SimpleDialog(None, 'Error contacting grooveshark.com, can not continue.', 'Playback Error', style = wx.OK)
            dlg.ShowModal()
        else:
            print 'Preceding'
            print _data
            keys, urls = _data
            # Test whether if all of the values in urls are skips
            if all( ['SKIP' == url for url in urls] ):
                # if we need to skip them all then 
                dlg = SimpleDialog(None, 'Invalid Search Entry. Grooveshark sometimes returns a song that no longer exists.', 'Playback Error', style = wx.OK)
                dlg.ShowModal()
            else:
                # files, urls
                files = []
                for file_name in song_names:
                    files.append(os.path.join(self.settings.music_folder, file_name + '.mp3'))
                p = Player(self)
                dm = DownloadManager()
                for url, file, data in zip(urls, files, keys):
                    p.load_url(url = 'http://' + url + '/stream.php', filename = file, method = 'POST', postdata = 'streamKey=%s' % data.encode('ascii'), headers = {'content-type': 'application/x-www-form-urlencoded'})
                for urlobject in p.playback_queue:
                    dm.add_urlobject(urlobject)
                    self.GetParent().GetParent().downloads.add_url(urlobject)
                dm.start_downloads()
                wx.CallLater(10000, p.Show)
    def download_handler(self, _data, song_names):
        # _data is a tuple of the urls and data, check we have atleast one url
        if len(_data[0]) < 1:
            dlg = SimpleDialog(None, 'Error contacting grooveshark.com, can not continue.', 'Playback Error', style = wx.OK)
            dlg.ShowModal()
        else:            
            keys, urls = _data
            if all( ['SKIP' == url for url in urls] ):
                # if we need to skip them all then 
                dlg = SimpleDialog(None, 'Invalid Search Entry. Grooveshark sometimes returns a song that no longer exists.', 'Download Error', style = wx.OK)
                dlg.ShowModal()
            else:
                files = []
                for file_name in song_names:
                    files.append(os.path.join(self.settings.music_folder, file_name + '.mp3'))
                dm = DownloadManager()
                for url, file, data in zip(urls, files, keys):
                    urlobject = URLObject('http://' + url + '/stream.php', file, 'POST', postdata = 'streamKey=%s' % data.encode('ascii'), headers = {'content-type': 'application/x-www-form-urlencoded'})
                    dm.add_urlobject(urlobject)
                    self.GetParent().GetParent().downloads.add_url(urlobject)
                dm.start_downloads()
        
# /events
# /processing methods (used by event methods)
    def display_search(self, search_results):
        log.msg('Displaying Search Results')
        log.msg('Deleting any old results.')
        self.search_results.DeleteAllItems()#Deletes any items that where there prevouisly
        log.msg('Deleted old results.')
        self.song_ids = []
        self.song_names = []
        log.msg('Enumerating through results.')
        print type(search_results)
        print len(search_results)
        for n,i in enumerate(search_results):
            index = self.search_results.InsertStringItem(n+1, str(n+1)+'.')
            try:
                self.search_results.SetStringItem(index, 1, i['Name'])
            except UnicodeEncodeError:
                self.search_results.SetStringItem(index, 1, repr(i['Name'])[2:-1])
            self.search_results.SetStringItem(index, 2, i['AlbumName']) 
            try:
                self.search_results.SetStringItem(index, 3, i['ArtistName']) 
            except TypeError:
                self.search_results.SetStringItem(index, 1, '')
            self.song_ids.append(i['SongID'])
            self.song_names.append(i['Name'])
        log.msg('Done Displaying Results.')
        self.timer.Stop()
        self.prog_bar.Hide()
        log.msg('Stopping Progress Bar.')
        self.set_info_text('Done.')
        log.msg('Done with search results.')

    def get_checked_songs(self):
        item_count = self.search_results.GetItemCount()
        checked_song_ids = []
        checked_song_names = []
        log.msg('Item Count (Number of Songs): %s' % item_count)
        for i in xrange(item_count):
            if self.search_results.IsChecked(i):
                checked_song_ids.append(self.song_ids[i])
                checked_song_names.append(self.song_names[i])
        #Check that the item amounts are equal
        if not len(checked_song_ids) == len(checked_song_names):
            #We got problems
            log.msg('******Error******')
            log.msg('The number of ids and the number of song names does not equal each other.')
            log.msg('Name(s): %s' % len(checked_songs_names))
            log.msg('Id(s):   %s' % len(checked_songs_ids))
            log.msg('=================')
            log.msg('\n')
            self.error('An unknown error occured.')
            raise StandardError('An unknown error occured')
        if len(checked_song_ids) < 1 and len(checked_song_names) < 1:
            log.msg('******Error******')
            log.msg('No Songs checked selected.')
            log.msg('=================')
            log.msg('\n')
            self.error('No items checked.')
            raise StandardError('No items checked')
        else:
            return checked_song_names, checked_song_ids
        
class Main(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent = parent, id = id, title = title, size = (500,300))
        log.startLogging(sys.stdout)
        self.s = Settings()
        log.startLogging(open(self.s.log_file, 'wb'))
        log.msg('Started Logging')
        log.msg('Using Twisted Version: %s' % twisted.version)
        log.msg('Starting Grooveshark and Started Settings.')
        self.g = Grooveshark() # start up grooveshark
        #Create notebook
        log.msg('Setting up Notebook')
        self.notebook = wx.Notebook(self)
        self.notebook.g = self.g
        #Sets Settings to also notebook for parent referance
        self.notebook.s = self.s
        #Tabs
        log.msg('Adding Tabs (About)')
        log.msg('Creating Instances of AboutMe')
        self.about = AboutMe(self.notebook, (500,300), (0,0))
        self.search = Search(self.notebook, (500,300), (0,0))
        self.options = OptionsPanel(self.notebook, (500,300), (0,0))
        self.downloads = DownloadListCtrl(self.notebook, (500,300), (0, 0))
        log.msg('Adding it as tab to Notebook')
        self.notebook.AddPage(self.about, 'About')
        self.notebook.AddPage(self.search, 'Search')
        self.notebook.AddPage(self.options, 'Options')
        self.notebook.AddPage(self.downloads, 'Downloads')
        #App Cleanup
        self.Bind(wx.EVT_CLOSE, self.stop_reactor)
        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.tab_change)
        #Show Dialog
        #self.run_twisted()
        log.msg('Starting Twisted')
        # if reactor.running:
            # log.msg('Twisted is running.')
            # self.s.twisted_running = True
        # else:
            # log.msg('Twisted is not running')
            # self.s.twisted_running = False
            # dlg = SimpleDialog(None, 'Error: Network backend not running. This is not your fault, please try restarting this application and try again. \nSorry For the Inconvience.', 'Error', wx.OK | wx.ICON_ERROR)
            # dlg.ShowModal()
        if not self.s.eula:
            dlg = SimpleDialog(None, LEGAL, 'Legal: Eula Agreement.', style = wx.YES_NO)
            if dlg.ShowModal() == wx.ID_YES:
                log.msg('User agreed to the eula.')
                self.s.eula = True
            else:
                log.msg('User did not agree to the eula.')
                self.Destroy()
        # only do this if the eula has been agreed to
        if self.s.eula:
            # check for updates
            d = update(VERSION)
            d.addCallback(self.new_version)
            d.addErrback(self.current_version)
        
    def new_version(self, version):
        # Got a new version
        log.msg('Found New New Version: %s' % str(version))
        dlg = SimpleDialog(None, 'New Version!\nVersion: %s' % version, 'New Version', style = wx.OK)
        dlg.ShowModal()
        
        
    def current_version(self, error):
        try:
            error.raiseException()
        except CurrentVersion:
            log.msg('Got Current Version')
        except NoUpdate:
            log.msg('Got Newer Version Huh')
        except:
            log.msg('Uknown Error; Unable to update')
            log.err()

    def tab_change(self, event):
        log.msg('Tab Changed')
        log.msg('Tab Changed to: %s' % self.notebook.GetCurrentPage())
        # start Grooveshark
        if type(self.notebook.GetCurrentPage()) == Search:# if the class is an instance of Search
            log.msg('Switched to Search Tab')
            if self.s.grooveshark_started:
                log.msg('Grooveshark is started')
            else:
                log.msg('Grooveshark is not started. Starting.')
                self.notebook.GetCurrentPage().start_grooveshark()

    def stop_reactor(self, event):
        log.msg('Stopping Reactor')
        #Stop Reactor
        reactor.stop()
        log.msg('Destroying Window')
        #Destroy Windows
        self.Destroy()
        log.msg('Quiting')
        log.msg('\n\n')#Add Two lines so it is easy to distinguish between two app instances
        #Quit
        sys.exit()
#Twisted Support
    def run_twisted(self):  
        reactor.startRunning(installSignalHandlers=0)
        timerid = wx.NewId()
        self.timer = wx.Timer(self, timerid)
        wx.EVT_TIMER(self, timerid, self.OnTimer)
        self.timer.Start(10, False)
    def OnTimer(self, event):
        reactor.runUntilCurrent()
        reactor.doIteration(0)
#End Twisted Support
class Start_Grooveshark(wx.Dialog):#Starts Grooveshark and gets the basics like the session, uuid, and token
    def __init__(self, parent):
        print type(parent)
        wx.Dialog.__init__(self, parent = parent, id = -1, title = 'Starting Grooveshark', style = wx.SYSTEM_MENU)
        self.s = parent.s
        self.info_text = wx.StaticText(self, -1, 'Getting Groooveshark Data.', pos = (5,10))
        self.info_text.Wrap(385)
        if not reactor.running:
            log.msg('\n\n ERROR ERROR ERROR \n TWISTED IS !NOT! RUNNING \ ERROR ERROR ERROR \n\n ')
            dial = SimpleDialog(None, 'Error: Network backend not running. This is not your fault, please try restarting this application and try again. \nSorry For the Inconvience.', 'Error', wx.OK | wx.ICON_ERROR)
            dial.ShowModal()
        else:
            self.g = parent.g
            d=self.session()
            d.addCallback(self.session_complete)
            d.addErrback(self.error)
    def session(self):
        log.msg('Getting Grooveshark Session.')
        d = self.g.session_and_country()
        return d
    def update_info(self, text):
        log.msg('Updating Grooveshark Info: %s' % repr(text))
        self.info_text.SetLabel(text)
        self.info_text.Wrap(385)
    def error(self, error):
        log.msg('******Error******')
        log.err(error)
        log.msg('****End Error****')
        self.update_info('Error: %s' % error.getErrorMessage())
        self.SetReturnCode(wx.ID_CLOSE)
        self.count = 5
        wx.CallLater(1000, self.countdown)
    def countdown(self):
        original_text = self.info_text.GetLabel().replace('\n\n\tClosing in (%s)' % (self.count + 1), '')
        self.update_info(original_text + '\n\n\tClosing in (%s)' % self.count)
        self.count = self.count -1
        if self.count >= 0:
            wx.CallLater(1000, self.countdown)
        else:
            self.Destroy()
    def session_complete(self, vars):
        log.msg('Session: %s' % vars['sessionID'])
        log.msg('Country ID: %s' % urllib.unquote(vars['country']))
        # get token
        d = self.g.get_token()
        d.addCallback(self.token_complete)
        d.addErrback(self.error)

    def token_complete(self, token):
        log.msg('token_complete')
        self.update_info('Got Token. Done.')
        wx.CallLater(100, self.Destroy)

    def grooveshark_retry(self):
        log.msg('Asking User if they want to try and get all the Grooveshark Data again.')
        g_dlg = SimpleDialog(self, 'Could not start Grooveshark\nTry Again?\n\n Note: Grooveshark cannot be used if you click no  \nuntil you click retry in the about tab.', 'Retry?', wx.YES_NO | wx.ICON_QUESTION)
        result = g_dlg.ShowModal()
        if result == wx.ID_YES:
            log.msg('User Clicked Yes')
            return wx.ID_YES
        else:
            log.msg('User Clicked No')
            return wx.ID_NO
        
class DownloadListCtrl(wx.Panel):
    def __init__(self, parent, size, pos):
        wx.Panel.__init__(self, parent, -1, size = size, pos = pos)
        print 'ListCtrl Size: %s' % str(size)
        self.list=wx.ListCtrl(self, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER, pos = (0, 0), size = (size[0] - 18, size[1] - 63))
        self.list.Show(True)

        self.list.InsertColumn(0, "URL")
        self.list.InsertColumn(1, "Path")
        self.list.InsertColumn(2, "Percent Downloaded")
        self.list.InsertColumn(3, "State")
        self.downloads = []

    def add_url(self, urlobject):
        download_item = DownloadItem(urlobject)
        # insert don't append so we can use the index as the index for the list ctrl also
        self.downloads.append(download_item)
        print 'GETITEMCOUNT %s' % self.list.GetItemCount()
        position = self.list.InsertStringItem(self.list.GetItemCount(), urlobject.url)
        self.list.SetStringItem(position, 1, urlobject.path)
        self.list.SetStringItem(position, 2, '0%')
        if urlobject.started:
            self.list.SetStringItem(position, 3, 'Downloading')
        else:
            self.list.SetStringItem(position, 3, 'Waiting')
        download_item.add_size_callback(self.update_percent)
        
        
    def update_state(self, state, download_item):
        position = self.downloads.index(download_item)
        self.list.SetStringItem(position, 3, state)

    def update_percent(self, percent, download_item):
        position = self.downloads.index(download_item)
        self.list.SetStringItem(position, 2,  '%.1f%%' % percent )
        if percent == 100:
            self.list.SetStringItem(position, 3, 'Done')
    
class DownloadItem(object):
    def __init__(self, urlobject):
        self.urlobject = urlobject
        self.url = urlobject.url
        self.path = urlobject.path
        self.started = urlobject.started
        self.size_callbacks = []
        self.percent = None
        urlobject.add_size_callback(self.data_received)
    
    def data_received(self, data_length):
        print 'Received Data'
        for callback in self.size_callbacks:
            if self.urlobject.total_amount is not None and not self.urlobject.total_amount == 0:
                self.percent = (float(data_length) / float(self.urlobject.total_amount)) * 100 
            callback(self.percent, self)
    
    def add_size_callback(self, callback):
        assert callable(callback)
        # update the callback
        if self.percent is not None:
            callback(self.percent)
        self.size_callbacks.append(callback)

        
class OptionsPanel(wx.Panel):
    def __init__(self, parent, size, pos):
        wx.Panel.__init__(self, parent, -1, size = size, pos = pos)
        self.s = self.GetParent().s
        
        #Save Path
        self.change_path_text = wx.StaticText(self, -1, 'Change Save Path:', pos = (20,3))
        self.display_path = wx.TextCtrl(self, -1, self.s.music_folder, pos = (110,21), size = (300, -1))
        self.save_button  = wx.Button(self, -1, 'Change', pos = (20,20))
        
        #Mplayer
        self.change_mplayer_text = wx.StaticText(self, -1, 'Change MPlayer Path:', pos = (20,45))
        self.display_mplayer_path = wx.TextCtrl(self, -1, self.s.mplayer, pos = (110,66), size = (300, -1))
        self.mplayer_button  = wx.Button(self, -1, 'Change', pos = (20,65))

        # Download Percent
        self.download_percent_text = wx.StaticText(self, -1, 'Change Playback Buffer (%):', pos = (20, 90))
        self.download_percent_display = wx.TextCtrl(self, -1, '%s' % int( self.s.download_percent * 100 ), pos = (150, 110), size = (25, -1))
        self.download_percent_set_button = wx.Button(self, -1, 'Set Playback Buffer', pos = (20, 110))
        #Binds
        self.Bind(wx.EVT_BUTTON, self.change_save_path, self.save_button)
        self.Bind(wx.EVT_BUTTON, self.change_mplayer_path, self.mplayer_button)
        self.Bind(wx.EVT_BUTTON, self.set_playback_buffer, self.download_percent_set_button)
        # self.Bind(wx.EVT_BUTTON, self.change_buffer, self.change_buffer)
    def change_save_path(self, event):
        self.save_dlg = wx.DirDialog(self, 'Select save folder.', 'C:/', name = 'save_dialog')
        result = self.save_dlg.ShowModal()
        if result == wx.ID_OK:
            print 'Changed Path; OK'
            self.s.music_folder = self.save_dlg.GetPath().replace('\\', '/')+'/'
            self.display_path.SetValue(self.s.music_folder)
        if result == wx.ID_CANCEL:
            pass #User did not select a path, or they select the path and then hit cancel
    def change_mplayer_path(self, event):
        self.mplayer_dlg = wx.FileDialog(self, 'Select MPlayer executable.', 'C:/')
        result = self.mplayer_dlg.ShowModal()
        if result == wx.ID_OK:
            print 'Changed MPlayer; OK'
            input_path = self.mplayer_dlg.GetDirectory().replace('\\', '/') + '/' + self.mplayer_dlg.GetFilename()
            if os.path.exists(input_path):
                self.s.mplayer = input_path
                self.display_mplayer_path.SetValue(self.s.mplayer)
            else:
                print 'Path does not exist'
        
    def set_playback_buffer(self, event):
        self.s.download_percent = int( self.download_percent_display.GetValue() ) / 100.0
        print 'Buffer: %i' % self.download_percent_display.GetValue()

if __name__ == '__main__':
    app = wx.App(redirect = False)
    app_window = Main(parent = None, id = -1, title = 'Sharky')
    app_window.Show()
    app.SetTopWindow(app_window)
    reactor.registerWxApp(app)
    reactor.run()

Edited by Zimmer
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...