###########################################################
## winamp.py
## Python Winamp Controller
##
## Version 1.0, 1-Feb-2001
##
## About:
##  Class to control running instance
##  or Winamp mp3 player on current
##  machine.
##
## Requirements:
##  Winamp and Win32 (of course).
##  ActivePython or Win32 Python extensions.
##  Tested with Winamp 2.71 and ActivePython 2.0
##  on WinNT4.
##
## Usage:
##  Copy this file anywhere in your
##  pythonpath.
##  Create an instance of winamp class
##  and call methods on it to control
##  a running winamp program on current
##  machine.
##
##  Example:
##    >>> import winamp
##    >>> w = winamp.winamp()
##    >>> w.getPlayingStatus()
##    'stopped'
##    >>> w.play()
##    >>> w.getPlayingStatus()
##    'playing'
##    >>>
##
## Uses the winamp api http://www.winamp.com
## /nsdn/winamp2x/dev/sdk/api.jhtml
## and windows messaging to control winamp.
##
## 
## Copyright (c) 2001, Shalabh Chaturvedi
##
## Permission is hereby granted, free of charge, to any
## person obtaining a copy of this software and associated
## documentation files (the "Software"), to deal in the
## Software without restriction, including without 
## limitation the rights to use, copy, modify, merge, 
## publish, distribute, sublicense, and/or sell copies of 
## the Software, and to permit persons to whom the Software 
## is furnished to do so, subject to the following 
## conditions:
##
## The above copyright notice and this permission notice 
## shall be included in all copies or substantial portions 
## of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
## KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
## THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
## PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
## DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
## CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
## IN THE SOFTWARE.
##
###########################################################

import win32gui
import win32api

# wonder why win32 imports dont define these
WM_COMMAND = 0x0111
WM_USER    = 0x400

def voidfunc():
    pass

class winamp:

    winamp_commands = { 'prev'    :40044,
                        'next'    :40048,
                        'play'    :40045,
                        'pause'   :40046,
                        'stop'    :40047,
                        'fadeout' :40157,
                        'forward' :40148,
                        'rewind'  :40144,
                        'raisevol':40058,
                        'lowervol':40059}

    def __init__(self):
        self.hWinamp = win32gui.FindWindow('Winamp v1.x', None)

        iVersionNumber = self.usercommand(0)
        sVersionString = hex(iVersionNumber)
        sVersionString = sVersionString[2:3] + '.' + sVersionString[3:]
        self.sVersion = sVersionString

    def command(self, sCommand):
        if winamp.winamp_commands.has_key(sCommand):
            return win32api.SendMessage(self.hWinamp, WM_COMMAND, winamp.winamp_commands[sCommand], 0)
        else:
            raise 'NoSuchWinampCommand'

    def __getattr__(self, attr):
        self.command(attr)
        return voidfunc

    def usercommand(self, id, data=0):
        return win32api.SendMessage(self.hWinamp, WM_USER, data, id)
        
    def getVersion(self):
        "returns the version number of winamp"
        return self.sVersion

    def getPlayingStatus(self):
        "returns the current status string which is one of 'playing', 'paused' or 'stopped'"
        iStatus = self.usercommand(104)
        if iStatus == 1:
            return 'playing'
        elif iStatus == 3:
            return 'paused'
        else:
            return 'stopped'
            
    def getTrackStatus(self):
        "returns a tuple (total_length, current_position) where both are in msecs"
        iTotalLength = self.usercommand(105, 1) * 1000 # the usercommand returns the number in seconds
        iCurrentPos  = self.usercommand(105, 0)
        return (iTotalLength, iCurrentPos)

    def setCurrentTrack(self, iTrackNumber):
        "changes the track selection to the number specified"        
        return self.usercommand(121, iTrackNumber)

    def getCurrentTrack(self):
        return self.usercommand(125)

    def getCurrentTrackName(self):
        return win32gui.GetWindowText(self.hWinamp)

    def seekWithinTrack(self, iPositionMsecs):
        "seeks within currently playing track to specified milliseconds since start"
        return self.usercommand(106, iPositionMsecs)
        
    def setVolume(self, iVolumeLevel):
        "sets the volume to number specified (range is 0 to 255)"
        return self.usercommand(122, iVolumeLevel)

    def getNumTracks(self):
        "returns number of tracks in current playlist"
        return self.usercommand(124)

    def getTrackInfo(self):
        "returns a tuple (samplerate, bitrate, number of channels)"
        iSampleRate = self.usercommand(126,0)
        iBitRate = self.usercommand(126,1)
        iNumChannels = self.usercommand(126,2)
        return (iSampleRate, iBitrate, iNumChannels)

    def dumpList(self):
        "dumps the current playlist into WINAMPDIR/winamp.m3u"
        return self.usercommand(120)


def getTrackList(sPlaylistFilepath):
    playlistfile = open(sPlaylistFilepath, "r")
    lines = playlistfile.readlines()
    playlistfile.close()
    playlist = []
    for line in lines:
        if not line[0]=='#':
            playlist.append(line[:-1])
    return playlist

