Pastebin is 300% more awesome when you are logged in. Sign Up, it's FREE!
Guest

Untitled

By: a guest on Sep 23rd, 2011  |  syntax: Python  |  size: 17.72 KB  |  hits: 85  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. from PyQt4.QtCore import *
  2. from PyQt4.QtGui import *
  3. from PyQt4.QtNetwork import QHttp
  4.  
  5. from PyKDE4.plasma import Plasma
  6. from PyKDE4 import plasmascript
  7. from PyKDE4.kdeui import KMessageBox
  8. import sys
  9. import os
  10. import os.path
  11. import time
  12. import datetime
  13. import urllib2
  14.  
  15. # parsing modules
  16. from BeautifulSoup import BeautifulSoup
  17. import re
  18.  
  19.        
  20.  
  21. class ShowDesc(QThread):
  22.   def __init__(self, app, showName):
  23.     QThread.__init__(self)
  24.     self.app = app
  25.     self.showName = showName.replace("_", " ")
  26.     HOST = "http://www.tvrage.com/"
  27.     self.showUrl = QUrl(HOST+showName.replace(" ","_"))
  28.     self.imageLocal = self.app.applet.package().path()+"contents/shows/"+self.showName.toLower()+".jpg"
  29.    
  30.    
  31.     self.imageUrl = None
  32.     self.title = None
  33.     self.ntimestamp = None
  34.     self.ptimestamp = None
  35.     self.busy = True
  36.     self.finalEpisode = False  
  37.        
  38.     self.label = None
  39.     self.ntime = None
  40.     self.ntimestamp = float(sys.maxint)
  41.     self.__initGui()
  42.     self.setEdit(False)
  43.  
  44.  
  45.   def __del__(self):
  46.     print "removed this showdesc"
  47.  
  48.   def __initGui(self):
  49.     if not self.label == None:
  50.       print "already guied bitch!"
  51.       return
  52.      
  53.     l = Plasma.Label(self.app.applet)  
  54.     l.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
  55.     l.setMinimumSize(48,48)
  56.     l.setMaximumSize(48,48)
  57.     self.imgLabel = l
  58.      
  59.     l = Plasma.Label(self.app.applet)
  60.     l.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
  61.     l.setMinimumSize(170,48)
  62.     l.setMaximumSize(170,48)
  63.     #l.setAutoFillBackground(True)
  64.     #l.setStyleSheet("QLabel {background: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #eef, stop: 1 #ccf); padding: 1px;border-style: solid;border: 2px solid black;border-radius: 8px;}")
  65.     #l.setAutoFillBackground(True)
  66.     self.label = l
  67.  
  68.     l = Plasma.Label(self.app.applet)  
  69.     l.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
  70.     l.setMinimumSize(80,48)
  71.     l.setMaximumSize(80,48)
  72.     #l.setAutoFillBackground(True)
  73.     #l.setStyleSheet("QLabel {background: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #eef, stop: 1 #ccf); padding: 1px;border-style: solid;border: 2px solid black;border-radius: 8px;}")
  74.     #l.setAutoFillBackground(True)
  75.     self.dateLabel = l
  76.  
  77.     p = Plasma.PushButton(self.app.applet)
  78.     icon23 = QIcon()
  79.     icon23.addPixmap(QPixmap(self.app.applet.package().filePath("ui","remove.png")), QIcon.Normal, QIcon.Off)
  80.     p.setIcon(icon23)
  81.     p.setEnabled(False)
  82.     p.setMinimumSize(48,48)
  83.     p.setMaximumSize(48,48)
  84.     p.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)  
  85.     self.removeButton = p
  86.     self.busyWidget = Plasma.BusyWidget()
  87.     self.busyWidget.setRunning(True)  
  88.  
  89.     self.imgLabelContainer = QGraphicsAnchorLayout ()
  90.     self.imgLabelContainer.addAnchor(self.imgLabel,Qt.AnchorVerticalCenter,self.removeButton,Qt.AnchorVerticalCenter)
  91.     self.imgLabelContainer.addAnchor(self.imgLabel,Qt.AnchorVerticalCenter,self.busyWidget,Qt.AnchorVerticalCenter)
  92.  
  93.    
  94.     self.containerLayout = QGraphicsLinearLayout(Qt.Horizontal)
  95.     self.containerLayout.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Minimum)
  96.     self.containerLayout.addItem(self.imgLabelContainer)
  97.     self.containerLayout.addItem(self.label)
  98.     self.containerLayout.addItem(self.dateLabel)
  99.     self.containerLayout.setSpacing(0)
  100.    
  101.     self.container = Plasma.Frame()
  102.     self.container.setLayout(self.containerLayout)
  103.     self.container.setContentsMargins(0,0,0,0)
  104.     self.container.setWindowFrameMargins(0,0,0,0)
  105.     QObject.connect(self.removeButton, SIGNAL("clicked()"), self.destroy)        
  106.  
  107.   def setEdit(self, t):
  108.     if not t:
  109.       self.removeButton.setEnabled(False)
  110.       self.removeButton.setVisible(False)
  111.     else:
  112.       self.removeButton.setEnabled(True)
  113.       self.removeButton.setVisible(True)
  114.      
  115.  
  116.   def destroy(self):
  117.     print "destroy"
  118.     self.label.close()
  119.     self.imgLabel.close()
  120.     self.dateLabel.close()
  121.     self.container.close()
  122.    
  123.     # delete show
  124.     for s in self.app.shows:
  125.       if s == self:
  126.         print "removing %s" % self.showName
  127.         self.app.shows.remove(s)
  128.         self.app.update()
  129.         self.app.saveShows()
  130.         self.quit()
  131.  
  132.   def outputElements(self):
  133.     return self.container
  134.  
  135.  
  136.   def get(self):
  137.     self.begin()
  138.    
  139.     print "Preparing http"
  140.     print self.showUrl.host()
  141.     self.http = QHttp(self.showUrl.host());
  142.     self.infoBuffer = QBuffer()
  143.     self.http.get(self.showUrl.path(), self.infoBuffer)
  144.     QObject.connect(self.http, SIGNAL("done(bool)"), self.fetchedInfo)  
  145.    
  146.     return True
  147.  
  148.  
  149.   def getImage(self):
  150.     if self.imageUrl == None:
  151.       return
  152.        
  153.  
  154.     if (QFile.exists(self.imageLocal)):
  155.       print "Local copy of image found for '%s'" % self.showName
  156.       self.imageBuffer = QFile(self.imageLocal)
  157.       self.http = None
  158.       self.fetchedImage(False)
  159.       return
  160.  
  161.     print "Preparing http request for image retrieval 'http://%s%s'" % (self.imageUrl.host(),self.imageUrl.path())
  162.     self.http = QHttp(self.imageUrl.host());
  163.     self.imageBuffer = QFile(self.imageLocal)
  164.     if not self.imageBuffer.open(QIODevice.WriteOnly):
  165.       print "Can't open '%s' for writing" % self.imageLocal
  166.       return
  167.      
  168.     self.http.get(self.imageUrl.path(), self.imageBuffer)
  169.     QObject.connect(self.http, SIGNAL("done(bool)"), self.fetchedImage)  
  170.  
  171.  
  172.   def fetchedImage(self,error):
  173.     filename = self.imageBuffer.fileName()
  174.     print "fetched image '%s'" % filename
  175.     self.updateImage(filename)
  176.     if not self.http == None:
  177.       self.http.close();
  178.     self.imageBuffer.close();
  179.     self.end()
  180.  
  181.   def begin(self):
  182.     self.busy = True
  183.     self.busyWidget.setRunning(True)
  184.     self.busyWidget.setVisible(True)
  185.    
  186.   def end(self,bypassFlag=False):    
  187.     self.busyWidget.setRunning(False)
  188.     self.busyWidget.setVisible(False)
  189.     if not bypassFlag:
  190.       self.busy = False
  191.    
  192.   def fetchedInfo(self, error):
  193.     print "Got a Http response"
  194.     html = str(self.infoBuffer.data())
  195.    
  196.     # got a http respose, now let's parse it
  197.     soup = BeautifulSoup(html)
  198.    
  199.     numFields = 6
  200.     newEpisode = [ None for i in xrange(numFields)]
  201.     prevEpisode = [ None for i in xrange(numFields)]
  202.     self.fetchOkay = False
  203.  
  204.     # get episode infos
  205.     h2Tags = soup.findAll('h2')  
  206.     for h in h2Tags:
  207.       print h
  208.       # get new episode infos
  209.       matchObj = re.match(r'.*Next: <a.*>([0-9]*)x([0-9]*).--.(.*)</a>.\((.*)\/(.*)\/(.*)\) ', str(h), re.M|re.I)
  210.       if matchObj:
  211.           newEpisode = matchObj.groups()
  212.           fetchOkay = True
  213.           continue
  214.      
  215.       # get previous episode infos
  216.       matchObj = re.match(r'.*Prev: <a.*>([0-9]*)x([0-9]*).--.(.*)</a>.\((.*)\/(.*)\/(.*)\) ', str(h), re.M|re.I)
  217.       if matchObj:
  218.           prevEpisode = matchObj.groups()
  219.           print "matched prev"
  220.           self.fetchOkay = True
  221.           continue
  222.        
  223.       # check if last episode aired?
  224.       matchObj = re.match(r'.*Final: <a.*>([0-9]*)x([0-9]*).--.(.*)</a>.\((.*)\/(.*)\/(.*)\) ', str(h), re.M|re.I)
  225.       if matchObj:
  226.           prevEpisode = matchObj.groups()
  227.           print "matched prev"
  228.           self.finalEpisode = True
  229.           self.fetchOkay = True
  230.           continue
  231.  
  232.    
  233.     # check if we got valid data or not
  234.     if not self.fetchOkay and self.app.loaded and self.app.initialized:
  235.       KMessageBox.messageBox(None, KMessageBox.Information, "Show '%s' can't be found, sorry!" % self.showName)
  236.       print "fetch wasn't valid"
  237.       self.destroy()
  238.       return False
  239.  
  240.  
  241.     # get image info, since we already scanned anyway
  242.     imgTags = soup.findAll('img', {'src' : re.compile(r'(.*shows.*)(jpe?g)|(png)$')})
  243.     for i in imgTags:
  244.       matchObj =  re.match(r'.*src..(.*shows.*).jpg.*>', str(i))
  245.       if matchObj:
  246.         imgSrc = matchObj.group(1)
  247.         continue
  248.     self.imageUrl = QUrl(imgSrc+".jpg")
  249.    
  250.     # start image retrieval
  251.     self.getImage()
  252.  
  253.     # use the time that it takes to get the image for assignment of the fetched info
  254.     self.ntime = None
  255.     self.ptime = None
  256.     self.title = None
  257.     self.ntimestamp = float(sys.maxint)
  258.  
  259.     self.ptimestamp = None
  260.  
  261.     # title
  262.     self.title = newEpisode[2]
  263.  
  264.     monthNum = {'Feb': 2, 'Aug': 8, 'Jan': 1, 'Dec': 12, 'Oct': 10, 'Mar': 3, 'Sep': 9, 'May': 5, 'Jun': 6, 'Jul': 7, 'Apr': 4, 'Nov': 11}
  265.     # time new episode
  266.     day = newEpisode[3]
  267.     month = newEpisode[4]
  268.     year = newEpisode[5]
  269.     if not (day==None and month==None and year==None):
  270.       datestring = "%s %s %s" % (monthNum[day], month, year)
  271.       self.ntime = time.strptime(datestring,"%m %d %Y")
  272.       self.ntimestamp = time.mktime(self.ntime)
  273.  
  274.     # time prev episode
  275.     day = prevEpisode[3]
  276.     month = prevEpisode[4]
  277.     year = prevEpisode[5]
  278.     if not (day==None and month==None and year==None):
  279.       datestring = "%s %s %s" % (monthNum[day], month, year)
  280.       self.ptime = time.strptime(datestring,"%m %d %Y")
  281.       self.ptimestamp = time.mktime(self.ptime)
  282.      
  283.     print self.ptime
  284.     self.updateText()
  285.  
  286.   def updateImage(self, filename):
  287.     self.imgLabel.nativeWidget().setPixmap(QPixmap(filename).scaled(48,48))
  288.    
  289.   def updateText(self):
  290.    
  291.     if self.title == None:
  292.       ntitle="TBA"
  293.     else:
  294.       ntitle=self.title
  295.      
  296.     if self.finalEpisode:
  297.       ntitle="no more episodes"
  298.  
  299.     self.label.setText(" " \
  300.           "<b>%(name)s</b><br>%(title)s" % dict(name=self.showName.replace("_"," "), title=ntitle))
  301.          
  302.     if self.ntime == None:
  303.       ntimestr = "TBA"
  304.     elif time.strftime("%d. %b %y",self.ntime) == time.strftime("%d. %b %y",time.localtime()):
  305.       ntimestr = "Today"
  306.     else:
  307.       ntimestr = time.strftime("%d. %b %y",self.ntime)
  308.  
  309.     if self.finalEpisode:
  310.       ntimestr="finished"
  311.  
  312.     self.dateLabel.setText(" " \
  313.           "<span style=\"color:#1245aa; font-weight:bold;\">%(ntime)s</span><br><span style=\"font-size:7pt;color:#1245aa;\">%(ptime)s</span>" % dict(name=self.showName, \
  314.             ntime=ntimestr, \
  315.             ptime=time.strftime("%d. %b %y",self.ptime) if not self.ptime == None else "n/a", \
  316.             ))    
  317.  
  318. class AirdatePlasmoidApplet(plasmascript.Applet):
  319.  
  320.   def __init__(self,parent,args=None):
  321.     plasmascript.Applet.__init__(self,parent)
  322.  
  323.  
  324.   def init(self):  
  325.     self.__initGui()
  326.     self.setEnabled(False)
  327.     self.firstRun = True
  328.     self.loaded = False
  329.     self.initialized = False
  330.     self.needsInitRefetch = True
  331.     self.timeEngine = self.dataEngine("time")
  332.     self.timeEngine.connectSource("Local", self, 1000)
  333.     self.firstRun = False
  334.  
  335.  
  336.   def __initGui(self):
  337.     self.setAspectRatioMode(Plasma.IgnoreAspectRatio)
  338.     self.setSizePolicy(QSizePolicy.Preferred,QSizePolicy.Preferred)
  339.     self.setMinimumSize(370,250)
  340.     # No configuration interface supported
  341.     self.setHasConfigurationInterface(False)
  342.     self.layout = QGraphicsLinearLayout(Qt.Vertical, self.applet)
  343.     self.setLayout(self.layout)
  344.  
  345.     # setup gui  
  346.     self.scrollArea = Plasma.ScrollWidget()
  347.     self.frame = Plasma.Frame()
  348.     self.frame.setLayout(QGraphicsLinearLayout(Qt.Vertical))
  349.     self.scrollArea.setWidget(self.frame)
  350.    
  351.     self.outputLayout = self.frame.layout()
  352.     self.outputLayout.setSpacing(0)
  353.     self.layout.addItem(self.scrollArea)
  354.  
  355.     self.controlLayout = QGraphicsLinearLayout(Qt.Horizontal)
  356.     self.controlLayout.setSizePolicy(QSizePolicy.Preferred,QSizePolicy.Preferred)  
  357.     self.layout.addItem(self.controlLayout)
  358.  
  359.     self.showUrl = Plasma.LineEdit(self.applet)
  360.     self.controlLayout.addItem(self.showUrl)
  361.     self.showUrl.setEnabled(False)
  362.     self.addButton = Plasma.PushButton(self.applet)
  363.     icon23 = QIcon()
  364.     icon23.addPixmap(QPixmap(self.applet.package().filePath("ui","add.png")), QIcon.Normal, QIcon.Off)
  365.     self.addButton.setIcon(icon23)
  366.     self.addButton.setMinimumSize(24,24)
  367.     self.addButton.setMaximumSize(24,24)
  368.     self.addButton.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)  
  369.     self.addButton.setEnabled(False)
  370.     self.controlLayout.addItem(self.addButton)
  371.     QObject.connect(self.addButton, SIGNAL("clicked()"), self.addShow)        
  372.  
  373.  
  374.     self.updateButton = Plasma.PushButton(self.applet)
  375.     self.updateButton.setMinimumSize(24,24)
  376.     self.updateButton.setMaximumSize(24,24)
  377.     self.updateButton.setEnabled(False)
  378.     icon23 = QIcon()
  379.     icon23.addPixmap(QPixmap(self.applet.package().filePath("ui","reload.png")), QIcon.Normal, QIcon.Off)
  380.     self.updateButton.setIcon(icon23)
  381.     self.updateButton.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)  
  382.     self.controlLayout.addItem(self.updateButton)
  383.     QObject.connect(self.updateButton, SIGNAL("clicked()"), self.refetch)  
  384.    
  385.     self.editButton = Plasma.PushButton(self.applet)
  386.     self.editButton.setEnabled(False)
  387.     self.editButton.setMinimumSize(24,24)
  388.     self.editButton.setMaximumSize(24,24)
  389.     self.editButton.setCheckable(True)
  390.     icon23 = QIcon()
  391.     icon23.addPixmap(QPixmap(self.applet.package().filePath("ui","edit.png")), QIcon.Normal, QIcon.Off)
  392.     self.editButton.setIcon(icon23)
  393.     self.editButton.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)  
  394.     self.controlLayout.addItem(self.editButton)
  395.     QObject.connect(self.editButton, SIGNAL("clicked()"), self.editShows)
  396.  
  397.  
  398.   def editShows(self):
  399.     if self.editButton.isChecked():
  400.       self.addButton.setEnabled(True)
  401.       self.showUrl.setEnabled(True)
  402.      
  403.       for s in self.shows:
  404.         s.setEdit(True)
  405.     else:
  406.       self.addButton.setEnabled(False)
  407.       self.showUrl.setEnabled(False)
  408.  
  409.       for s in self.shows:
  410.         s.setEdit(False)
  411.      
  412.   def addShow(self):
  413.     self.setEnabled(False)
  414.     showName = self.showUrl.text()
  415.     print "adding show %s" % showName
  416.  
  417.     for sd in self.shows:
  418.       if str(sd.showName).lower() == str(showName).lower():
  419.         print "show is already there!!"
  420.         return
  421.        
  422.     newShowDesc = ShowDesc(self,showName)
  423.     newShowDesc.setEdit(self.editButton.isChecked())
  424.     if newShowDesc.get():
  425.       self.shows.append(newShowDesc)
  426.       self.outputLayout.addItem(newShowDesc.outputElements())
  427.       self.saveShows()
  428.      
  429.     # switch to watch mode
  430.     self.timeEngine.connectSource("Local",self,1000)
  431.  
  432.  
  433.   def saveShows(self):
  434.     settings = QSettings("Airdate-Plasmoid","Airdate-Plasmoid")
  435.     showNames = [ s.showName for s in self.shows ]
  436.     settings.setValue("shows", showNames)
  437.  
  438.     showTitles = [ s.title for s in self.shows ]
  439.     settings.setValue("titles", showTitles)
  440.     showNTimestamps = [ s.ntimestamp for s in self.shows ]
  441.     print showNTimestamps
  442.     settings.setValue("ntimestamps", showNTimestamps)
  443.     showPTimestamps = [ s.ptimestamp for s in self.shows ]
  444.     settings.setValue("ptimestamps", showPTimestamps)
  445.    
  446.   def output(self):      
  447.     print "updating output"
  448.  
  449.     # sort shows:
  450.     self.shows = sorted(self.shows, key=lambda ShowDesc: ShowDesc.ntimestamp, reverse=False)
  451.     for i,s in enumerate(self.shows):
  452.       self.outputLayout.addItem(s.outputElements())
  453.  
  454.   def update(self):
  455.     removeList = []
  456.     for i in range(self.outputLayout.count()):
  457.       if not self.outputLayout.itemAt(i).graphicsItem().isVisible():
  458.         removeList.append(i)
  459.         print "not visible!"
  460.        
  461.     for i in removeList:
  462.       self.outputLayout.removeAt(i)
  463.  
  464.   def isConnectedToInternet(self):
  465.     try:
  466.         response=urllib2.urlopen('http://www.tvrage.com',timeout=2)
  467.         return True
  468.     except urllib2.URLError as err: pass
  469.    
  470.     return False
  471.  
  472.   def refetch(self):
  473.     self.setEnabled(False)
  474.     self.updateButton.setEnabled(False)
  475.    
  476.     if not self.isConnectedToInternet():
  477.       print "not connected to internet"
  478.       self.needsInitRefetch = True
  479.      
  480.       if self.loaded:
  481.         self.loaded=False
  482.         print "switching to watch mode"
  483.         self.timeEngine.connectSource("Local",self,1000)       
  484.        
  485.       for sd in self.shows:
  486.         sd.end(bypassFlag=True)
  487.       return False
  488.      
  489.  
  490.     for i,sd in enumerate(self.shows):
  491.       sd.get()
  492.  
  493.     # switch to watch mode  
  494.     if self.loaded:
  495.       print "switching to watch mode"
  496.       self.timeEngine.connectSource("Local",self,1000)
  497.      
  498.     return True
  499.  
  500.   def isEverythingFetched(self):
  501.      for s in self.shows:
  502.         if s.busy == True:
  503.           return False
  504.          
  505.      return True
  506.  
  507.   @pyqtSignature("dataUpdated(const QString &, const Plasma::DataEngine::Data &)")
  508.   def dataUpdated(self, sourceName, data):
  509.     if self.firstRun:
  510.       return
  511.  
  512.     print "Status: init %s | needinitrefetch %s | loaded %s | internet %s" % (str(self.initialized), str(self.needsInitRefetch), str(self.loaded), self.isConnectedToInternet())
  513.    
  514.     if not self.initialized:
  515.       print "\tInitialising"
  516.       # load settings
  517.       settings = QSettings("Airdate-Plasmoid","Airdate-Plasmoid")
  518.       nstamps = settings.value("ntimestamps").toList()
  519.       pstamps = settings.value("ptimestamps").toList()
  520.       titles = settings.value("titles").toList()
  521.       shows = settings.value("shows").toList()
  522.       self.shows = []
  523.      
  524.       for s in shows:
  525.         sd = ShowDesc(self, s.toString().replace("_", " "))
  526.         self.shows.append(sd)
  527.        
  528.       self.initialized = True
  529.       self.needsInitRefetch = True
  530.     elif self.needsInitRefetch and self.initialized:
  531.       self.output()
  532.       self.loaded = self.refetch()
  533.       self.needsInitRefetch = not self.loaded
  534.     elif self.loaded and self.isEverythingFetched():
  535.       print "\teverything is fetched"
  536.       ## do sorting when everything is ready
  537.  
  538.       self.setEnabled(True)
  539.       #delete everything, now we can do some sorting!
  540.       for s in self.shows:
  541.         self.outputLayout.removeItem(s.outputElements())
  542.       #sort this ...
  543.       self.output()
  544.       # switch to more conservative mode
  545.       self.timeEngine.disconnectSource("Local",self)
  546.       self.editButton.setEnabled(True)
  547.       self.updateButton.setEnabled(True)
  548.       self.loaded = True
  549.     else:
  550.       print "\t skipped"
  551.  
  552.  
  553. def CreateApplet(parent):
  554.   return AirdatePlasmoidApplet(parent)