• 1
  • 2
  • 3(current)
  • 4
  • 5
  • 18
[RELEASE] SageTV recordings
#31
(2012-08-23, 22:16)kricker Wrote: I've made all the changes to the code so far and I'm going to push them up to github.

LehighBri,

Please note I moved the strURL variable declaration out of the def CATEGORIES(): section. This allows us to use it anywhere else in the code where we need the URL (like on line 130 for the delete command) and saves us from typing that long string out each time.

OK, sounds good. Keep me posted if there's any other enhancements you think we need to make and I'll keep looking into the date sorting piece.
Reply
#32
I've noticed sorting by title and switching from ascending to descending works when at the "episode" level, but not at the "series" level.
Reply
#33
Thanks to the wonderful Amet, sorting issues have been resolved. Github will be updated shortly.
Reply
#34
Hi Kricker - the more I play around with this plugin, the more I love it everyday! So simple, yet so useful.

BUT, found one issue (which has an easy fix). To mimic SageTV behavior, ideally the episode listing would show both completed AND partial recordings (aka live TV that is in the process of being recorded). The current implementation only shows completed.

Thus to show both completed and in flight recordings, can you update line 40 in the github and simply add the following phrase "&partials=both" to the URL that is formed (ignoring the quotation marks)? This should do it. Thanks!
Reply
#35
No problem. But can you confirm if you can play the partial recording? And what if you have various "live tv" partial recordings laying around. those will show up as well.
Reply
#36
Yes, you can play back live tv recordings while they are recording with no issues at all.
Reply
#37
Are you using a PVR build of XBMC? I just tried playing a currently recording stream and it failed.
Reply
#38
No. I'm using the Frodo alpha 4 build. But even before then, I think even with Eden normal build I was able to playback "growing" .mpg files.

http://mirrors.xbmc.org/snapshots/win32/

Can you try browsing through the file structure to play the file directory outside of the SageTV plugin to at least confirm that works first? (under Videos -> Files)
Reply
#39
Just tried it on a live recording and it works as advertised. Very nice. I am running the latest PVR version.
Reply
#40
Kricker et al - see below for an updated version of this plugin that includes the following:

1. Changed "All Shows" to "[All Shows]" so that this naturally sorts as the first item (above entries like "60 Minutes")
2. Added in my suggestion above around including partial (aka Live TV) recordings so you can watch live recordings
3. Added initial POSTER ART support (it needs to be expanded, but this is a start)... it should be noted that you must have the sagex JSON APIs installed to be able to get this to work

Test it out and let me know what you think. Would love to get this into the github at some point (or feel free to give me access and I can do myself if you like).

Enjoy!

Code (this is the entire default.py file):
Code:
import urllib,urllib2,re
import xbmc,xbmcplugin,xbmcgui,xbmcaddon
import os
import unicodedata
from xml.dom.minidom import parse

__settings__ = xbmcaddon.Addon(id='plugin.video.SageTV')
__language__ = __settings__.getLocalizedString
__cwd__      = __settings__.getAddonInfo('path')

# SageTV recording Directories for path replacement
sage_rec = __settings__.getSetting("sage_rec")
sage_unc = __settings__.getSetting("sage_unc")

# SageTV URL based on user settings
strUrl = 'http://' + __settings__.getSetting("sage_user") + ':' + __settings__.getSetting("sage_pass") + '@' + __settings__.getSetting("sage_ip") + ':' + __settings__.getSetting("sage_port")

def CATEGORIES():

        iconImage = xbmc.translatePath(os.path.join(__cwd__,'resources','media','icon.png'))
        addDir('[All Shows]', strUrl + '/sage/Recordings?xml=yes',2,iconImage)
        req = urllib.urlopen(strUrl + '/sage/Recordings?xml=yes')
        content = parse(req)
        dictOfTitlesAndMediaFileIds = {}
        for showlist in content.getElementsByTagName('show'):
          strTitle = ''
          strMediaFileId = ''
          for shownode in showlist.childNodes:
            # Get the title of the show
            if shownode.nodeName == 'title':
              strTitle = shownode.toxml()
              strTitle = strTitle.replace('<title>','')
              strTitle = strTitle.replace('</title>','')
              strTitle = strTitle.replace('&amp;','&')
              strTitle = strTitle.replace('&quot;','"')
              strTitle = unicodedata.normalize('NFKD', strTitle).encode('ascii','ignore')
            # Get the mediafileid of the show
            if shownode.nodeName == 'airing':
              for shownode1 in shownode.childNodes:
                if shownode1.nodeName == 'mediafile':
                  strMediaFileId = shownode1.getAttribute('sageDbId')
                  
            if(strTitle<>""):
                dictOfTitlesAndMediaFileIds[strTitle] = strMediaFileId
            
        for strTitle in dictOfTitlesAndMediaFileIds:
            urlToShowEpisodes = strUrl + '/sage/Search?searchType=TVFiles&SearchString=' + urllib2.quote(strTitle.encode("utf8")) + '&DVD=on&sort2=airdate_asc&partials=both&TimeRange=0&pagelen=100&sort1=title_asc&filename=&Video=on&search_fields=title&xml=yes'
            print "ADDING strTitle=" + strTitle + "; urlToShowEpisodes=" + urlToShowEpisodes
            imageUrl = strUrl + "/sagex/media/poster/" + dictOfTitlesAndMediaFileIds[strTitle]
            print "ADDING imageUrl=" + imageUrl
            addDir(strTitle, urlToShowEpisodes,2,imageUrl)

def VIDEOLINKS(url,name):
        #Videolinks gets called immediately after adddir, so the timeline is categories, adddir, and then videolinks
        #Videolinks then calls addlink in a loop
        #This code parses the xml link
        req = urllib.urlopen(url)
        content = parse(req)    
        for showlist in content.getElementsByTagName('show'):
          strTitle = ''
          strEpisode = ''
          strDescription = ''
          strGenre = ''
          strAirdate = ''
          strMediaFileID = ''
          for shownode in showlist.childNodes:
            # Get the title of the show
            if shownode.nodeName == 'title':
              strTitle = shownode.toxml()
              strTitle = strTitle.replace('<title>','')
              strTitle = strTitle.replace('</title>','')
              strTitle = strTitle.replace('&amp;','&')
            # Get the episode name
            if shownode.nodeName == 'episode':
              strEpisode = shownode.toxml()
              strEpisode = strEpisode.replace('<episode>','')
              strEpisode = strEpisode.replace('</episode>','')
              strEpisode = strEpisode.replace('&amp;','&')
            # Get the show description
            if shownode.nodeName == 'description':
              strDescription = shownode.toxml()
              strDescription = strDescription.replace('<description>','')
              strDescription = strDescription.replace('</description>','')
              strDescription = strDescription.replace('&amp;','&')
            # Get the category to use for genre
            if shownode.nodeName == 'category':
              strGenre = shownode.toxml()
              strGenre = strGenre.replace('<category>','')
              strGenre = strGenre.replace('</category>','')
              strGenre = strGenre.replace('&amp;','&')
            # Get the airdate to use for Aired
            if shownode.nodeName == 'originalAirDate':
              strAirdate = shownode.toxml()
              strAirdate = strAirdate.replace('<originalAirDate>','')
              strAirdate = strAirdate.replace('</originalAirDate>','')
              strAirdate = strAirdate[:10]
              # now that we have the title, episode, genre and description, create a showname string depending on which ones you have
              # if there is no episode name use the description in the title
            if len(strEpisode) == 0:
              strShowname = strTitle+' - '+strDescription
              strPlot = strDescription
              # else if there is an episode use that
            elif len(strEpisode) > 0:
              if name == 'All Shows' or name == 'Sports':
                strShowname = strTitle+' - '+strEpisode
              elif name != 'All Shows' and name != 'Sports':
                strShowname = strEpisode
              strPlot = strDescription
            if shownode.nodeName == 'airing':
              for shownode1 in shownode.childNodes:
                if shownode1.nodeName == 'mediafile':
                  strMediaFileID = shownode1.getAttribute('sageDbId')
                  for shownode2 in shownode1.childNodes:
                    if shownode2.nodeName == 'segmentList':
                      shownode3 =  shownode2.childNodes[1]
                      strFilepath = shownode3.getAttribute('filePath')
                      addLink(strShowname,strFilepath.replace(sage_rec, sage_unc),strPlot,'',strGenre,strAirdate,strTitle,strMediaFileID)

def get_params():
        param=[]
        paramstring=sys.argv[2]
        if len(paramstring)>=2:
                params=sys.argv[2]
                cleanedparams=params.replace('?','')
                if (params[len(params)-1]=='/'):
                        params=params[0:len(params)-2]
                pairsofparams=cleanedparams.split('&')
                param={}
                for i in range(len(pairsofparams)):
                        splitparams={}
                        splitparams=pairsofparams[i].split('=')
                        if (len(splitparams))==2:
                                param[splitparams[0]]=splitparams[1]
                                
        return param

def addLink(name,url,plot,iconimage,genre,airdate,showtitle,fileid):
        ok=True
        liz=xbmcgui.ListItem(name)
        strDelete = strUrl + '/sagex/api?command=DeleteFile&1=mediafile:' + fileid
        liz.addContextMenuItems([('Delete Show', 'PlayMedia(' + strDelete + ')',)])
        datesplit = airdate.split('-')
        try:
            date = datesplit[2]+'.'+datesplit[1]+'.'+datesplit[0]
        except:
            date = "01.01.1900"
        liz.setInfo( type="Video", infoLabels={ "Title": name, "Plot": plot, "Genre": genre, "date": date, "aired": airdate, "TVShowTitle": showtitle } )
        ok=xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=liz,isFolder=False)
        return ok


def addDir(name,url,mode,iconimage):
        u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)
        ok=True
        liz=xbmcgui.ListItem(name)
        liz.setInfo(type="video", infoLabels={ "Title": name } )
        liz.setIconImage(iconimage)
        liz.setThumbnailImage(iconimage)
        #liz.setIconImage(xbmc.translatePath(os.path.join(__cwd__,'resources','media',iconimage)))
        #liz.setThumbnailImage(xbmc.translatePath(os.path.join(__cwd__,'resources','media',iconimage)))
        ok=xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
        return ok
        
              
params=get_params()
url=None
name=None
mode=None

try:
        url=urllib.unquote_plus(params["url"])
except:
        pass
try:
        name=urllib.unquote_plus(params["name"])
except:
        pass
try:
        mode=int(params["mode"])
except:
        pass

if mode==None or url==None or len(url)<1:
        print ""
        CATEGORIES()
      
elif mode==1:
        print ""+url
        INDEX(url)
        
elif mode==2:
        print ""+url
        VIDEOLINKS(url,name)

xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE)
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_TITLE)
xbmcplugin.setContent(int(sys.argv[1]),'episodes')
xbmcplugin.endOfDirectory(int(sys.argv[1]))
Reply
#41
Just got a chance to try the new version with poster art while dodging Hurricane Isaac. Really really cool. It would be extremely nice if there would be a way to set the default view to 'Media Info' when entering each show's folder. I did a search to see if this was somehow settable, but I wasn't able to find it. With that exception, this plugin is pretty darn awesome.

*EDIT* Looks like you can set the view using 'Container.SetViewMode(id)' . Not too sure how to find the id value for 'Media Info' though. I'll keep looking.
Reply
#42
(2012-08-29, 20:24)dinki Wrote: *EDIT* Looks like you can set the view using 'Container.SetViewMode(id)' . Not too sure how to find the id value for 'Media Info' though. I'll keep looking.

Good find. I noticed on the site below there are various built in functions we can try to us... SetViewMode or even things like SortDirection, etc.

http://wiki.xbmc.org/index.php?title=Lis..._functions

In reading around the forums though, it sounds like SetViewMode's ids are skin-dependent and could vary across skins. Like you, I would love it if the "show" level could have one view and then the "episode" level could have a consistent view and not be different per show. Have you found anything else in the forums that would help us? Thanks for continuing to look!
FYI... Kricker just gave me access to the github so I just checked in the code from post #40.
Reply
#43
So it appears the dates are a bit screwy still. I think we need to make a change. Right now it is using original air date. Not every show has this so a fake date of "01.01.1900" is used. If you are viewing the "All Shows" list, the date sort will not be in order of when they were recorded, but the original air date if it was available. I'm thinking we need to use the dates differently if possible. The date the show is recorded should be the 'date' and the original air date if available should be just that "original air date". Then we have two dates to sort from. The recorded date and the original air date.

Also the "All Shows" category only shows the episode name. It should have the series name in front of that I think, if possible.
Reply
#44
(2012-08-29, 22:40)kricker Wrote: So it appears the dates are a bit screwy still. I think we need to make a change. Right now it is using original air date. Not every show has this so a fake date of "01.01.1900" is used. If you are viewing the "All Shows" list, the date sort will not be in order of when they were recorded, but the original air date if it was available. I'm thinking we need to use the dates differently if possible. The date the show is recorded should be the 'date' and the original air date if available should be just that "original air date". Then we have two dates to sort from. The recorded date and the original air date.

Also the "All Shows" category only shows the episode name. It should have the series name in front of that I think, if possible.

Thanks for testing this. I just fixed both and checked the updated code into the github.

-Updating airdate to be mapped to Sage's recording date and not the original air date (this is because all recordings have a recorded date but may not have an original air date)
-Fixed bug where choosing [All Shows] did not show the show name in the episode list

https://github.com/kricker/plugin.video.SageTV

EDIT: To clarify the date mapping piece, it doesn't support two dates yet. For now, the airdate in XBMC uses the RECORDING date from SageTV. Need to look into how we support multiple date fields (thoughts?)
Reply
#45
Wow, I've been away but looks like a lot of cool stuff happening with this now. Thanks guys
Reply
  • 1
  • 2
  • 3(current)
  • 4
  • 5
  • 18

Logout Mark Read Team Forum Stats Members Help
[RELEASE] SageTV recordings2