ipodderx-core/iPXTools.py

1206 lines
33 KiB
Python

#(c) 2004-2008 Thunderstone Media, LLC
#Creative Commons Attribution-Noncommercial 3.0 United States License
#
#Python Developyment By:
#
#Ray Slakinski
#August Trometer
import iPXSettings
import sys, difflib
from types import *
from time import *
if sys.platform == 'darwin':
from objc import *
from Foundation import *
class SM (difflib.SequenceMatcher):
def __helper(self, alo, ahi, blo, bhi, answer):
# slightly modified from difflib to ignore blocks of one elt
# this prevents weird ones like <del>Whe</><ins>Ocasio</>n<ins>ally</>
i, j, k = x = self.find_longest_match(alo, ahi, blo, bhi)
# a[alo:i] vs b[blo:j] unknown
# a[i:i+k] same as b[j:j+k]
# a[i+k:ahi] vs b[j+k:bhi] unknown
if k:
if alo < i and blo < j:
self.__helper(alo, i, blo, j, answer)
if k > 1: answer.append(x)
if i+k < ahi and j+k < bhi:
self.__helper(i+k, ahi, j+k, bhi, answer)
_SequenceMatcher__helper = _SM__helper # python name mangling funniness
class HTTPHead:
import urllib2, iPXSettings
def __init__(self, url, username=None, password=None):
self.reply = 302
self.headers = []
self.msg = ''
setOpener()
url = url.strip()
url = url.replace(' ', '%20')
req = urllib2.Request(url)
req.add_header('User-Agent', iPXSettings.USER_AGENT)
try:
h = urllib2.urlopen(req)
self.headers = h.info()
except Exception, e:
logIt(e)
def getType(self):
if self.headers.has_key('Content-Type') and self.reply == 200:
return self.headers['Content-Type']
else:
return None
def getLength(self):
if self.headers.has_key('Content-Length') and self.reply == 200:
return self.headers['Content-Length']
else:
return None
def getName(self):
import re
from string import split
newName = ''
if self.headers.has_key('Content-Disposition') and self.reply == 200:
if re.search('filename=', self.headers['Content-Disposition'], re.IGNORECASE):
textSplit = self.headers['Content-Disposition'].split(';')
for text in textSplit:
if re.search('filename=', text, re.IGNORECASE):
newNameSplit = text.split('=')
newName = newNameSplit[len(newNameSplit) -1]
newName = newName.replace('"', '')
return newName
def stringCleaning(text):
import re
text = re.sub('[\\\\/?*:<>|;"\']','', text)
text = text.strip()
return text
def isTag(x): return x[0] == "<" and x[-1] == ">"
def stringDiff(a, b):
from string import join
"""@@@"""
out = ''
chars = 0
a, b = ' '.join(html2list(a)), ' '.join(html2list(b))
s = SM(None, a, b)
a = ' '.join(html2list(a, b=1))
for e in s.get_opcodes():
if e[0] == "replace":
out += "<del>" + a[e[1]:e[2]] + "</del>"
out += "<ins>" + b[e[3]:e[4]] + "</ins>"
elif e[0] == "delete":
out += "<del>"+ a[e[1]:e[2]] +"</del>"
elif e[0] == "insert":
out += "<ins>"+b[e[3]:e[4]] +"</ins>"
elif e[0] == "equal":
chunk = b[e[3]:e[4]]
if len(chunk) > chars: chars = len(chunk)
out += chunk
else:
raise "Um, something's broken. I didn't expect a '" + `e[0]` + "'."
return out
def textDiff(a, b):
"""Takes in strings a and b and returns a human-readable HTML diff."""
from string import join
out = []
a, b = html2list(a), html2list(b)
s = difflib.SequenceMatcher(isTag, a, b)
for e in s.get_opcodes():
if e[0] == "replace":
# @@ need to do something more complicated here
# call textDiff but not for html, but for some html... ugh
# gonna cop-out for now
out.append("<span class='modified diff'>"+' '.join(b[e[3]:e[4]])+"</span>")
elif e[0] == "delete":
out.append("<del class='diff'>"+ ' '.join(a[e[1]:e[2]]) + "</del>")
elif e[0] == "insert":
out.append("<ins class='diff'>"+' '.join(b[e[3]:e[4]]) + "</ins>")
elif e[0] == "equal":
out.append(' '.join(b[e[3]:e[4]]))
else:
raise "Um, something's broken. I didn't expect a '" + `e[0]` + "'."
return ' '.join(out)
def html2list(x, b=0):
import string
mode = 'char'
cur = ''
out = []
for c in x:
if mode == 'tag':
if c == '>':
if b: cur += ']'
else: cur += c
out.append(cur); cur = ''; mode = 'char'
else: cur += c
elif mode == 'char':
if c == '<':
out.append(cur)
if b: cur = '['
else: cur = c
mode = 'tag'
elif c in string.whitespace: out.append(cur); cur = ''
else: cur += c
out.append(cur)
return filter(lambda x: x is not '', out)
def htmlDiff(a, b):
f1, f2 = a.find('</head>'), a.find('</body>')
ca = a[f1+len('</head>'):f2]
f1, f2 = b.find('</head>'), b.find('</body>')
cb = b[f1+len('</head>'):f2]
r = textDiff(ca, cb)
hdr = '<style type="text/css"><!-- ins{color: green} del{color:red}--></style></head>'
return b[:f1] + hdr + r + b[f2:]
def getDirSize(dir):
import os
sizes = []
os.path.walk(dir, calcDirSize, sizes)
total = 0
for size in sizes:
total = total + size
return (total)
def calcDirSize(arg, dir, files):
import os
for file in files:
stats = os.stat(os.path.join(dir, file))
size = stats[6]
arg.append(size)
def HTML2Text(text):
import htmlentitydefs
flag = [1]
cleanText = ''
def stripfunc(c):
if not flag[0]:
if c == '>':
flag[0] = 1
return 0
elif c == '<':
flag[0] = 0
return flag[0]
cleanText = filter(stripfunc,text)
# 039 isn't in the defs table for some reason.
htmlentitydefs.codepoint2name[39] = 'quot'
for key in htmlentitydefs.name2codepoint:
if ('&%s;' % key) in cleanText:
try:
cleanText = cleanText.replace('&%s;' % key, unichr(htmlentitydefs.name2codepoint[key]))
except:
pass
for key in htmlentitydefs.codepoint2name:
if key < 100:
if ('&#0%d;' % key) in cleanText:
try:
cleanText = cleanText.replace('&#0%d;' % key, unichr(key))
except:
pass
if ('&#%d;' % key) in cleanText:
try:
cleanText = cleanText.replace('&#%d;' % key, unichr(key))
except:
pass
cleanText = cleanText.strip()
return cleanText
def text2Audio(text, saveDir, saveName):
import os
printMSG('Converting Text Entry To Audio...')
logIt('Converting Text Entry To Audio...')
cleanText = HTML2Text(text)
cleanText = cleanText.replace('"', '')
if sys.platform == 'darwin':
try:
f = open('/tmp/iPX-textToAudio.applescript', 'w')
f.write('set theText to "%s"\r\n' % cleanText)
f.write('set theFile to POSIX file "%s/%s\r\n' % (saveDir,saveName))
f.write('say theText saving to theFile')
f.close()
os.popen('/usr/bin/osascript /tmp/iPX-textToAudio.applescript')
return True
except Exception, msg:
logIt('text2Audio Error: %s' % msg)
return False
elif sys.platform == 'win32':
try:
import win32com.client
import shutil
speech = win32com.client.Dispatch('SAPI.SpVoice')
file_stream = win32com.client.Dispatch('SAPI.SpFileStream')
except Exception, msg:
logIt('text2Audio Error: %s' % msg)
return False
logIt('Speech Modules Loaded...')
try:
file_stream.Format.Type = 6
file_stream.Open(saveName, 3, True)
speech.AudioOutputStream = file_stream
if not speech.Speak(cleanText) == 1:
return False
file_stream.Close()
if os.path.isfile('.\\%s' % saveName):
shutil.move('.\\' + saveName, saveDir + '\\' + saveName)
else:
logIt('text2Audio Error: File was not properly created')
return False
except Exception, msg:
logIt('text2Audio Error: %s' % msg)
return False
return True
def prepURL(url):
url = url.replace('%3A', ':')
url = url.replace('%2F', '/')
if (url[:8] != 'https://'):
if (url[:7] != 'http://'):
url = 'http://%s' % url
return url
def trimLog():
import os, iPXSettings
if os.path.isfile(iPXSettings.logFile):
os.unlink(iPXSettings.logFile)
def genHash(data):
import md5
try:
msg = data.encode('utf8')
except:
from binascii import hexlify
msg = hexlify(data)
msg = msg.encode('utf8')
item = md5.new()
item.update(msg)
return item.hexdigest()
def logIt(incomingMsg):
import os, iPXSettings
try:
if type(incomingMsg) is UnicodeType:
incomingMsg = incomingMsg.encode('utf8')
else:
incomingMsg = str(incomingMsg)
msg = '%s %s' % (strftime('[%H:%M:%S]',localtime()), incomingMsg)
if iPXSettings.DEBUG:
printMSG(msg)
if os.path.isfile(iPXSettings.logFile):
f = open(iPXSettings.logFile, 'a')
f.write(msg + '\r\n')
f.close()
else:
f = open(iPXSettings.logFile, 'w')
f.write(msg + '\r\n')
f.close()
except Exception, msg:
if iPXSettings.DEBUG:
printMSG('Error Saving Log: %s' % msg)
if os.path.isfile(iPXSettings.logFile):
if iPXSettings.DEBUG:
printMSG('Attempting to deleting old log file...')
try:
os.unlink(iPXSettings.logFile)
except Exception, msg:
if iPXSettings.DEBUG:
printMSG('Error Deleting Log: ' + msg)
def latin1_to_ascii(unicrap):
"""This takes a UNICODE string and replaces Latin-1 characters with
something equivalent in 7-bit ASCII. It returns a plain ASCII string.
This function makes a best effort to convert Latin-1 characters into
ASCII equivalents. It does not just strip out the Latin-1 characters.
All characters in the standard 7-bit ASCII range are preserved.
In the 8th bit range all the Latin-1 accented letters are converted
to unaccented equivalents. Most symbol characters are converted to
something meaningful. Anything not converted is deleted.
"""
xlate={0xc0:'A', 0xc1:'A', 0xc2:'A', 0xc3:'A', 0xc4:'A', 0xc5:'A',
0xc6:'Ae', 0xc7:'C',
0xc8:'E', 0xc9:'E', 0xca:'E', 0xcb:'E',
0xcc:'I', 0xcd:'I', 0xce:'I', 0xcf:'I',
0xd0:'Th', 0xd1:'N',
0xd2:'O', 0xd3:'O', 0xd4:'O', 0xd5:'O', 0xd6:'O', 0xd8:'O',
0xd9:'U', 0xda:'U', 0xdb:'U', 0xdc:'U',
0xdd:'Y', 0xde:'th', 0xdf:'ss',
0xe0:'a', 0xe1:'a', 0xe2:'a', 0xe3:'a', 0xe4:'a', 0xe5:'a',
0xe6:'ae', 0xe7:'c',
0xe8:'e', 0xe9:'e', 0xea:'e', 0xeb:'e',
0xec:'i', 0xed:'i', 0xee:'i', 0xef:'i',
0xf0:'th', 0xf1:'n',
0xf2:'o', 0xf3:'o', 0xf4:'o', 0xf5:'o', 0xf6:'o', 0xf8:'o',
0xf9:'u', 0xfa:'u', 0xfb:'u', 0xfc:'u',
0xfd:'y', 0xfe:'th', 0xff:'y',
0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}',
0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}',
0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}',
0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}',
0xb1:'{+/-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'",
0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}',
0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>',
0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?',
0xd7:'*', 0xf7:'/'
}
r = ''
for i in unicrap:
if xlate.has_key(ord(i)):
r += xlate[ord(i)]
elif ord(i) >= 0x80:
pass
else:
r += str(i)
return r
def updatePlaylist(saveLocation, saveName, playList, customGenre, convertToAAC, makeBookmarkable):
import os, iPXSettings, random
location = ''
iPXID = ''
if sys.platform == 'darwin':
if (convertToAAC):
printMSG('Exporting to iTunes and converting to AAC...')
logIt('Exporting to iTunes and converting to AAC...')
else:
printMSG('Exporting to iTunes...')
logIt('Exporting to iTunes...')
trackID = 0
fullPath = saveLocation + '/' + saveName
song = os.path.abspath(fullPath)
while True:
scriptName = '/tmp/iPX-iTunes-%d.scpt' % random.randint(1,90000)
if not os.path.isfile(scriptName):
break
f = open(scriptName, 'w')
# initial settings
f.write('set thePlaylist to "%s"\r\n' % playList)
f.write('set theFile to "%s"\r\n' % song)
f.write('set theGenre to "%s"\r\n' % customGenre)
f.write('set theTrackID to 0\r\n')
f.write('property required_version : "4.0"\r\n')
# if iTunes isn't open, open it in the background
f.write('tell application "System Events"\r\n')
f.write('if (not (exists process "iTunes")) then\r\n')
f.write('tell application "iTunes"\r\n')
f.write('set visible of front window to false\r\n')
f.write('end tell\r\n')
f.write('end if\r\n')
f.write('end tell\r\n')
f.write('set theFile to the POSIX file theFile\r\n')
f.write('tell application "iTunes"\r\n')
#
# IMPORT TO ITUNES LIBRARY
#
f.write('with timeout of 1800 seconds\r\n')
# move track to Library and get track object
f.write('try\r\n')
f.write('set theTrack to add theFile to library playlist 1 of source 1\r\n')
f.write('on error theError\r\n')
f.write('set theTrack to add theFile to library playlist 1\r\n')
f.write('end try\r\n')
f.write('end timeout\r\n')
#
# SET CUSTOM GENRE
#
if len(customGenre) > 0:
f.write('try\r\n')
f.write('set genre of theTrack to theGenre\r\n')
f.write('end try\r\n')
#
# SET IPXID IN THE COMMENTS FIELD
#
iPXID = strftime('%M%Y%m%H%d%S',gmtime())
f.write('set theComment to the comment of theTrack\r\n')
f.write('set theCharacters to every character in theComment\r\n')
f.write('set commentString to ""\r\n')
f.write('repeat with aCharacter in theCharacters\r\n')
f.write('if (count commentString) is less than 160 then\r\n')
f.write('set commentString to commentString & aCharacter\r\n')
f.write('end if\r\n')
f.write('end repeat\r\n')
f.write('set the comment of theTrack to commentString & "\r\r" & "[iPXID:%s]"\r\n' % iPXID)
#
# MAKE BOOKMARKABLE
#
f.write('with timeout of 1800 seconds\r\n')
f.write('try\r\n')
f.write('set this_version to the version as string\r\n')
f.write('if this_version is greater than or equal to the required_version then\r\n')
f.write('set bookmarkable of theTrack to true\r\n')
f.write('end if\r\n')
f.write('end try\r\n')
f.write('end timeout\r\n')
#
# MOVE TO PLAYLIST
#
# Create playlist if it doesn't exist
f.write('try\r\n')
f.write('if (not (exists user playlist thePlaylist)) then\r\n')
f.write('make new playlist with properties {name:thePlaylist}\r\n')
f.write('end if\r\n')
# move to the playlist
f.write('duplicate theTrack to the playlist thePlaylist\r\n')
f.write('end try\r\n')
"""
# update connected iPod
f.write('try\r\n')
f.write('set myPod to (name of some source whose kind is iPod)\r\n')
f.write('update myPod\r\n')
f.write('end try\r\n')
"""
f.write('return theTrack\r\n')
f.write('end tell\r\n')
f.close()
ret_pipe = os.popen('/usr/bin/osascript %s' % scriptName)
returnValue = ''
returnValue = ret_pipe.readline()
if len(returnValue) > 0:
location = "iTunes"
if (iPXSettings.deleteAudio > 0):
logIt('Deleting: %s...' % fullPath)
if os.path.isfile(fullPath):
os.unlink(fullPath)
else:
printMSG('iTunes failed to update. Track left in Library')
logIt('iTunes failed to update. Track left in Library')
iPXID = ''
if not iPXSettings.DEBUG:
if os.path.isfile(scriptName):
os.unlink(scriptName)
else:
logIt('Keeping script: %s' % scriptName)
elif sys.platform == 'win32':
import win32com.client
import shutil
if iPXSettings.Prefs['exportApp'] == 1:
try:
printMSG('Exporting to Windows Media Player...')
logIt('Exporting to Windows Media Player...')
wmp = win32com.client.Dispatch('WMPlayer.OCX.7')
playlists = wmp.playlistCollection.getByName(playList)
if playlists.count == 0:
pl = wmp.playlistCollection.newPlaylist(playList)
else:
pl = playlists.item(0)
media = wmp.newMedia('%s\\%s' % (saveLocation, saveName))
if len(customGenre) > 0:
# Can not set Genre on some media files
try:
media.setItemInfo('WM/Genre', customGenre)
except:
pass
logIt('Adding Media File...')
pl.appendItem(media)
wmp.close()
location = "WMP"
except Exception, msg:
logIt('Failed to export to Windows Media Player')
logIt('ERRMSG: %s' % msg)
else:
try:
if (convertToAAC):
printMSG('Exporting to iTunes and converting to AAC...')
logIt('Exporting to iTunes and converting to AAC...')
else:
printMSG('Exporting to iTunes...')
logIt('Exporting to iTunes...')
itunes = win32com.client.Dispatch('iTunes.Application')
playlists = itunes.LibrarySource.Playlists
pl = playlists.ItemByName(playList)
if not pl:
pl = itunes.CreatePlaylist(playList)
if (convertToAAC):
oldEncoder = itunes.CurrentEncoder
itunes.CurrentEncoder = itunes.Encoders.ItemByName('AAC Encoder')
handle = itunes.ConvertFile2('%s\\%s' % (saveLocation, saveName))
while handle.InProgress:
sleep(3)
itunes.CurrentEncoder = oldEncoder
for track in handle.Tracks:
aacLocation = str(track.Location)
if os.path.isfile(aacLocation):
newAacLocation = aacLocation.replace('.m4a', '.m4b')
shutil.copy(aacLocation, newAacLocation)
track.Delete()
os.unlink(aacLocation)
handle = pl.AddFile(newAacLocation)
try:
while handle.InProgress:
sleep(3)
except:
pass
else:
handle = pl.AddFile('%s\\%s' % (saveLocation, saveName))
try:
while handle.InProgress:
sleep(3)
except:
pass
for track in handle.Tracks:
#
# SET IPXID IN THE COMMENTS FIELD
#
iPXID = strftime('\r\n[iPXID:%M%Y%m%H%d%S]\r\n',gmtime())
track.Comment = track.Comment + iPXID
if len(customGenre) > 0:
track.Genre = customGenre
location = 'iTunes'
except Exception, msg:
logIt('Failed to export to iTunes')
logIt('ERRMSG: %s' % msg)
return iPXID, location
def updateiPhoto(saveLocation, saveName, photoAlbum, type):
import os, iPXSettings, random
printMSG( 'Exporting to iPhoto...')
location = ''
iPhotoID = 0
iPXID = ''
if sys.platform == 'darwin':
fullPath = saveLocation + '/' + saveName
while True:
scriptName = '/tmp/iPX-iPhoto-%d.scpt' % random.randint(1,90000)
if not os.path.isfile(scriptName):
break
f = open(scriptName, 'w')
# base values
f.write('set theAlbum to "%s"\r\n' % photoAlbum)
f.write('set thePath to "%s"\r\n' % fullPath)
f.write('tell application "iPhoto"\r\n')
#create album if it doesn't exist
f.write('if not (exists album theAlbum) then\r\n')
f.write('new album name theAlbum\r\n')
f.write('end if\r\n')
#import the photo
f.write('set thePhoto to thePath\r\n')
f.write('import from thePhoto to album theAlbum\r\n')
#get the photo location
f.write('set importedPhoto to the last item in (every photo in the last import album)\r\n')
#
# SET IPXID IN THE COMMENTS FIELD
#
iPXID = strftime('%m%M%Y%H%d%S',gmtime())
f.write('set theComment to the comment of importedPhoto\r\n')
f.write('set the comment of importedPhoto to theComment & "\r\r" & "[iPXID:%s]"\r\n' % iPXID)
# return the final Track Location
f.write('return the (id of importedPhoto) mod (8 ^ 8) as integer\r\n')
f.write('end tell\r\n')
f.close()
try:
ret_pipe = os.popen('/usr/bin/osascript %s' % scriptName)
iPhotoID = int(ret_pipe.readline())
except:
pass
if (iPhotoID > 3):
location = "iPhoto"
if type == 0:
if (iPXSettings.deleteImages > 0):
logIt('Deleting: %s...' % fullPath)
if os.path.isfile(fullPath):
os.unlink(fullPath)
elif type == 1:
if (iPXSettings.deleteVideo > 0):
logIt('Deleting: %s...' % fullPath)
if os.path.isfile(fullPath):
os.unlink(fullPath)
else:
printMSG('iPhoto failed to update. Image left in iPodderX Library')
iPXID = ''
if not iPXSettings.DEBUG:
if os.path.isfile(scriptName):
os.unlink(scriptName)
# return the photoID of the file just added
return iPXID, location
def detectFileType(fileName):
import typeFile, re
logIt('Detecting file type...')
try:
fileType = typeFile.file(fileName)
except Exception, msg:
logIt('Failed to detect type, using data')
logIt(msg)
fileType = 'data'
if re.search('ascii', fileType, re.IGNORECASE):
f = open(fileName, 'r')
for line in f.readlines():
if re.search('<html>', line, re.IGNORECASE):
type = 'html'
break
if re.search('xml', fileType, re.IGNORECASE):
f = open(fileName, 'r')
for line in f.readlines():
if re.search('<rss', line, re.IGNORECASE):
type = 'rss'
break
elif re.search('<opml', line, re.IGNORECASE):
type = 'opml'
break
logIt('File type is %s' % fileType)
return fileType
def readplist(pList):
if sys.platform == 'darwin':
try:
plistObj = NSMutableDictionary.dictionary()
plistObj = NSMutableDictionary.dictionaryWithContentsOfFile_(pList)
except Exception, msg:
logIt('Error reading plist: %s' % msg)
plistObj = {}
elif sys.platform == 'win32':
import plistlib
try:
plistObj = plistlib.Plist.fromFile(file(pList))
except:
plistObj = plistlib.Plist()
return plistObj
def writeplist(dictObj, plist):
import os
if sys.platform == 'darwin':
try:
dictObj.writeToFile_atomically_(plist, True)
except Exception, msg:
logIt('Error saving %s file' % plist)
logIt('ERRMSG: %s' % msg)
if os.path.isfile(plist):
os.unlink(plist)
elif sys.platform == 'win32':
import plistlib
dictObj.write(plist)
def checkReg():
return 1
def checkDir(dir):
import os
if not os.path.isdir(dir):
os.mkdir(dir)
def delTree(dir):
import os
for root, dirs, files in os.walk(dir, topdown=False):
for name in files:
os.remove(os.path.join(root, name))
for name in dirs:
os.rmdir(os.path.join(root, name))
def getHistory():
import os, iPXSettings
logIt('Getting history from history.dat...')
guids = []
if os.path.isfile(iPXSettings.historyFile):
logIt('Found history.plist, converting to history.dat...')
try:
import plistlib
tempHist = plistlib.Plist.fromFile(file(iPXSettings.historyFile))
except Exception, msg:
logIt('History file could not be read')
logIt('ERRORMSG: %s' % msg)
tempHist['downloadHistory'] = list('')
try:
if (len(tempHist['downloadHistory']) > 0):
for historyItem in tempHist['downloadHistory']:
if historyItem.has_key('encGUID'):
guids.append(historyItem['encGUID'])
try:
os.unlink(iPXSettings.historyFile)
except:
pass
for guid in guids:
saveHistory(guid)
except Exception, msg:
logIt('ERRMSG: %s' % msg)
else:
import pickle
try:
if os.path.isfile(iPXSettings.newHistoryFile):
guids = pickle.load(open(iPXSettings.newHistoryFile))
except:
pass
return guids
def saveHistory(encGUID):
import pickle, iPXSettings
if iPXSettings.ranHistCheck == False:
iPXSettings.histGUIDs = getHistory()
iPXSettings.ranHistCheck = True
if not encGUID in iPXSettings.histGUIDs:
logIt('Adding to history.dat: %s' % encGUID)
iPXSettings.histGUIDs.append(encGUID)
pickle.dump(iPXSettings.histGUIDs, open(iPXSettings.newHistoryFile,'w'))
else:
logIt('Entry already found in history.dat: %s' % encGUID)
def doPing(encURL, feedURL):
import urllib, iPXSettings
logIt('Sending Anonymous download feedback...')
pingURL = 'http://directory.iPodderX.com/feedData/survey/files?url=%s&feed=%s' % (encURL, feedURL)
try:
class AppURLopener(urllib.FancyURLopener):
version = iPXSettings.USER_AGENT
urllib._urlopener = AppURLopener()
handle = urllib.urlopen(pingURL)
except Exception, msg:
logIt('ERRMSG: %s' % msg)
def printMSG(msg):
import os
try:
print msg.encode('utf8')
sys.stdout.flush()
except Exception, msg:
logIt('Failed to print console message')
logIt('ERRMSG: %s' % msg)
def checkForScript():
import iPXSettings, os
if sys.platform == 'darwin':
if not iPXSettings.progName == 'iPodderX':
if (int(os.popen('ps auxww | grep -i iPodderX.py | grep -i "progName==' + iPXSettings.progName +'" |grep -v /bin/sh | grep -w -v ps | wc -l','r').readline().strip()) > 1):
printMSG('CHECK_ALREADY_RUNNING')
for line in os.popen('ps auxww | grep -i iPodderX.py | grep -v /bin/sh | grep -w -v ps','r').readlines():
logIt(line)
return True
else:
return False
else:
if (int(os.popen('ps auxww | grep -i iPodderX.py |grep -v /bin/sh | grep -w -v ps | wc -l','r').readline().strip()) > 2):
printMSG('CHECK_ALREADY_RUNNING')
for line in os.popen('ps auxww | grep -i iPodderX.py | grep -v /bin/sh | grep -w -v ps','r').readlines():
logIt(line)
return True
else:
return False
elif sys.platform == 'win32':
pass
def getOpmlFeeds(url):
import opmlparser, urllib, re
ompl_parser = opmlparser.OPMLParser()
try:
data = urllib.urlopen(url).read()
ompl_parser.feed(data)
except Exception, msg:
logIt('OPML Connect Error: %s' % msg)
opmlFeeds = {}
for node in ompl_parser:
try:
if re.search('rss', str(node.get('type')), re.IGNORECASE) or re.search('atom', str(node.get('type')), re.IGNORECASE):
title = 'Unknown'
if not str(node.get('title')) == 'None':
title = str(node.get('title'))
elif not str(node.get('text')) == 'None':
title = str(node.get('text'))
if not str(node.get('xmlUrl')) == 'None':
opmlFeeds[title] = str(node.get('xmlUrl'))
elif not str(node.get('url')) == 'None':
opmlFeeds[title] = str(node.get('url'))
except Exception, msg:
logIt('OPML Error: %s' % msg)
return opmlFeeds
def checkForUI():
import os, iPXSettings
if sys.platform == 'darwin':
if (int(os.popen('ps auxww | grep -i /Contents/MacOS/%s | grep -w -v ps | wc -l' % iPXSettings.progName,'r').readline().strip()) > 1):
return True
else:
return False
elif sys.platform == 'win32':
pass
def encrypt(plain):
import pyDes, iPXSettings
from binascii import hexlify
key = iPXSettings.getVar('3DESKey')
key = key.decode('rot-13')
k = pyDes.triple_des(key)
d = k.encrypt(plain.strip(), ' ')
return hexlify(d)
def decrypt(ciph):
import pyDes, iPXSettings
from binascii import unhexlify
ciph = unhexlify(ciph)
key = iPXSettings.getVar('3DESKey')
key = key.decode('rot-13')
k = pyDes.triple_des(key)
d = k.decrypt(ciph, ' ')
return d
def isWhole(x):
return x == math.floor(x)
def setProxy():
import os, iPXSettings
from string import split
proxy = ''
if sys.platform == 'darwin':
import ic
try:
inetConfig = ic.IC()
if 'UseHTTPProxy' in inetConfig and inetConfig['UseHTTPProxy']:
if inetConfig.has_key('HTTPProxyHost'):
proxy = 'http://%s' % inetConfig['HTTPProxyHost']
iPXSettings.useProxyServer = inetConfig['HTTPProxyHost']
except Exception, msg:
logIt('Failed to detect OSX Proxy: %s' % msg)
elif sys.platform == 'win32':
if iPXSettings.useProxyServer:
if iPXSettings.useProxyIE:
try:
import _winreg as winreg
host_port = None
# Try to grab current proxy settings from the registry
regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
'Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings')
regval = winreg.QueryValueEx(regkey, 'ProxyServer')
proxyEnabled = winreg.QueryValueEx(regkey, 'ProxyEnable')
regkey.Close()
regval = str(regval[0])
proxyEnabled = proxyEnabled[0]
if proxyEnabled:
# Regval can be of two types:
# - 'myproxy:3128' if one proxy for all protocols
# - 'ftp=myftpproxy:3128;http=myhttpproxy:3128;...' if several different proxies
values = regval.split(';')
if len(values) > 1:
for s in values:
scheme, p = s.split('=')
if scheme == 'http':
host_port = p
break
else:
host_port = values[0]
# Split host and port
if host_port is not None:
t = host_port.split(':')
host = t[0].strip()
if host:
try:
port = int(t[1])
except:
port = 80
proxy = '%s:%d' % (host, port)
iPXSettings.proxyServer = host
iPXSettings.proxyPort = str(port)
except Exception, e:
logIt('Proxy Detection Error: %s' % e)
else:
if iPXSettings.useProxyAuth:
proxy = iPXSettings.proxyUsername + ':' + decrypt(iPXSettings.proxyPassword) + '@' + iPXSettings.proxyServer
if len(iPXSettings.proxyPort) > 0:
proxy = proxy + ':' + iPXSettings.proxyPort
else:
proxy = iPXSettings.proxyServer
if len(iPXSettings.proxyPort) > 0:
proxy = proxy + ':' + iPXSettings.proxyPort
if len(proxy) > 0:
proxy = 'http://' + proxy
if len(proxy) > 0:
os.environ["http_proxy"] = proxy
os.environ["https_proxy"] = proxy
else:
iPXSettings.proxyServer = ''
iPXSettings.proxyPort = ''
return proxy
def setOpener(url='', uName=None, pWord=''):
import urlparse, base64, socket, urllib2, iPXSettings
socket.setdefaulttimeout(30)
headers = []
host = urlparse.urlparse(url)[1]
path = urlparse.urlparse(url)[2]
headers.append(('User-Agent', iPXSettings.USER_AGENT))
if iPXSettings.useProxyServer:
if iPXSettings.useProxyAuth:
user_pass = base64.encodestring('%s:%s' %(iPXSettings.proxyUsername,decrypt(iPXSettings.proxyPassword)))
headers.append(('Proxy-authorization', 'Basic %s' % user_pass))
opener = urllib2.build_opener()
if not uName == None:
webAuth = base64.encodestring('%s:%s' % (uName, pWord))
headers.append(('Authorization', 'Basic ' + webAuth))
opener.addheaders = headers
urllib2.install_opener(opener)
return opener
def getFileViaProxySSL(url, uName, pWord, justHead=False, dlProgress=False):
import urlparse, base64, socket, httplib, urllib, os, iPXSettings, re
from string import split
host = urlparse.urlparse(url)[1]
port=443
filePath = urlparse.urlparse(url)[2]
phost=iPXSettings.proxyServer
pport=int(iPXSettings.proxyPort)
if iPXSettings.SUPERDEBUG:
logIt('Using Proxy: %s:%d' % (phost, pport))
webAuth = base64.encodestring('%s:%s' % (uName, pWord))
proxy_authorization = ''
if iPXSettings.useProxyAuth:
user=iPXSettings.proxyUsername
passwd=decrypt(iPXSettings.proxyPassword)
user_pass=base64.encodestring(user + ':' + passwd)
proxy_authorization='Proxy-authorization: Basic '+user_pass+'\r\n'
proxy_connect='CONNECT %s:%s HTTP/1.0\r\n'%(host,port)
proxy_pieces=proxy_connect+proxy_authorization+'\r\n'
if iPXSettings.SUPERDEBUG:
print proxy_pieces
try:
#now connect, very simple recv and error checking
proxy=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
proxy.settimeout(60)
proxy.connect((phost,pport))
proxy.sendall(proxy_pieces+'\r\n')
response=proxy.recv(8192)
status=response.split()[1]
if status!='200': raise Exception, 'Recieved HTTP Status Code: %d' % status
#trivial setup for ssl socket
ssl = socket.ssl(proxy, None, None)
sock = httplib.FakeSocket(proxy, ssl)
#initalize httplib and replace with your socket
params = urllib.urlencode({})
headers = {'Authorization':'Basic ' + webAuth, 'User-Agent':iPXSettings.USER_AGENT}
h=httplib.HTTPConnection('localhost')
h.sock=sock
if justHead:
saveName = None
h.request("HEAD", url,headers=headers)
respObj = h.getresponse()
url = urlparse.urljoin(url, respObj.getheader('location', ''))
saveName = url.split('/')[len(url.split('/'))-1]
logIt(saveName)
if respObj.status in (301,302,):
url = urlparse.urljoin(url, respObj.getheader('location', ''))
#filePath = urlparse.urlparse(url)[2]
logIt('Redirecting to url: %s' % url)
try:
if not respObj.getheader('Content-Disposition') == None:
if re.search('filename=', respObj.getheader('Content-Disposition'), re.IGNORECASE):
textSplit = respObj.getheader('Content-Disposition')
textSplit = textSplit.split(';')
for text in textSplit:
if re.search('filename=', text, re.IGNORECASE):
logIt('Detected New Filename To Use:')
newSaveNameSplit = text.split('=')
newSaveName = newSaveNameSplit[len(newSaveNameSplit) -1]
newSaveName = newSaveName.replace('"', '')
logIt(newSaveName)
saveName = newSaveName
except Exception, msg:
logIt('Content-Disposition Error: %s' % msg)
return respObj.status, url, saveName
else:
h.request('GET', url, headers=headers)
except Exception, msg:
logIt('Connection Failed')
logIt('ERRMSG: %s' % msg)
return 0, None, None
if dlProgress:
import tempfile
try:
count = 0
lastPercentDone = 0
n = 1024 # number of bytes to read at a time
fileSize = 0
r=h.getresponse()
if r.status == 200:
fileSize = float(r.getheader('Content-Length', 0.00)) / 1024
printMSG(';;1;;1;;100.00;;0.00')
tmpFile = tempfile.mkstemp()
tmpFileName = tmpFile[1]
f = open(tmpFileName, 'ab')
while True:
a = r.read(n)
f.write(a)
if not a: break
count += len(a) # len(a) may not be same as n for final read
percentDone = ((float(count) /1024) / fileSize) * 100
if percentDone >= lastPercentDone + 1:
lastPercentDone = percentDone
printMSG(';;1;;1;;100.00;;%.2f' % percentDone)
printMSG(';;1;;1;;100.00;;100.00')
f.close()
os.close(tmpFile[0])
return 200, tmpFileName, r
else:
logIt('Recieved HTTP Code: %s' % r.status)
return 0, None, None
except Exception, msg:
logIt('Connection Failed')
logIt('ERRMSG: %s' % msg)
return 0, None, None
else:
try:
r=h.getresponse()
data = r.read()
if iPXSettings.SUPERDEBUG:
print data
return 200, data, None
except Exception, msg:
logIt('Connection Failed')
logIt('ERRMSG: %s' % msg)
return 0, '', None