Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.
Status
Not open for further replies.
OK. but how do I get it to work with GeekTool? I mainly use the shell never a script!

So the first link I gave you wasn't good, it isn't a 5 day forecast.

Here is the actual 5 day script, save as fivedayforecastv3.py in the directory of your choosing.
Code:
#!/usr/bin/env python

""" FIVEDAYFORCAST
 ROBERT WOLTERMAN (xtacocorex) - 2011

 GRABS THE 5 DAY WEATHER FORECAST FROM YAHOO WEATHER FOR PRINTING IN GEEKTOOL
 AWESOMENESS FLOWS FROM HERE, THERE ARE NO FILES DOWNLOADED FROM THE INTERNET
 THE ONLY FILE NEEDED IS A ZIPCODE TO WOEID MAPPING TO KEEP THE YAHOO QUERIES
 TO A MINIMUM (1000 HITS/HOUR LIMIT)
 
 *** MAKE SURE TO KEEP THE REFRESH RATE IN GEEKTOOL/NERDTOOL TO A SLOWER VALUE
 
 THANKS TO brenm666 AND dotcommer ON THE MACRUMORS FORUMS FOR BETA TESTING THIS
"""

# CHANGELOG
# 07 JUNE 2011
#  - ADDED OPTION TO SPECIFY A URL TO PARSE IF LOCATION GRABBING ISN'T VALID
#    FOR A USERS AREA
#  _ FIXED ISSUE WITH urllib2 NOT WORKING PROPERLY OUTSIDE OF THE USA, MADE
#    THE CODE USE urllib INSTEAD
#  - FIXED ISSUE WHERE ZIP CODES HAVE SPACES, THIS WOULD CAUSE NON-USA LOCATIONS 
#    TO FAIL IN THE YAHOO QUERY
#  - RE-WROTE REGULAR EXPRESSIONS TO PARSE THE HTML
# 04 JUNE 2011
#  - ADDED SUPPORT TO AUTOMAGICALLY GRAB THE ZIP CODE AND WOEID AND GENERATE THE
#    THE PROPER URL FOR YAHOO WEATHER
#  - RE-FORMATTED THE COMMAND LINE ARGUMENTS
#  - ADDED SUPPORT TO TURN ON/OFF UNDERLINING THE DAY HEADER
# 30 MAY 2011
#  - ADDED 5 DAY HIGH/LOW CODE
# 29 MAY 2011
#  - INITIAL WRITE

# MODULE IMPORTS
import urllib, os, re, sys, string, ast, optparse

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#  ***                 ONLY MODIFY THIS SECTION                 ***
# MODIFY THIS WITH YOUR WEATHER URL
UNITS   = "C"

# FILE FOR WHERE THE WOEID TO ZIPCODE MAP GOES
# CURRENTLY SET TO BE A HIDDEN FOLDER IN THE USERS HOME DIRECTORY
# YOU CAN CUSTOMIZE THIS IF YOU WANT THE FILE SOMEPLACE ELSE
FCASTWOEIDDATA = os.getenv('HOME') + os.path.sep + ".zip_woeid_map.txt"

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

# DEBUG FLAG
DEBUG    = False
UNITTEST = False
URLTYPE = "5DAY"
YQLBASEURL = "http://query.yahooapis.com/v1/public/yql"
IPLOCURL   = "http://ipinfodb.com/my_ip_location.php"

# CONSTANTS
COMMA = "%2C"
SPACE = "%20"
EQUAL = "%3D"

def myencode(instr):
    """
        myencode
         - FUNCTION TO ENCODE THE YAHOO QUERY TEXT PROPERLY FOR THE URL
         - INPUT:  instr - QUERY STRING TO ENCODE
         - OUPUTS: rstr  - ENCODED QUERY STRING
    """
    rstr = ""
    for i in xrange(len(instr)):
        if   instr[i] == " ":
            rstr += SPACE
        elif instr[i] == "=":
            rstr += EQUAL
        else:
            rstr += instr[i]
    
    return rstr

def getLocationData():
    """
        getWOEID
         - FUNCTION TO GET THE WOEID ID FROM THE LOCALLY STORED DATABASE
          OR
           PULLS THE DATA FROM THE INTERNET AND STORES INTO THE DATABASE
         - INPUT:  NONE
         - OUPUTS: locdict - DICTIONARY OF LOCATION DATA
    """
    # SET UP OUR DICTIONARY
    locdict = { 'zipcode' : "", 
                'country' : "",
                'stprov'  : "", 
                'city'    : "",
                'lat'     : "",
                'lon'     : ""}
    
    # GET THE ZIP CODE BASED UPON OUR EXTERNAL IP ADDRESS
    if not UNITTEST:
        url = urllib.urlopen(IPLOCURL)
        ippagedata = url.read()
        url.close()
    
    if UNITTEST and DEBUG:
        # DEBUG
        print "USING LOCAL FILE"
        loco = open("./myloc.txt")
        ippagedata = loco.read()
        loco.close()
    
    # REGULAR EXPRESSION TO FIND THE NEEDED DATA IN THE WEBPAGE
    # WOULD BE BETTER TO USE SGML TO PARSE THE HTML BUT I DON'T
    # WANT TO FIGURE IT OUT
    
    # GET THE COUNTRY
    mat = re.search('<li>Country : .*<img',ippagedata)
    locdict['country'] = mat.group(0).split(': ')[1].split('<img')[0].rstrip().lower()
    
    # GET THE STATE/PROVINCE
    mat = re.search('<li>State/Province : .*</li>',ippagedata)
    locdict['stprov'] = mat.group(0).split(': ')[1].split('</li>')[0].lower()
    
    # GET THE CITY
    mat = re.search('<li>City : .*</li>',ippagedata)
    locdict['city'] = mat.group(0).split(': ')[1].split('</li>')[0].lower()
    
    # GET THE ZIP CODE
    mat = re.search('<li>Zip or postal code : .*</li>',ippagedata)
    locdict['zipcode'] = mat.group(0).split(': ')[1].split('</li>')[0]

    # GET THE LATITUDE
    mat = re.search('<li>Latitude : .*</li>',ippagedata)
    locdict['lat'] = mat.group(0).split(': ')[1].split('</li>')[0]

    # GET THE LONGITUDE
    mat = re.search('<li>Longitude : .*</li>',ippagedata)
    locdict['lon'] = mat.group(0).split(': ')[1].split('</li>')[0]

    # RETURN THE LOCATION DICTIONARY
    return locdict

def getWOEID(zipcode):
    """
        getWOEID
         - FUNCTION TO GET THE WOEID ID FROM THE LOCALLY STORED DATABASE
          OR
           PULLS THE DATA FROM THE INTERNET AND STORES INTO THE DATABASE
         - INPUT:  zipcode - ZIPCODE FROM LOCATION DATA OR USER INPUT
         - OUPUTS: woeid   - THE WOEID WE WANT BASED ON OUR ZIPCODE
    """
    
    # CHECK TO SEE IF THE ZIP IS IN THE FILE
    haveWOEID = False
    infile    = False
    if os.path.isfile(FCASTWOEIDDATA):
        fin = open(FCASTWOEIDDATA,'r+a')
        infile = True
    else:
        # WE HIT THE CASE WHERE THE FILE DOESN'T EXIST
        fin = open(FCASTWOEIDDATA,'w')
        infile = False
        
    # IF WE HAVE THE INPUT FILE, LOOK FOR OUR ZIPCODE
    if infile:
        for line in fin.readlines():
            if zipcode in line:
                haveWOEID = True
                # GET THE WOEID AND RIGHT STRIP TO REMOVE THE RETURN LINE FROM THE FILE
                woeid     = line.split(",")[1].rstrip()
                # NOT RETURNING HERE SO WE CAN GRACEFULLY CLOSE THE INPUT FILE
                # THIS IS A STUPID LITTLE ISSUE
            else:
                haveWOEID = False

    # IF WE DON'T HAVE THE WOEID, LET'S GET THE SHIZZLE AND STORE LOCALLY    
    if not haveWOEID:
    
        # GET THE URL TO FIND WOEID
        yqlquery  = 'select woeid from geo.places where text=\"' + zipcode + '\" limit 1'
        yqlformat = "json"
        WOEIDURL = YQLBASEURL + "?q=" + myencode(yqlquery) + "&format=" + yqlformat
        
        # GET THE DATA FROM THE INTERNETS
        reqresp = urllib.urlopen(WOEIDURL)
        
        # NEED TO BREAK THE STRING INTO THE APPROPRIATE DICTIONARY STRUCTURE
        resp    = ast.literal_eval(reqresp.read())
        reqresp.close()
        
        # SEARCH THE RESPONSE FOR THE WOEID
        # JSON IS AWESOME! YAY FOR NESTED DICTIONARIES
        woeid = resp['query']['results']['place']['woeid']
        
        # WRITE THE DATA TO THE FILE
        fmt = "%s,%s\n" % (zipcode, woeid)
        fin.write(fmt)
    
    # NOW WE CAN CLOSE THE FILE
    fin.close()
    
    # RETURN THE WOEID WE FOUND
    return woeid

def makeUrl(utype,locdict,woeid,units):
    """
        makeUrl
         - FUNCTION TO CREATE THE URL FOR EITHER THE YAHOO WEATHER RSS
           OR THE 5-DAY FORECAST
         - INPUT:  utype   - TYPE OF URL: RSS OR 5DAY
                   locdict - ZIPCODE FROM LOCATION DATA OR USER INPUT
                   woeid   - THE WOEID WE WANT BASED ON OUR ZIPCODE
                   units   - UNITS OF MEASURE
         - OUPUTS: url     - THE URL FOR THE PAGE WE WANT TO PARSE
    """
    if   utype == "RSS":
        url = "http://weather.yahooapis.com/forecastrss?w="+woeid
        if units == "C":
            url += "&u=c"
    elif utype == "5DAY":
        # FORMAT THE COUNTRY PROPERLY
        tmp = locdict['country'].split(" ")
        country = ""
        for i in xrange(len(tmp)):
            country += tmp[i]
            if i < len(tmp)-1:
                country += "-"
        
        # FORMAT THE STATE/PROVINCE CORRECTLY
        tmp = locdict['stprov'].split(" ")
        stprov = ""
        for i in xrange(len(tmp)):
            stprov += tmp[i]
            if i < len(tmp)-1:
                stprov += "-"
        
        # FORMAT THE CITY PROPERLY
        tmp = locdict['city'].split(" ")
        city = ""
        for i in xrange(len(tmp)):
            city += tmp[i]
            if i < len(tmp)-1:
                city += "-"
    
        # GENERATE URL
        url = "http://weather.yahoo.com/" + country + "/" + stprov + "/" + city + "-" + woeid + "/"
        
        if units == "C":
            url += "&unit=c"
            
        if DEBUG:
            print country
            print stprov
            print city
            print url

    # RETURN THE URL
    return url

def getForecast(url,fcastopt):
    """
        getForecast()
         - GETS THE FORECAST DATA
         - INPUT:  url      - URL OF WEATHER PAGE
                   fcastopt - FORECAST TYPE
         - OUPUTS: NONE
    """

    # FUNCTION VARIABLES
    days      = []
    fcast     = []
    highs     = []
    lows      = []
    fcastdata = ""  
    
    # FOR DEPLOYMENT
    if not DEBUG:
        urld = urllib.urlopen(url)
        urldata = urld.read()
    else:
        # DEBUG
        urld = open("./lincolntest.txt")
        urldata = urld.read()
    urld.close()
    
    #print urldata
    
    if fcastopt.detailed:
    
        # GET THE DETAILED FORECAST SECTION
        mat = re.search('<div id="yw-detailedforecast">.*</div>.*<div> <!-- SpaceID=0',urldata,re.DOTALL)
        fcastdata = mat.group(0)
    
        # SPLIT THE LIST UP BY THE HTML <li> TAGS
        fcastdata = fcastdata.split('<li>')
        # REMOVE THE FIRST ITEM IN THE LIST AS IT ISN'T DATA
        fcastdata.pop(0)
        
        # LOOP THROUGH THE LIST AND BREAK UP THE LIST ITEMS
        for item in fcastdata:
            tmp = item.split('\n')
            # GET THE DAY
            days.append(tmp[0].split('<strong>')[1].split('</strong> ')[0])
            
            # GET THE FORECAST
            fcast.append(tmp[1])
            
        # PRINT OUT THE FORECAST
        for i in xrange(len(days)):
            temp = string.capwords(days[i])
            if fcastopt.underline:
                print "\033[4m" + temp + "\033[0m"
            else:
                print temp
            print " " + fcast[i] + "\n"
    
    elif fcastopt.highlow:
        # SEARCH FOR THE 5 DAY
        mat = re.search('<div id="yw-fivedayforecast">.*<td rowspan="2" class="extended"><!-- SpaceID=0 robot -->',urldata,re.DOTALL)
        fcastdata = mat.group(0).split('<tr')
        # REMOVE THE FIRST LIST ROW
        fcastdata.pop(0)
        
        # GET THE DAYS
        daysect = fcastdata[0].split('<th>')
        daysect.pop(0)
        for d in daysect:
            days.append(d.split('</th')[0])
        
        # GET THE AREA WITH THE FORECAST
        fcastsect = fcastdata[1].split('<br/>')
        fcastsect.pop(0)
        for f in fcastsect:
            if "-" in f:
                tmp2 = f.split('-\n')
                tmp3 = ""
                for charsect in tmp2:
                    tmp3 += charsect
                fcast.append(tmp3.split('</div>')[0])
            else:
                fcast.append(f.split('</div>')[0])
        
        # GET THE AREA WITH THE HIGHS/LOWS
        mat = re.search('<tr class="fiveday-temps">.*</td></tr></table></div>',urldata,re.DOTALL)
        hlsect = mat.group(0).split('<td>')
        hlsect.pop(0)
        for hl in hlsect:
            tmp = hl.split(": ")
            highs.append(int(tmp[1].split("&#")[0]))
            lows.append(int(tmp[2].split("&#")[0]))
                    
        # PRINT OUT THE FORECAST
        for i in xrange(len(days)):
            if fcastopt.underline:
                print "\033[4m%s\033[0m:\n %s\n H: %3d%s L: %3d%s\n" % (days[i],fcast[i],highs[i],UNITS,lows[i],UNITS)
            else:
                print "%s:\n %s\n H: %3d%s L: %3d%s\n" % (days[i],fcast[i],highs[i],UNITS,lows[i],UNITS)

def cmdLineOptionParser():
    """
        cmdLineOptionParser()
         - PARSES THE COMMAND LINE ARGUMENTS
         - INPUT:  NONE
         - OUPUTS: NONE
    """
    # CREATE OUR USAGE REPSONSE 
    usage = ("%prog [options]",__doc__)
    
    usage = "\n".join(usage)
    
    # CREATE OUR COMMAND LINE PARSER
    cmdparser = optparse.OptionParser(usage)
    
    # ADD OPTIONS 
    cmdparser.add_option('-d', '--detailed', action='store_true',
        help="Displays the detailed forecast",
        default=False
    )
    
    cmdparser.add_option('-l', '--highlow', action='store_true',
        help="Displays the Highs and Lows only forecast",
        default=False
    )
    
    cmdparser.add_option('-u', '--underline', action='store_true',
        help="Underlines the day headers",
        default=False
    )
    
    cmdparser.add_option('-w', '--webaddress', action='store', type='string',
        help="Used for pre-specifying the Yahoo Weather URL instead of automatically grabbing based on external IP",
        default=''
    )
    
    # RETURN THE PARSER
    return cmdparser

def forecastMain(argv):
    """
        forecastMain()
         - MAIN SCRIPT FUNCTION THAT ORGANIZES THE TASKS
         - INPUT:  args - COMMAND LINE ARGUMENTS
         - OUPUTS: NONE
    """

    # FIGURE OUT COMMAND LINE ARGUMENTS
    # FCASTTYPE OF -l IS FOR 5 DAY HIGHS/LOWS
    # FCASTTYPE OF -d IS FOR 5 DAY DETAILED
    cmdparser = cmdLineOptionParser()
    opts, args = cmdparser.parse_args(argv)
    
    # DETERMINE IF WE ARE USING A PROVIDED URL
    if opts.webaddress == '':
        # GET OUR LOCATION DICTIONARY
        locdict = getLocationData()
        
        # GET OUR WOEID
        mywoeid = getWOEID(locdict['zipcode'])
    
        # GET THE APPROPRIATE URL WE REQUIRE
        url = makeUrl(URLTYPE,locdict,mywoeid,UNITS)
    else:
        url = opts.webaddress

    # GET THE FORECAST
    getForecast(url,opts)

if __name__ == "__main__":
    forecastMain(sys.argv[1:])

Here are the command line options:
Code:
$ python fivedayforecastv3.py -h
Usage: fivedayforecastv3.py [options]
 FIVEDAYFORCAST
 ROBERT WOLTERMAN (xtacocorex) - 2011

 GRABS THE 5 DAY WEATHER FORECAST FROM YAHOO WEATHER FOR PRINTING IN GEEKTOOL
 AWESOMENESS FLOWS FROM HERE, THERE ARE NO FILES DOWNLOADED FROM THE INTERNET
 THE ONLY FILE NEEDED IS A ZIPCODE TO WOEID MAPPING TO KEEP THE YAHOO QUERIES
 TO A MINIMUM (1000 HITS/HOUR LIMIT)
 
 *** MAKE SURE TO KEEP THE REFRESH RATE IN GEEKTOOL/NERDTOOL TO A SLOWER VALUE
 
 THANKS TO brenm666 AND dotcommer ON THE MACRUMORS FORUMS FOR BETA TESTING THIS


Options:
  -h, --help            show this help message and exit
  -d, --detailed        Displays the detailed forecast
  -l, --highlow         Displays the Highs and Lows only forecast
  -u, --underline       Underlines the day headers
  -w WEBADDRESS, --webaddress=WEBADDRESS
                        Used for pre-specifying the Yahoo Weather URL instead
                        of automatically grabbing based on external IP

Since you want a detailed forecast, this is what you're going to type for the command in a shell geeklet:
Code:
python /path/to/script/fivedayforecastv3.py -d -u
 
For the current music script, you need to use a shell geeklet with the following command:
Code:
osascript /path/to/your/scripts/currentmusic.scpt

The encoding setting was my only idea for lyrics, I don't use a lyrics script.

Got it thanks!

But what about have a 2-digit seconds at all times? Like seconds 01-09 instead of 1-9?

And

When the music isn't playing, I would like the display to disappear; not stay on the screen and say "paused."

Thanks! :)
 
Last edited:
Got it thanks!

But what about have a 2-digit seconds at all times? Like seconds 01-09 instead of 1-9?

And

When the music isn't playing, I would like the display to disappear; not stay on the screen and say "paused."

Thanks! :)

Yeah, the number of digits for the seconds was an issue in the code that I found. I'll try to look into it here in a bit.

I'll also update the script for you so it doesn't print anything when the music is paused.
 
So the first link I gave you wasn't good, it isn't a 5 day forecast.

Here is the actual 5 day script, save as fivedayforecastv3.py in the directory of your choosing.
Code:
#!/usr/bin/env python

""" FIVEDAYFORCAST
 ROBERT WOLTERMAN (xtacocorex) - 2011

 GRABS THE 5 DAY WEATHER FORECAST FROM YAHOO WEATHER FOR PRINTING IN GEEKTOOL
 AWESOMENESS FLOWS FROM HERE, THERE ARE NO FILES DOWNLOADED FROM THE INTERNET
 THE ONLY FILE NEEDED IS A ZIPCODE TO WOEID MAPPING TO KEEP THE YAHOO QUERIES
 TO A MINIMUM (1000 HITS/HOUR LIMIT)
 
 *** MAKE SURE TO KEEP THE REFRESH RATE IN GEEKTOOL/NERDTOOL TO A SLOWER VALUE
 
 THANKS TO brenm666 AND dotcommer ON THE MACRUMORS FORUMS FOR BETA TESTING THIS
"""

# CHANGELOG
# 07 JUNE 2011
#  - ADDED OPTION TO SPECIFY A URL TO PARSE IF LOCATION GRABBING ISN'T VALID
#    FOR A USERS AREA
#  _ FIXED ISSUE WITH urllib2 NOT WORKING PROPERLY OUTSIDE OF THE USA, MADE
#    THE CODE USE urllib INSTEAD
#  - FIXED ISSUE WHERE ZIP CODES HAVE SPACES, THIS WOULD CAUSE NON-USA LOCATIONS 
#    TO FAIL IN THE YAHOO QUERY
#  - RE-WROTE REGULAR EXPRESSIONS TO PARSE THE HTML
# 04 JUNE 2011
#  - ADDED SUPPORT TO AUTOMAGICALLY GRAB THE ZIP CODE AND WOEID AND GENERATE THE
#    THE PROPER URL FOR YAHOO WEATHER
#  - RE-FORMATTED THE COMMAND LINE ARGUMENTS
#  - ADDED SUPPORT TO TURN ON/OFF UNDERLINING THE DAY HEADER
# 30 MAY 2011
#  - ADDED 5 DAY HIGH/LOW CODE
# 29 MAY 2011
#  - INITIAL WRITE

# MODULE IMPORTS
import urllib, os, re, sys, string, ast, optparse

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#  ***                 ONLY MODIFY THIS SECTION                 ***
# MODIFY THIS WITH YOUR WEATHER URL
UNITS   = "C"

# FILE FOR WHERE THE WOEID TO ZIPCODE MAP GOES
# CURRENTLY SET TO BE A HIDDEN FOLDER IN THE USERS HOME DIRECTORY
# YOU CAN CUSTOMIZE THIS IF YOU WANT THE FILE SOMEPLACE ELSE
FCASTWOEIDDATA = os.getenv('HOME') + os.path.sep + ".zip_woeid_map.txt"

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

# DEBUG FLAG
DEBUG    = False
UNITTEST = False
URLTYPE = "5DAY"
YQLBASEURL = "http://query.yahooapis.com/v1/public/yql"
IPLOCURL   = "http://ipinfodb.com/my_ip_location.php"

# CONSTANTS
COMMA = "%2C"
SPACE = "%20"
EQUAL = "%3D"

def myencode(instr):
    """
        myencode
         - FUNCTION TO ENCODE THE YAHOO QUERY TEXT PROPERLY FOR THE URL
         - INPUT:  instr - QUERY STRING TO ENCODE
         - OUPUTS: rstr  - ENCODED QUERY STRING
    """
    rstr = ""
    for i in xrange(len(instr)):
        if   instr[i] == " ":
            rstr += SPACE
        elif instr[i] == "=":
            rstr += EQUAL
        else:
            rstr += instr[i]
    
    return rstr

def getLocationData():
    """
        getWOEID
         - FUNCTION TO GET THE WOEID ID FROM THE LOCALLY STORED DATABASE
          OR
           PULLS THE DATA FROM THE INTERNET AND STORES INTO THE DATABASE
         - INPUT:  NONE
         - OUPUTS: locdict - DICTIONARY OF LOCATION DATA
    """
    # SET UP OUR DICTIONARY
    locdict = { 'zipcode' : "", 
                'country' : "",
                'stprov'  : "", 
                'city'    : "",
                'lat'     : "",
                'lon'     : ""}
    
    # GET THE ZIP CODE BASED UPON OUR EXTERNAL IP ADDRESS
    if not UNITTEST:
        url = urllib.urlopen(IPLOCURL)
        ippagedata = url.read()
        url.close()
    
    if UNITTEST and DEBUG:
        # DEBUG
        print "USING LOCAL FILE"
        loco = open("./myloc.txt")
        ippagedata = loco.read()
        loco.close()
    
    # REGULAR EXPRESSION TO FIND THE NEEDED DATA IN THE WEBPAGE
    # WOULD BE BETTER TO USE SGML TO PARSE THE HTML BUT I DON'T
    # WANT TO FIGURE IT OUT
    
    # GET THE COUNTRY
    mat = re.search('<li>Country : .*<img',ippagedata)
    locdict['country'] = mat.group(0).split(': ')[1].split('<img')[0].rstrip().lower()
    
    # GET THE STATE/PROVINCE
    mat = re.search('<li>State/Province : .*</li>',ippagedata)
    locdict['stprov'] = mat.group(0).split(': ')[1].split('</li>')[0].lower()
    
    # GET THE CITY
    mat = re.search('<li>City : .*</li>',ippagedata)
    locdict['city'] = mat.group(0).split(': ')[1].split('</li>')[0].lower()
    
    # GET THE ZIP CODE
    mat = re.search('<li>Zip or postal code : .*</li>',ippagedata)
    locdict['zipcode'] = mat.group(0).split(': ')[1].split('</li>')[0]

    # GET THE LATITUDE
    mat = re.search('<li>Latitude : .*</li>',ippagedata)
    locdict['lat'] = mat.group(0).split(': ')[1].split('</li>')[0]

    # GET THE LONGITUDE
    mat = re.search('<li>Longitude : .*</li>',ippagedata)
    locdict['lon'] = mat.group(0).split(': ')[1].split('</li>')[0]

    # RETURN THE LOCATION DICTIONARY
    return locdict

def getWOEID(zipcode):
    """
        getWOEID
         - FUNCTION TO GET THE WOEID ID FROM THE LOCALLY STORED DATABASE
          OR
           PULLS THE DATA FROM THE INTERNET AND STORES INTO THE DATABASE
         - INPUT:  zipcode - ZIPCODE FROM LOCATION DATA OR USER INPUT
         - OUPUTS: woeid   - THE WOEID WE WANT BASED ON OUR ZIPCODE
    """
    
    # CHECK TO SEE IF THE ZIP IS IN THE FILE
    haveWOEID = False
    infile    = False
    if os.path.isfile(FCASTWOEIDDATA):
        fin = open(FCASTWOEIDDATA,'r+a')
        infile = True
    else:
        # WE HIT THE CASE WHERE THE FILE DOESN'T EXIST
        fin = open(FCASTWOEIDDATA,'w')
        infile = False
        
    # IF WE HAVE THE INPUT FILE, LOOK FOR OUR ZIPCODE
    if infile:
        for line in fin.readlines():
            if zipcode in line:
                haveWOEID = True
                # GET THE WOEID AND RIGHT STRIP TO REMOVE THE RETURN LINE FROM THE FILE
                woeid     = line.split(",")[1].rstrip()
                # NOT RETURNING HERE SO WE CAN GRACEFULLY CLOSE THE INPUT FILE
                # THIS IS A STUPID LITTLE ISSUE
            else:
                haveWOEID = False

    # IF WE DON'T HAVE THE WOEID, LET'S GET THE SHIZZLE AND STORE LOCALLY    
    if not haveWOEID:
    
        # GET THE URL TO FIND WOEID
        yqlquery  = 'select woeid from geo.places where text=\"' + zipcode + '\" limit 1'
        yqlformat = "json"
        WOEIDURL = YQLBASEURL + "?q=" + myencode(yqlquery) + "&format=" + yqlformat
        
        # GET THE DATA FROM THE INTERNETS
        reqresp = urllib.urlopen(WOEIDURL)
        
        # NEED TO BREAK THE STRING INTO THE APPROPRIATE DICTIONARY STRUCTURE
        resp    = ast.literal_eval(reqresp.read())
        reqresp.close()
        
        # SEARCH THE RESPONSE FOR THE WOEID
        # JSON IS AWESOME! YAY FOR NESTED DICTIONARIES
        woeid = resp['query']['results']['place']['woeid']
        
        # WRITE THE DATA TO THE FILE
        fmt = "%s,%s\n" % (zipcode, woeid)
        fin.write(fmt)
    
    # NOW WE CAN CLOSE THE FILE
    fin.close()
    
    # RETURN THE WOEID WE FOUND
    return woeid

def makeUrl(utype,locdict,woeid,units):
    """
        makeUrl
         - FUNCTION TO CREATE THE URL FOR EITHER THE YAHOO WEATHER RSS
           OR THE 5-DAY FORECAST
         - INPUT:  utype   - TYPE OF URL: RSS OR 5DAY
                   locdict - ZIPCODE FROM LOCATION DATA OR USER INPUT
                   woeid   - THE WOEID WE WANT BASED ON OUR ZIPCODE
                   units   - UNITS OF MEASURE
         - OUPUTS: url     - THE URL FOR THE PAGE WE WANT TO PARSE
    """
    if   utype == "RSS":
        url = "http://weather.yahooapis.com/forecastrss?w="+woeid
        if units == "C":
            url += "&u=c"
    elif utype == "5DAY":
        # FORMAT THE COUNTRY PROPERLY
        tmp = locdict['country'].split(" ")
        country = ""
        for i in xrange(len(tmp)):
            country += tmp[i]
            if i < len(tmp)-1:
                country += "-"
        
        # FORMAT THE STATE/PROVINCE CORRECTLY
        tmp = locdict['stprov'].split(" ")
        stprov = ""
        for i in xrange(len(tmp)):
            stprov += tmp[i]
            if i < len(tmp)-1:
                stprov += "-"
        
        # FORMAT THE CITY PROPERLY
        tmp = locdict['city'].split(" ")
        city = ""
        for i in xrange(len(tmp)):
            city += tmp[i]
            if i < len(tmp)-1:
                city += "-"
    
        # GENERATE URL
        url = "http://weather.yahoo.com/" + country + "/" + stprov + "/" + city + "-" + woeid + "/"
        
        if units == "C":
            url += "&unit=c"
            
        if DEBUG:
            print country
            print stprov
            print city
            print url

    # RETURN THE URL
    return url

def getForecast(url,fcastopt):
    """
        getForecast()
         - GETS THE FORECAST DATA
         - INPUT:  url      - URL OF WEATHER PAGE
                   fcastopt - FORECAST TYPE
         - OUPUTS: NONE
    """

    # FUNCTION VARIABLES
    days      = []
    fcast     = []
    highs     = []
    lows      = []
    fcastdata = ""  
    
    # FOR DEPLOYMENT
    if not DEBUG:
        urld = urllib.urlopen(url)
        urldata = urld.read()
    else:
        # DEBUG
        urld = open("./lincolntest.txt")
        urldata = urld.read()
    urld.close()
    
    #print urldata
    
    if fcastopt.detailed:
    
        # GET THE DETAILED FORECAST SECTION
        mat = re.search('<div id="yw-detailedforecast">.*</div>.*<div> <!-- SpaceID=0',urldata,re.DOTALL)
        fcastdata = mat.group(0)
    
        # SPLIT THE LIST UP BY THE HTML <li> TAGS
        fcastdata = fcastdata.split('<li>')
        # REMOVE THE FIRST ITEM IN THE LIST AS IT ISN'T DATA
        fcastdata.pop(0)
        
        # LOOP THROUGH THE LIST AND BREAK UP THE LIST ITEMS
        for item in fcastdata:
            tmp = item.split('\n')
            # GET THE DAY
            days.append(tmp[0].split('<strong>')[1].split('</strong> ')[0])
            
            # GET THE FORECAST
            fcast.append(tmp[1])
            
        # PRINT OUT THE FORECAST
        for i in xrange(len(days)):
            temp = string.capwords(days[i])
            if fcastopt.underline:
                print "\033[4m" + temp + "\033[0m"
            else:
                print temp
            print " " + fcast[i] + "\n"
    
    elif fcastopt.highlow:
        # SEARCH FOR THE 5 DAY
        mat = re.search('<div id="yw-fivedayforecast">.*<td rowspan="2" class="extended"><!-- SpaceID=0 robot -->',urldata,re.DOTALL)
        fcastdata = mat.group(0).split('<tr')
        # REMOVE THE FIRST LIST ROW
        fcastdata.pop(0)
        
        # GET THE DAYS
        daysect = fcastdata[0].split('<th>')
        daysect.pop(0)
        for d in daysect:
            days.append(d.split('</th')[0])
        
        # GET THE AREA WITH THE FORECAST
        fcastsect = fcastdata[1].split('<br/>')
        fcastsect.pop(0)
        for f in fcastsect:
            if "-" in f:
                tmp2 = f.split('-\n')
                tmp3 = ""
                for charsect in tmp2:
                    tmp3 += charsect
                fcast.append(tmp3.split('</div>')[0])
            else:
                fcast.append(f.split('</div>')[0])
        
        # GET THE AREA WITH THE HIGHS/LOWS
        mat = re.search('<tr class="fiveday-temps">.*</td></tr></table></div>',urldata,re.DOTALL)
        hlsect = mat.group(0).split('<td>')
        hlsect.pop(0)
        for hl in hlsect:
            tmp = hl.split(": ")
            highs.append(int(tmp[1].split("&#")[0]))
            lows.append(int(tmp[2].split("&#")[0]))
                    
        # PRINT OUT THE FORECAST
        for i in xrange(len(days)):
            if fcastopt.underline:
                print "\033[4m%s\033[0m:\n %s\n H: %3d%s L: %3d%s\n" % (days[i],fcast[i],highs[i],UNITS,lows[i],UNITS)
            else:
                print "%s:\n %s\n H: %3d%s L: %3d%s\n" % (days[i],fcast[i],highs[i],UNITS,lows[i],UNITS)

def cmdLineOptionParser():
    """
        cmdLineOptionParser()
         - PARSES THE COMMAND LINE ARGUMENTS
         - INPUT:  NONE
         - OUPUTS: NONE
    """
    # CREATE OUR USAGE REPSONSE 
    usage = ("%prog [options]",__doc__)
    
    usage = "\n".join(usage)
    
    # CREATE OUR COMMAND LINE PARSER
    cmdparser = optparse.OptionParser(usage)
    
    # ADD OPTIONS 
    cmdparser.add_option('-d', '--detailed', action='store_true',
        help="Displays the detailed forecast",
        default=False
    )
    
    cmdparser.add_option('-l', '--highlow', action='store_true',
        help="Displays the Highs and Lows only forecast",
        default=False
    )
    
    cmdparser.add_option('-u', '--underline', action='store_true',
        help="Underlines the day headers",
        default=False
    )
    
    cmdparser.add_option('-w', '--webaddress', action='store', type='string',
        help="Used for pre-specifying the Yahoo Weather URL instead of automatically grabbing based on external IP",
        default=''
    )
    
    # RETURN THE PARSER
    return cmdparser

def forecastMain(argv):
    """
        forecastMain()
         - MAIN SCRIPT FUNCTION THAT ORGANIZES THE TASKS
         - INPUT:  args - COMMAND LINE ARGUMENTS
         - OUPUTS: NONE
    """

    # FIGURE OUT COMMAND LINE ARGUMENTS
    # FCASTTYPE OF -l IS FOR 5 DAY HIGHS/LOWS
    # FCASTTYPE OF -d IS FOR 5 DAY DETAILED
    cmdparser = cmdLineOptionParser()
    opts, args = cmdparser.parse_args(argv)
    
    # DETERMINE IF WE ARE USING A PROVIDED URL
    if opts.webaddress == '':
        # GET OUR LOCATION DICTIONARY
        locdict = getLocationData()
        
        # GET OUR WOEID
        mywoeid = getWOEID(locdict['zipcode'])
    
        # GET THE APPROPRIATE URL WE REQUIRE
        url = makeUrl(URLTYPE,locdict,mywoeid,UNITS)
    else:
        url = opts.webaddress

    # GET THE FORECAST
    getForecast(url,opts)

if __name__ == "__main__":
    forecastMain(sys.argv[1:])

Here are the command line options:
Code:
$ python fivedayforecastv3.py -h
Usage: fivedayforecastv3.py [options]
 FIVEDAYFORCAST
 ROBERT WOLTERMAN (xtacocorex) - 2011

 GRABS THE 5 DAY WEATHER FORECAST FROM YAHOO WEATHER FOR PRINTING IN GEEKTOOL
 AWESOMENESS FLOWS FROM HERE, THERE ARE NO FILES DOWNLOADED FROM THE INTERNET
 THE ONLY FILE NEEDED IS A ZIPCODE TO WOEID MAPPING TO KEEP THE YAHOO QUERIES
 TO A MINIMUM (1000 HITS/HOUR LIMIT)
 
 *** MAKE SURE TO KEEP THE REFRESH RATE IN GEEKTOOL/NERDTOOL TO A SLOWER VALUE
 
 THANKS TO brenm666 AND dotcommer ON THE MACRUMORS FORUMS FOR BETA TESTING THIS


Options:
  -h, --help            show this help message and exit
  -d, --detailed        Displays the detailed forecast
  -l, --highlow         Displays the Highs and Lows only forecast
  -u, --underline       Underlines the day headers
  -w WEBADDRESS, --webaddress=WEBADDRESS
                        Used for pre-specifying the Yahoo Weather URL instead
                        of automatically grabbing based on external IP

Since you want a detailed forecast, this is what you're going to type for the command in a shell geeklet:
Code:
python /path/to/script/fivedayforecastv3.py -d -u

OK did all that! What do I have to modify for it to show. Do I need to add a zip code etc? Here is the path to the fivedayforecast3.py /Users/joel/fivedayforecastv3.py -d -u

UPDATE It started working after a few minutes. Thanks.
 
Last edited:
Got it thanks!

But what about have a 2-digit seconds at all times? Like seconds 01-09 instead of 1-9?

And

When the music isn't playing, I would like the display to disappear; not stay on the screen and say "paused."

Thanks! :)

Here is the updated script, I fixed the track time information and removed the time info when listening to a web stream. Also included is the fix to not display any text when iTunes is not open or is paused/stopped.

Code:
-- DETERMINE IF ITUNES IS RUNNING AND IF IT IS NOT, RETURN NOTHING
tell application "System Events" to set iTunesIsRunning to (name of processes) contains "iTunes"
if iTunesIsRunning is false then
	return ""
end if
tell application "System Events"
	set powerCheck to ((application processes whose (name is equal to "iTunes")) count)
	if powerCheck = 0 then
		return ""
	end if
end tell
-- IF ITUNES IS RUNNING...
if iTunesIsRunning is true then
	tell application "iTunes"
		-- GET STREAM URL AND TITLE
		set theURL to the current stream URL as text
		set theStream to the current stream title as text
		
		-- CHECK THE PLAYER STATE OF ITUNES
		-- PLAYING
		if player state is playing then
			-- SET isPaused AND isStopped TO FALSE
			set isPaused to false
			set isStopped to false
			-- DETERMINE IF ARE LISTENING TO A WEB STREAM OR A LOCAL FILE
			if theURL is "missing value" then
				-- GET TRACK INFORMATION FROM THE FILE
				set sartist to artist of current track
				set strack to name of current track
				set salbum to album of current track
			else
				-- GET THE STREAM INFORMATION
				set stitle to current stream title as text
				set sname to name of current track
			end if
			-- PAUSED
		else if player state is paused then
			-- SET THE VARIABLES APPROPRIATELY
			set isPaused to true
			set isStopped to false
			-- STOPPED
		else if player state is stopped then
			-- SET THE VARIABLES APPROPRIATELY
			set isPaused to false
			set isStopped to true
			-- THERE IS NO ELSE CONDITION
		end if
		
		-- SECTION FOR TRACK TIME INFORMATION GATHERING
		-- *** MINUTES WILL NOT BE IN 2 DIGITS IF AUDIO FILE IS LONGER THAN AN HOUR... ***
		-- GET THE CURRENT PLAYER POSITION
		set when to player position
		-- GET THE MINUTE AND SECONDS
		set whenStrMin to (when div 60)
		set whenStrSec to (when mod 60)
		
		-- GET SECONDS IN TWO DIGITS
		if whenStrSec < 10 then
			set whenStrSec to "0" & whenStrSec
		end if
		
		-- SET whenStr
		set whenStr to whenStrMin & ":" & whenStrSec as text
		
		-- CREATE THE TIME INFORMATION
		set long to time of current track
		set tinfo to "[" & whenStr & " / " & long & "]" as string
		
		-- DETERMINE IF WE ARE LISTENING TO A WEB STREAM OR A LOCAL FILE
		if theURL is "missing value" then
			-- DETERMINE IF WE ARE PAUSED OR STOPPED
			if isPaused or isStopped then
				-- DON'T RETURN ANY THING, KEEP THE TEXT BLANK
				set info to ""
			else
				-- OTHERWISE SET TO THE LOCAL FILE TRACK NAME, TIME INFORMATION, ARTIST, AND ALBUM
				set info to strack & " " & tinfo & " | " & sartist & "
" & salbum as string
			end if
		else
			-- SET THE STREAM TITLE AND NAME
			set info to stitle & "
 Stream: " & sname
		end if
		
		-- RETURN THE INFORMATION
		return info
	end tell
end if

Here is proof that the time information is correct (ran in the Applescript editor):
Code:
"This Shattered Symphony [2:06 / 4:27] | Coheed and Cambria
Year of the Black Rainbow"


----------

OK did all that! What do I have to modify for it to show. Do I need to add a zip code etc? Here is the path to the fivedayforecast3.py /Users/joel/fivedayforecastv3.py -d -u

UPDATE It started working after a few minutes. Thanks.

I've noticed that if you set a longer refresh rate, the geeklet won't automatically update when it's created. My stock ticker script has this issue, it won't update right away when I bring the computer out of sleep.

Glad that the weather script is working for you. The nice thing about it is it'll update to your current location, so if you take your computer some where, it'll grab that locations weather.
 
Countdown Script

So i wanted to make a countdown until vacation and this is what i came up with.

For some reason it does not refresh, what am i doing wrong?

Code:
ENDTIME=`date -j -f '%m%d%y%H%M' "0930111430" +%s`
CURTIME=`date +%s`
TIMEDIF=`expr $ENDTIME - $CURTIME`
echo "$TIMEDIF seconds till vacation"
 
Here is the updated script, I fixed the track time information and removed the time info when listening to a web stream. Also included is the fix to not display any text when iTunes is not open or is paused/stopped.

You rock! Thank you very much! :D:D:D
 
I've noticed that if you set a longer refresh rate, the geeklet won't automatically update when it's created. My stock ticker script has this issue, it won't update right away when I bring the computer out of sleep.

Glad that the weather script is working for you. The nice thing about it is it'll update to your current location, so if you take your computer some where, it'll grab that locations weather.

Thanks for all the help, it works great. Now too prune some of my Geeklets to make room. Easy on the iMac 24 hard on the Macbook Pro 13".
 
I've tried google but it has failed me... I am no master at Geektool, but I know you can combine code and pictures and get things off of websites and all that. Now that being said I am a huge sudoku player and I was wondering if there would be any way to get a daily sudoku on my desktop using geektool or something? Thanks.
 
just thought I'd show you guys my new desktop that I made with geektool. Pretty basic stuff.
xds7ex.png
 
Last edited by a moderator:
just thought I'd show you guys my new desktop that I made with geektool. Pretty basic stuff.
 

Attachments

  • Screenshot_1.png
    Screenshot_1.png
    822.1 KB · Views: 276
just thought I'd show you guys my new desktop that I made with geektool. Pretty basic stuff.

Not too bad, one suggestion would be to get a monospaced font for the calendar.

----------

I've tried google but it has failed me... I am no master at Geektool, but I know you can combine code and pictures and get things off of websites and all that. Now that being said I am a huge sudoku player and I was wondering if there would be any way to get a daily sudoku on my desktop using geektool or something? Thanks.

You're not wanting to actually input the answers on to the image are you?

Just grabbing a sudoku puzzle and displaying it wouldn't be too difficult, you'd need two geeklets for that task though: one for the script to run and the other to display the image.
 
You're not wanting to actually input the answers on to the image are you?

Just grabbing a sudoku puzzle and displaying it wouldn't be too difficult, you'd need two geeklets for that task though: one for the script to run and the other to display the image.

Unfortunately I do wanna input the answers. I mean I realize as I have programmed things before that it would be very complicated and I don't know if geektool could handle it or not, but I wanted to see if you guys no any different.
 
New and Improved Line Calendar

So I've been on a roll the last two days with helping out/scripting for people on the forum.

I decided to revisit the line calendar and make one in Python.

NOTE: This is currently English only as I haven't messed with the Locale stuff in Python. I apologize to everyone outside of the USA; I'll be looking into that for the future.

Save the script as linecalendar.py and chmod +x the file to make it executable. Make your geeklet large enough for the calendar, set it to a monospace font, enable colorized output if you use that option.

Here are the script options:
Code:
Options:
  -h, --help            show this help message and exit
  -c, --colorize        Colorize the current day
  -d DAYCOLOR, --daycolor=DAYCOLOR
                        Color for the current day, only use with the -c option
  -o ORIENTATION, --orientation=ORIENTATION
                        Orientation of the line calendar: horizontal/vertical
  -u, --underline       Underlines the day headers

As you can tell, this will output horizontally or vertically. :)

Here are the approved colors:
Code:
 APPROVED COLORS (CAN BE INPUT IN ANY CASE IN THE CMD LINE ARGUMENT):
   BLACK       DGRAY
   RED         LRED
   GREEN       LGREEN
   BROWN       YELLOW
   BLUE        LBLUE
   MAGENTA     LMAGENTA
   CYAN        LCYAN
   GRAY        WHITE

Here is the script:
Code:
#!/usr/bin/env python

""" LINECALENDAR
 ROBERT WOLTERMAN (xtacocorex) - 2011

 CREATES A CALENDAR FOR DISPLAY IN A LINE, EITHER HORIZONTALLY OR VERTICALLY
 *** THIS IS CURRENTLY IN ENGLISH ONLY, I HAVEN'T MESSED WITH LOCALE SETTINGS IN PYTHON ***
 
 APPROVED COLORS (CAN BE INPUT IN ANY CASE IN THE CMD LINE ARGUMENT):
   BLACK       DGRAY
   RED         LRED
   GREEN       LGREEN
   BROWN       YELLOW
   BLUE        LBLUE
   MAGENTA     LMAGENTA
   CYAN        LCYAN
   GRAY        WHITE
   
 *** CERTAIN COLOR COMBINATIONS MAY NOT DISPLAY PROPERLY, UNSURE IF 
     THIS IS A CODE ISSUE OR AN ISSUE WITH ANSI COLOR COMBINATIONS
 
 *** MAKE SURE TO KEEP THE REFRESH RATE IN GEEKTOOL/NERDTOOL TO A SLOWER VALUE
"""

# LINE CALENDAR - VERSION 1
# ROBERT WOLTERMAN - 2011
# CREATES A CALENDAR FOR DISPLAY IN A LINE, EITHER HORIZONTALLY OR VERTICALLY

# CHANGELOG
# 11 SEPTEMBER 2011:
#  - INITIAL WRITE

# MODULE IMPORTS
import sys, time, datetime, optparse, re
from calendar import TextCalendar

# CONSTANTS
SPACER = " "

WEEKDAYMAP = {
    'monday'    : 0,
    'tuesday'   : 1,
    'wednesday' : 2,
    'thursday'  : 3,
    'friday'    : 4,
    'saturday'  : 5,
    'sunday'    : 6
  }

# ASCII ESCAPE SEQUENCES
RESET     = "\x1B[0m"
UNDERLINE = "\x1B[4m"
ESCAPE    = "\x1B["
FGCOLORDICT = {
 'BLACK'    : "0;30m",
 'RED'      : "0;31m",
 'GREEN'    : "0;32m",
 'BROWN'    : "0;33m",
 'BLUE'     : "0;34m",
 'MAGENTA'  : "0;35m",
 'CYAN'     : "0;36m",
 'GRAY'     : "0;37m",
 'DGRAY'    : "1;30m",
 'LRED'     : "1;31m",
 'LGREEN'   : "1;32m",
 'YELLOW'   : "1;33m",
 'LBLUE'    : "1;34m",
 'LMAGENTA' : "1;35m",
 'LCYAN  '  : "1;36m",
 'WHITE'    : "1;37m"
  }

BGCOLORDICT = {
 'BLACK'    : "0;40m",
 'RED'      : "0;41m",
 'GREEN'    : "0;42m",
 'BROWN'    : "0;43m",
 'BLUE'     : "0;44m",
 'MAGENTA'  : "0;45m",
 'CYAN'     : "0;46m",
 'GRAY'     : "0;47m",
 'DGRAY'    : "1;40m",
 'LRED'     : "1;41m",
 'LGREEN'   : "1;42m",
 'YELLOW'   : "1;43m",
 'LBLUE'    : "1;44m",
 'LMAGENTA' : "1;45m",
 'LCYAN  '  : "1;46m",
 'WHITE'    : "1;47m"
  }

# CLASS DEFINITION
class LineCalendar(TextCalendar):
    """
        CLASS: LineCalendar
        INHERITS: TextCalendar
        PURPOSE: Create a text calendar to be displayed in a line (horizontal or vertical)
    """
    def __init__(self):
        # INITIALIZE TextCalendar
        TextCalendar.__init__(self)
        
        # SET THE WIDTH AND LINE SPACING FOR CALENDAR
        self.__w = 3
        self.__l = 1
        
        # GET THE CURRENT YEAR AND MONTH
        self.__year  = int(time.strftime("%Y"))
        self.__month = int(time.strftime("%m"))
        
        # GET THE FIRST DAY OF THE MONTH'S NAME
        # SO WE CAN START THE CALENDAR PRINTING WITH THAT DAY
        tmp  = datetime.date(self.__year,self.__month,1)
        # GET THE DAY NAME AND CONVERT TO LOWERCASE TO WORK WITH WEEKDAYMAP DICTIONARY
        self.__fdom = tmp.strftime("%A").lower()
        
        # CREATE OUR CALENDAR INSTANCE, INIT WITH THE FIRST WEEK DAY
        # FOR THE FIRST DAY OF THE MONTH
        self.__cal = TextCalendar(WEEKDAYMAP[self.__fdom])

        # SET THE TEXT VARIABLES FOR THE DAY NAME AND THE DAY NUMBER ROWS
        self.__daynamerow = ""
        self.__daynumrow  = ""

    def create(self,opts):
        """
             create()
             - CREATES THE CALENDAR STRINGS
             - INPUT:  opts - COMMAND LINE OPTIONS
             - OUPUTS: NONE
        """
        # GET THE OUTPUT INTO A VARIABLE SO WE CAN BREAK
        # THE SHIZZLE UP WITH .split
        tmp = self.__cal.formatmonth(self.__year,self.__month,self.__w,self.__l)
        
        # RIGHT STRIP THE STRING TO REMOVE THE LAST RETURN LINE
        tmp = tmp.rstrip('\n')
        
        # BREAK THE TEMPORARY STRING UP INTO A LIST
        callist = tmp.split('\n')
        
        # GET LIST LENGTHS OF IMPORTANCE
        lencallist = len(callist)
        numdayrows = lencallist - 2
        
        # SET OUR DAY NAME VARIABLE
        daynames = callist[1]
        
        # SET __daynamerow AND __daynumrow
        # LOOP THROUGH THE LENGTH OF THE LIST STARTING AT THE 
        # SECOND ITEM WHICH IS THE FIRST SET OF DAY NUMBERS
        for i in xrange(2,lencallist):
            self.__daynamerow += daynames + SPACER
            self.__daynumrow  += callist[i] + SPACER

        # GET LENGTH OF __daynumrow
        lendaynumrow = len(self.__daynumrow)
        lendaynamerow = len(self.__daynamerow)

        # ADJUST LENGTH OF __daynamerow TO MATCH __daynumrow
        self.__daynamerow = self.__daynamerow[0:lendaynumrow]

        # RIGHT STRIP BOTH STRINGS FOR SAFE MEASURE
        self.__daynamerow = self.__daynamerow.rstrip()
        self.__daynumrow = self.__daynumrow.rstrip()

        # BASED ON COMMAND LINE ARGUMENTS, COLOR THE CURRENT DAY IF NEEDED
        # THIS STEP IS HERE BECAUSE WE NEED BOTH STRINGS THE SAME LENGTH
        # PRIOR TO MODIFYING WITH THE COLOR ESCAPE SEQUENCES
        if opts.colorize:
            # GET THE CURRENT DATE
            day = time.strftime("%d")
            
            # GET THE COLOR
            COLOR = FGCOLORDICT[opts.daycolor.upper()]

            # GET THE MATCH OBJECT FOR FINDING THE CURRENT DAY
            # IN THE __daynumrow STRING
            m = re.search(day,self.__daynumrow)
            
            # BREAK UP THE __daynumrow STRING AROUND THE CURRENT DAY
            tmp1 = self.__daynumrow[0:m.start()]
            tmp2 = self.__daynumrow[m.end():]
            
            # SET THE __daynumrow VARIABLE WITH THE COLOR ADDED
            self.__daynumrow = tmp1 + ESCAPE + COLOR + str(day) + RESET + tmp2
        
        # BASED ON COMMAND LINE ARGUMENTS, UNDERLINE ALL THE DAY NAMES
        if opts.underline:
            tmp = self.__daynamerow.split()
            mstr = ""
            for i in xrange(len(tmp)):
                mstr += UNDERLINE + tmp[i] + RESET + SPACER
            self.__daynamerow = mstr.rstrip()

    def prmonth(self,opts):
        """
             prmonth()
             - MONTH PRINT FUNCTION
             - INPUT:  opts - COMMAND LINE OPTIONS
             - OUPUTS: NONE
        """
        
        # CHECK TO SEE IF THE __daynamerow OR __daynumrow STRINGS ARE EMPTY
        # ONLY NEEDED IF PERSON WRITING CODE DOES NOT CALL THE create() 
        # PRIOR TO CALLING THE prmonth()
        if self.__daynamerow == "" or self.__daynumrow == "":
            # CREATE THE STRINGS SO WE CAN PRINT THEM
            self.create(opts)
        
        # CHECK TO SEE HOW THE USER WANTS THE CALENDAR PRINTED
        if opts.orientation.lower() == 'horizontal':
            print self.__daynamerow
            print self.__daynumrow
        elif opts.orientation.lower() == 'vertical':
            # BREAK THE STRINGS UP BY SPACES
            names = self.__daynamerow.split()
            days  = self.__daynumrow.split()

            # LOOP THROUGH THE LENGTH OF THE LIST AND PRINT OUT
            for i in xrange(len(names)):
                print "%3s %2s" % (names[i],days[i])

# FUNCTION DEFINITIONS
def cmdLineOptionParser():
    """
        cmdLineOptionParser()
         - PARSES THE COMMAND LINE ARGUMENTS
         - INPUT:  NONE
         - OUPUTS: NONE
    """
    # CREATE OUR USAGE REPSONSE 
    usage = ("%prog [options]",__doc__)
    
    usage = "\n".join(usage)
    
    # CREATE OUR COMMAND LINE PARSER
    cmdparser = optparse.OptionParser(usage)
    
    # ADD OPTIONS 
    cmdparser.add_option('-c', '--colorize', action='store_true',
        help="Colorize the current day",
        default=False
    )
    
    cmdparser.add_option('-d', '--daycolor', action='store', type='string',
        help="Color for the current day, only use with the -c option",
        default='yellow'
    )
    
    cmdparser.add_option('-o', '--orientation', action='store', type='string',
        help="Orientation of the line calendar: horizontal/vertical",
        default='horizontal'
    )
    
    cmdparser.add_option('-u', '--underline', action='store_true',
        help="Underlines the day headers",
        default=False
    )
        
    # RETURN THE PARSER
    return cmdparser

def MyMain(argv):
    """
        MyMain()
         - MAIN FUNCTION
         - INPUT:  args - COMMAND LINE ARGUMENTS
         - OUPUTS: NONE
    """
    
    # FIGURE OUT COMMAND LINE ARGUMENTS
    cmdparser = cmdLineOptionParser()
    opts, args = cmdparser.parse_args(argv)

    # CREATE OUR CALENDAR OBJECT
    tcal = LineCalendar()
    tcal.create(opts)
    tcal.prmonth(opts)

# MAIN
if __name__ == '__main__':
    # CALL OUR MAIN FUNCTION
    MyMain(sys.argv[1:])

Here are some samples:
Code:
python /path/to/script/linecalendar.py -o horizontal -u -c blue
Code:
python /path/to/script/linecalendar.py -o vertical -c magenta

Attached are two screenshots showing examples.
 

Attachments

  • Screen shot 2011-09-11 at 22.36.40 .png
    Screen shot 2011-09-11 at 22.36.40 .png
    48.1 KB · Views: 150
  • Screen shot 2011-09-11 at 22.37.02 .png
    Screen shot 2011-09-11 at 22.37.02 .png
    74.4 KB · Views: 158
Unfortunately I do wanna input the answers. I mean I realize as I have programmed things before that it would be very complicated and I don't know if geektool could handle it or not, but I wanted to see if you guys no any different.

Sad to say that this is impossible until the developers for Geektool/Nerdtool add the capability (which I believe would be very hard to do).

I think your only solution for the time being is something for Dashboard.
 
Sad to say that this is impossible until the developers for Geektool/Nerdtool add the capability (which I believe would be very hard to do).

I think your only solution for the time being is something for Dashboard.

Yeah figured as much. THanks for your help anyway.

Also here is my simple desktop. Nothing too over the top. REally wish I could figure out that linear calendar thing, but maybe tomorrow.
 

Attachments

  • Screen shot 2011-09-12 at 12.30.08 AM.png
    Screen shot 2011-09-12 at 12.30.08 AM.png
    700.7 KB · Views: 299
Last edited:
I installed the icalbuddy but i can't get my ical calendar to display. This is the command that I entered in the shell.
/usr/local/bin/icalBuddy -nc eventsToday | sed -e "s/*/--/" | sed -e "s/!/!!/"
 
Last edited:
just thought I'd show you guys my new desktop that I made with geektool. Pretty basic stuff.

Very nice! Just one tip for you though, you can change the spot where your username is to just an icon or remove it completely.

Screen Shot 2011-09-12 at 6.23.51 AM.png


Just go to System Preferences --> Users & Groups --> Login Options. There you go to Show fast user switching menu as: and change it so something else or uncheck it altogether and it will go away.

Screen Shot 2011-09-12 at 6.25.17 AM.png
 
hey guys i'm trying to get my itunes albumart to show on the desktop.

BUT i cant seem to get the script working. what info do i need to change?

here's my script:

Code:
-- Paths and stuff
set ArtworkFromiTunes to ((path to home folder) as text) & ¬
	"Pictures:iTunesArtwork:From iTunes:albumArt.pict" as alias
set iTunesArtwork to ((path to home folder) as text) & ¬
	"Pictures:iTunesArtwork:From iTunes:albumArt.pict"
set DefaultArtwork to ((path to home folder) as text) & ¬
	"Pictures:iTunesArtwork:Default:albumArt.pict"
set displayArtwork to ((path to home folder) as text) & ¬
	"Pictures:iTunesArtwork:albumArt.pict"

-- Unix versions of the above path strings
set unixITunesArtwork to the quoted form of POSIX path of iTunesArtwork
set unixDefaultArtwork to the quoted form of POSIX path of DefaultArtwork
set unixDisplayArtwork to the quoted form of POSIX path of displayArtwork

set whichArt to "blank"
tell application "System Events"
	if exists process "iTunes" then -- iTunes is running
		tell application "iTunes"
			if player state is playing then -- iTunes is playing
				set aLibrary to name of current playlist -- Name of Current Playlist
				set aTrack to current track
				set aTrackArtwork to null
				if (count of artwork of aTrack) ≥ 1 then -- there's an album cover
					"Running and playing and art"
					set aTrackArtwork to data of artwork 1 of aTrack
					set fileRef to ¬
						(open for access ArtworkFromiTunes with write permission)
					try
						set eof fileRef to 512
						write aTrackArtwork to fileRef starting at 513
						close access fileRef
					on error errorMsg
						try
							close access fileRef
						end try
						error errorMsg
					end try
					
					tell application "Finder" to ¬
						set creator type of ArtworkFromiTunes to "????"
					set whichArt to "iTunes"
				end if
			end if
		end tell
	end if
end tell

if whichArt is "iTunes" then
	do shell script "ditto -rsrc " & unixITunesArtwork & space & unixDisplayArtwork
else
	do shell script "ditto -rsrc " & unixDefaultArtwork & space & unixDisplayArtwork
end if

when i run the script in Applescript editor this error comes out:

error "File Macintosh HD:Users:bong:pictures:iTunesArtwork:From iTunes:albumArt.pict wasn’t found." number -43 from "Macintosh HD:Users:bong:pictures:iTunesArtwork:From iTunes:albumArt.pict"
 
Last edited:
hey guys i'm trying to get my itunes albumart to show on the desktop.

BUT i cant seem to get the script working. what info do i need to change?

here's my script:

when i run the script in Applescript editor this error comes out:

error "File Macintosh HD:Users:bong:pictures:iTunesArtwork:From iTunes:albumArt.pict wasn’t found." number -43 from "Macintosh HD:Users:bong:pictures:iTunesArtwork:From iTunes:albumArt.pict"

Did you get that code from somewhere? It looks very similar to one that I tried that didn't work. From what I remember, you had to run another script to get the album art into your pictures folder.

I ended up giving up on trying to figure it out because I determined I didn't need the album artwork on my desktop since most of my albums didn't pull artwork when I checked.

Most people use Bowtie for the album art.
 
Quick question, loving playing around with Geektool, but wondering if there is a way to keep everything on 'one' desktop, I switch my laptop out at home and at work with two separate monitors and leave my laptop lid open but the monitors are on separate sides, I can of course put the monitors in different places, but everytime if I move the monitor that's not where geek tool is loaded on, it just stays where I put them. (which is a good thing I guess) except when I would like it to stay with the main laptop screen all the time.
 
I thought I saw someone who had a script for a MacRumors display. Does anyone have that one?

Bringing back an old one for you SandboxGeneral...

Are you still looking for a MacRumors display? It's your lucky day if you are, here it is.

Code:
#!/usr/bin/env python

""" MACRUMORS_FEED_GRABBER
 ROBERT WOLTERMAN (xtacocorex) - 2010

 PULLS THE CURRENT FEED FROM MACRUMORS
 
"""

# MACRUMORS FEED - VERSION 1
# ROBERT WOLTERMAN - 2011
# PULLS THE CURRENT FEED FROM MACRUMORS

# CHANGELOG
# 12 SEPTEMBER 2011:
#  - INITIAL WRITE

# MODULE IMPORTS
import xml.dom.minidom
from optparse import OptionParser
import re
import urllib
import sys

# CONSTANTS
FEEDURL = "http://feeds.macrumors.com/MacRumors-All"

# CLASS TO HOLD THE DATA FOR A FEED ITEM
class NewsItem():
    def __init__(self):
        self.title = ""
        self.link = ""
        self.desc = ""
        self.pubdate = ""

# THE FOLLOWING TWO FUNCTIONS ARE FROM:
# http://love-python.blogspot.com/2008/07/strip-html-tags-using-python.html
# THEY WORK PERFECTLY
def remove_html_tags(data):
    p = re.compile(r'<.*?>')
    return p.sub('', data)    

def remove_extra_spaces(data):
    p = re.compile(r'\s+')
    return p.sub(' ', data)

# INLINE FUNCTIONS - DON'T FEEL LIKE CLASSING THIS UP
def getText(nodelist):
    rc = []
    for node in nodelist:
        if node.nodeType == node.TEXT_NODE:
            rc.append(node.data)
    return ''.join(rc)

def handleFeed(feed,FeedItems):
    items = feed.getElementsByTagName("item")
    handleNewsItem(items,FeedItems)

def handleNewsItem(items,FeedItems):
    for item in items:
        # CREATE TEMPORARY TODO
        tmpCls = NewsItem()
        # GET THE DATA FROM THE CURRENT ITEM
        title = item.getElementsByTagName("title")[0]
        link = item.getElementsByTagName("link")[0]
        pubdate = item.getElementsByTagName("pubDate")[0]
        # DESCRIPTION USES CDATA INSIDE TO CONTAIN HTML ELEMENTS
        desc = item.getElementsByTagName("description")[0].firstChild.wholeText
        # GET THE VALUES FROM THE TAGS
        tmpCls.title = getText(title.childNodes).strip()
        tmpCls.link = getText(link.childNodes).strip()
        tmpCls.pubdate = getText(pubdate.childNodes).strip()
        # DESCRIPTION IS DIFFERENT BECAUSE OF THE CDATA USE
        tmpCls.desc = remove_extra_spaces(remove_html_tags(desc))
        # APPEND TEMP DROPBOX NEWS CLASS TO DROP BOX NEWS LIST
        FeedItems.append(tmpCls)

def cmdLineOptionParser():
    """
        cmdLineOptionParser()
         - PARSES THE COMMAND LINE ARGUMENTS
         - INPUT:  NONE
         - OUPUTS: NONE
    """
    # CREATE OUR USAGE REPSONSE 
    usage = ("%prog [options]",__doc__)
    
    usage = "\n".join(usage)
    
    # CREATE OUR COMMAND LINE PARSER
    cmdparse = OptionParser(usage)
    
    # ADD COMMAND LINE OPTIONS
    cmdparse.add_option('-c', '--count', action='store', type='int',
        help="line count for output, default is 10",
        default=10
    )
    
    # NOT IMPLEMENTED
    #cmdparse.add_option('-s', '--sort', action="store", type='string',
    #    help="sort direction for the news items: forward/reverse",
    #    default='forward'
    #)
    
    # RETURN THE PARSER
    return cmdparse

if __name__ == "__main__":

    # SET UP THE COMMAND LINE OPTION HOLDER
    cmdparse = cmdLineOptionParser()
        
    # PARSE THE COMMAND LINE OPITONS
    opts, args = cmdparse.parse_args(sys.argv[1:])

    # GET THE FEED - UPDATE TO CMD LINE ARGUMENT
    dom = xml.dom.minidom.parse(urllib.urlopen(FEEDURL))

    # LIST TO HOLD ALL THE TASKS (toDo CLASS)
    FeedItems = []

    # HANDLE THE XML
    handleFeed(dom,FeedItems)

    # FIGURE OUT THE NUMBER OF ITEMS WE SHOULD PRINT
    if len(FeedItems) > opts.count:
        numprint = opts.count
    else:
        numprint = len(FeedItems)

    # PRINT OUT THE MACRUMORS NEWS
    # THIS IS CUSTOMIZABLE
    for i in range(numprint):
        # PRINT OUT THE DATA HOWEVER YOU WANT
        # DATA STORED IN EACH FeedItems SEGMENT
        # FeedItems[i].title   = TITLE OF THE NEWS ITEM
        # FeedItems[i].desc    = DESCRIPTION OF THE NEWS ITEM
        # FeedItems[i].link    = NEWS ITEM LINK
        # FeedItems[i].pubdate = DATE THE NEWS ITEM WAS PUBLISHED
        # CURRENTLY SET TO PRINT THE PUB DATE AND THE TITLE
        print FeedItems[i].pubdate + " " + FeedItems[i].title

Save the script as macrumorsnews.py. Output is customizable and is currently set to the publishing date and the title.

Options are similar to my Dropbox RSS feed script.
Code:
Options:
  -h, --help            show this help message and exit
  -c COUNT, --count=COUNT
                        line count for output, default is 10

For the geeklet (displays all items)
Code:
python /path/to/script/macrumorsnews.py


----------

Hello.

How make the vertical text? "September"

Image

They are images controlled by a Python script. I have an image for each month with the text vertical, they are .png files with transparent backgrounds.

I have a folder of the images in the location where I store all my geektool scripts, the script logic grabs this location and knows where the images are for the copy command at the end.

I have two geeklets, one to run the python script and another set to be an image pointed at /tmp/geektool/curmonthpic.png.

The python script is as follows:
Code:
#!/usr/bin/env python

import os, shutil, time

# Sets the current month to the /tmp/geektool/curmonthpic.png file

home = os.environ['HOME']
#print home
wdir = home+"/bin/geektool"
os.chdir(wdir)
cwd = os.getcwd()
#print cwd

ipath=cwd+"/monthimages/"
cfile="/tmp/geektool/curmonthpic.png"

# Set up day icon dictionary
monthmap = {
    'January'   : 'january.png',
    'February'  : 'february.png',
    'March'     : 'march.png',
    'April'     : 'april.png',
    'May'       : 'may.png',
    'June'      : 'june.png',
    'July'      : 'july.png',
    'August'    : 'august.png',
    'September' : 'september.png',
    'October'   : 'october.png',
    'November'  : 'november.png',
    'December'  : 'december.png'
	}

# GET THE CURRENT DATE
month = time.strftime("%B")

cicon = ipath + monthmap[month]

#print cicon

# Copy the current month image to /tmp/geektool/curmonthimg.png
shutil.copyfile(cicon,cfile)
 
Status
Not open for further replies.
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.