Advertisement
Guest User

fysa

a guest
Feb 13th, 2009
277
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 30.37 KB | None | 0 0
  1. #!/usr/bin/env python
  2. #encoding:utf-8
  3.  
  4. import urllib
  5. import xml.dom.minidom
  6. import re
  7. import time
  8. import os
  9. import sys                                        
  10. import string
  11.  
  12. from tvdb_api import (tvdb_error, tvdb_shownotfound, tvdb_seasonnotfound,
  13.     tvdb_episodenotfound, tvdb_episodenotfound, tvdb_attributenotfound, tvdb_userabort)
  14. from tvdb_api import Tvdb
  15.  
  16. ######
  17. # TV #
  18. ######
  19.  
  20. __author__ = "minimad/Neil"
  21. __version__ = "0.88"
  22.  
  23. ################################### MEGA IMPORTANT ##################################################
  24. #
  25. # This script also requires the tvdb_api from http://github.com/dbr/tvdb_api/tree/master
  26. # you will require ALL the files (well, maybe not the setup.py) and they need to be in the same dir
  27. # as this script
  28. #
  29. # Expected Show format is (Showname/Season XX/Showname - SxxExx - Episodename.ext e.g.
  30. # House/Season 02/House - S02E01 - Autopsy.avi
  31. #
  32. ################################### MEGA IMPORTANT ##################################################
  33.  
  34. ################################### CHANGE LOG ######################################################
  35. #
  36. # 090103 1600   Now uses SAB 0.4.6 illegal character replacement behaviour
  37. #
  38. # 090112 2300   Uses tvdb_api to validate show name
  39. #
  40. # 090114 2300   Cleaned up the code, used re.pattern in print statements where possible
  41. #               and tried to limit number of places to change for new formats by using vars
  42. #
  43. # 090117 2300   Fixed bug - Queued name is meant to be original report, NOT reformated version
  44. #
  45. # 090117 2330   Added required video format functionality
  46. #
  47. # 090117 2345   Moved Season/Episode regex formats to user config area
  48. #
  49. # 090120 2045   Added Debug setting for 'print' statements
  50. #               Fixed IsMissing regex to look for both cases of S and E i.e. s and S
  51. #               Fixed season_to_check variable
  52. #               A few wording changes
  53. #
  54. # 090121 2330   Made 'Smart' queue optional
  55. #               Removing Illegal Chars at end of cleanSeriesName if Win32
  56. #               Moved Format check into isWanted.  Check format before checking for show.
  57. #               Should reduce processing time by not checking all shows then finding out that format isn't wanted
  58. #               Removed sum_file_size function as not
  59. #
  60. # 090122 0015   Added 'extra' debug messages
  61. #               Fixed 'Smart' Queue
  62. #               Moved Change Log to Top of Script
  63. #               Added 'Known Issues'
  64. #               Made Code more consistant
  65. #
  66. # 090122 2200   Fixed 'isMissing', left a test string in place, so it always thought you needed the episode
  67. #               Also it 'bombed' out because I left an icorrectly anmed variable in
  68. #
  69. # 090123 2200   Added option to choose SABnzbd style or tvnamer.py style, illegal character replacement
  70. #               Added option to force Windows compliant names, useful if you run this on a linux box but access via windows
  71. #               Now we reformat a NewzBin into the same format as a 'non' newzbin feed, Smart Queue should work better now
  72. #               Added an 'Aliases' function to trasnlate known 'Aliases' into proper show names, at least until the tvdb_api has
  73. #               this functionality which is due in the next few weeks
  74. #
  75. # 090124 0015   'Smart' queue wasn't being smart, it was still checking filename against a reformated string, now fixed
  76. #               However the script is considerably slower due to the number of calls to tvdb_api, now once per queue entry per queue check
  77. #
  78. # 090124 2300   Fixed NewzBin adding to queue, was trying to add entire url (thanks markus101).
  79. #
  80. # 090125 0935   New Function, isInHistorySmart (ONLY 0.5.0 onwards), checks the history for the show, episode
  81. #               NOT COMPLETE, NOT ACTIVE IN CODE
  82. #
  83. # 090125 2200  0.80 NEW FEATURE - Per Show AND Season Format Matching.  Only get the format specified for the show and season
  84. #
  85. # 090126 1430  0.81 Should find files in ANY supported format (supported formats in Importnat Info section), no need to rename files
  86. #
  87. # 090126 2330       MAJOR Code Cleanup. Most probably broke everything.
  88. #
  89. # 090127 1100  0.82 Fixed - MATCH FOUND now returns the Season & Episode rather than the regex pattern that found it
  90. #                   (regex pattern looks like gibberish
  91. #                   Fixed - General Format Matching - I had changed the regex, now back to what it was.
  92. #
  93. # 090128 2220  0.84 Multiple Feed Functionality, Script now smart enough to know a newzbin feed
  94. #                   Fixed - NewzBin format check
  95. #
  96. # 090206 2050  0.88 Changed way isWanted looks for a show, it now loops through the tvdirs checking a lowercase
  97. #                   dir against a lowercase series_title
  98. #
  99. #
  100. ################################### CHANGE LOG ######################################################
  101.  
  102. ################################### KNOWN ISSUES ####################################################
  103. #
  104. # Script is too fast and gets 'Trying to fetch NZB from.....' in the Queue.  'Smart' queue and 'Normal' Queue
  105. # are unable to check show, episode or filename in this instance so they assume it isn't in the queue.
  106. #
  107. # This script is UNABLE to process feeds that are gzip'd, TVBINZ etc are now using gzip'd feeds
  108. # Use www.feedburner.com to turn them back into 'raw' feeds.
  109. #
  110. # Seems to have a problem with shows that have a : (colon) in them e.g. CSI: Miami, CSI: NY etc
  111. #
  112. ################################### KNOWN ISSUES ####################################################
  113.  
  114. ################################### TO DO (NOT IN ORDER) ############################################
  115. #
  116. # Improve script speed, All those tvdb_api calls, REALLY slows it down, maybe cache the answers????
  117. # Have config settings in another file.
  118. #
  119. ################################### TO DO ###########################################################
  120.  
  121.  
  122. ################################### IMPORTANT INFO ##################################################
  123. #  To ignore a whole season, create a file or directory in the directory for your show with this name
  124. #  ignore Season x
  125. #  e.g. c:\tv\lost\ignore Season 1
  126. #
  127. #  To use Per Show and Season format matching, create a file or directory in the SHOW directory with
  128. #  name format Sxx.yyyy.format
  129. #  Where xx is the season number
  130. #  Where yyyy is the format, either xvid or x264
  131. #  e.g. S01.xvid.format
  132. #       S02.x264.format
  133. #
  134. #  Supported File Naming Formats:-
  135. #
  136. #  seriesname.s01e02.dsr.nf.avi
  137. #  seriesname.S01E02.PROPER.dsr.nf.avi
  138. #  seriesname.s01.e02.avi
  139. #  seriesname-s01e02.avi
  140. #  seriesname-s01e02.the.wrong.ep.name.avi
  141. #  seriesname - [01x02].avi
  142. #  seriesname - [01x002].avi
  143. #  seriesname-[01x02].avi
  144. #  seriesname [01x02].avi
  145. #  seriesname [01x02] epname.avi
  146. #  seriesname [01x02] - the wrong ep name.avi
  147. #  seriesname - [01x02] - the wrong ep name.avi
  148. #  seriesname.01x02.epname.avi
  149. #  seriesname.102.epname.avi
  150. #  seriesname_s1e02_epname.avi
  151. #  seriesname - s01e02 - dsr.nf.avi
  152. #  seriesname - s01e02 - the wrong ep name.avi
  153. #  seriesname - s01e02 - the_wrong_ep_name!.avi
  154. #
  155. ################################### IMPORTANT INFO ##################################################
  156.  
  157. #################################### CHANGE TO YOUR OWN VALUES ######################################
  158. #
  159. # set this to the location of your downloads.  the first entry must be your live download area
  160. if sys.platform == "win32":
  161.     tv_dirs=[ "Z:" ]
  162. else:
  163.     tv_dirs=[ "/share/Qmultimedia/TV_Shows" ]
  164.  
  165. # the RSS link to your search
  166. nzbfeeds=[
  167. "http://myfeed.rss",
  168. "http://feeds.feedburner.com/minimad-csi"
  169. ]
  170.  
  171. # your SABNZB address
  172. my_SAB="http://192.168.1.200:8800"
  173. # /sabnzbd is added below
  174.  
  175. # additional SAB parameters to e.g. specify the category, and/or script to run.  see http://sabnzbd.wikidot.com/automation-support
  176. my_SAB_params="&cat=tv"
  177.  
  178. # Use NewzBin feed
  179. # Changes several sections to use NewzBin specific functionality
  180. # NO LONGER USED, Script is Mart enough to know a NewzBin feed when it sees it
  181. # becuase the feed has newzbin in the url e.g. http://www.newzbin.com
  182. #NewzBin = False
  183.  
  184. # theTVDB api
  185. # Set tvdb_interactive=True to select shows returned, otherwise it takes first show returned (usually the right one)
  186. tvdb_interactive=False
  187.  
  188. # Required video formats
  189. # for x264 enter 'x264'
  190. # for xvid enter 'xvid'
  191. # for 720p enter '720p'
  192. # for 1080p enter '1080'
  193. # for multiple formats put | between them and brackets around each group e.g.
  194. # ([x264])|([xvid])
  195. #
  196. video_formats='x264'
  197.  
  198. # Season/Episode Formats
  199. # Standard Regex with brackets around each format and seperated by |
  200. season_formats="([sS][0-9][0-9])|([0-9]?[0-9][xX])"
  201. episode_formats="([eE][0-9][0-9])|([xX][0-9][0-9])"
  202.  
  203. # DEBUG
  204. # Set debug to True, to see what this scrip is doing
  205. debug = True
  206. # theTVDB api
  207. # Set tvdb_debug=True to see debug info from theTVDB api
  208. tvdb_debug=False
  209.  
  210. # 'Smart' Queue checking
  211. # Set to True to use 'Smart' Queue checking
  212. # Looks for the Show, Episode in Queue rather than the filename
  213. useSmartQueue = True
  214.  
  215. # SABnzbd or tvnamer.py style illegal char replaement
  216. # Set to True to use SABnzbd Style
  217. SABnzbdIllegalCharsStyle = False
  218.  
  219. # Force Windows Compliant Names
  220. # Set to True to force script to use windows compliant names
  221. force_windows_compliant_filenames = True
  222.  
  223. ################################### CHANGE TO YOUR OWN VALUES #####################################
  224.  
  225. config = {}
  226.  
  227. reportdict = {}
  228.  
  229. config['valid_filename_chars'] = """0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@£$%^&*()_+=-[]:{}"'.,<>`~? """
  230.  
  231. config['with_ep_name'] = '%(seriesname)s - S%(seasno)02dE%(epno)02d - %(epname)s'
  232.  
  233. # Force the stripping of invalid Windows characters, even if the current
  234. # platform is not detected as Windows
  235. config['force_windows_compliant_filenames'] = True
  236.  
  237. if sys.platform == "win32" or config['force_windows_compliant_filenames']:
  238.     # " * : < > ? | \ are all invalid on Windows
  239.     config['valid_filename_chars'] = config['valid_filename_chars'].replace("\"*:<>?|\\","")
  240.  
  241. config['valid_filename_chars_regex'] = re.escape(config['valid_filename_chars'])
  242.  
  243. # Regex's to parse filenames with. Must have 3 groups, seriesname, season number
  244. # and episode number. Use (?: optional) non-capturing groups if you need others.
  245. # taken from tvnamer.py script
  246. config['name_parse'] = [
  247.     # foo_[s01]_[e01]
  248.     re.compile('''^([%s]+?)[ \._\-]\[[Ss]([0-9]+?)\]_\[[Ee]([0-9]+?)\]?([%s]+)[^\\/]*$''' % (config['valid_filename_chars_regex'], config['valid_filename_chars_regex']) ),
  249.     # foo.1x09*
  250.     re.compile('''^([%s]+?)[ \._\-]\[?([0-9]+)x([0-9]+)([%s]+)[^\\/]*$''' % (config['valid_filename_chars_regex'], config['valid_filename_chars_regex']) ),
  251.     # foo.s01e01.title
  252.     re.compile('''^([%s]+?)[ \._\-][Ss]([0-9]+)[\.\- ]?[Ee]([0-9]+)[ \._\-]([%s]+)[^\\/]*$''' % (config['valid_filename_chars_regex'], config['valid_filename_chars_regex']) ),
  253.     # foo.s01.e01, foo.s01_e01, foo.s01e01
  254.     re.compile('''^([%s]+?)[ \._\-][Ss]([0-9]+)[\.\- ]?[Ee]([0-9]+)([%s]+)[^\\/]*$''' % (config['valid_filename_chars_regex'], config['valid_filename_chars_regex']) ),
  255.     # foo.103*
  256.     re.compile('''^([%s]+)[ \._\-]([0-9]{1})([0-9]{2})[\._ -]([%s]+)[^\\/]*$''' % (config['valid_filename_chars_regex'], config['valid_filename_chars_regex']) ),
  257.     # foo.0103*
  258.     re.compile('''^([%s]+)[ \._\-]([0-9]{2})([0-9]{2,3})[\._ -]([%s]+)[^\\/]*$''' % (config['valid_filename_chars_regex'], config['valid_filename_chars_regex']) ),
  259. ]
  260.  
  261.  
  262. # Class to allow an exception to be raised
  263. # if format is not wanted
  264. class FormatNotWanted:
  265.     pass
  266.  
  267. class formatError:
  268.     pass
  269.  
  270. # SABnzbd style illegal chars
  271. illegal = r'\/<>?*:;|"'
  272. legal   = r'++{}!@--#`'
  273. translate_table = string.maketrans(illegal, legal)
  274.  
  275. #Directory Seperator Character (default linux)
  276. ds="/"
  277. #If Win32 then double backslash
  278. if sys.platform == "win32":
  279.     ds="\\"
  280.  
  281. already=[]
  282.  
  283. #RegEx Compiles
  284. daily=re.compile("([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])|([0-9][0-9][0-9][0-9]\.[0-9][0-9]\.[0-9][0-9])")
  285. season_re = re.compile( season_formats )
  286. episode_re = re.compile( episode_formats )
  287. video_formats_re = re.compile( video_formats, re.IGNORECASE )                                                
  288.                
  289.  
  290.  
  291. #### SimpleCache Start - jason.fisher@gmail.com
  292.  
  293. class SimpleCache:
  294.     def __init__(self, filename="simplecache.pyd", debug=1, safe=1):
  295.                
  296.         self.file = os.path.join(os.path.dirname(sys.argv[0]),filename)
  297.         self.debug = debug
  298.         self.safe = safe
  299.         self.init = 0
  300.  
  301.         self.msg("loading " + self.file + " .. ")    
  302.         try:
  303.             cache = open(self.file,"r")
  304.         except IOError, EOFError:
  305.             try:
  306.                 self.msg("new cache file: " + self.file)
  307.                 cache = open(self.file,"w")
  308.                 self.data = {'evalcacheversion_creation':'20090212a-jmf'}
  309.                 self.msg(self.data)
  310.                 pickle.dump(self.data, cache)
  311.                 cache.close()
  312.                 self.msg(".. created.")
  313.                 cache = open(self.file,"r")
  314.             except IOError, EOFError:
  315.                 self.msg("cannot open/create " + self.file)
  316.                 return 0
  317.                
  318.         self.data = pickle.load(cache)
  319.         self.msg(".. done.")
  320.         self.msg(self.data)
  321.         cache.close()
  322.        
  323.     def msg(self, val):
  324.         if self.debug:
  325.             print val
  326.            
  327.     def save(self):
  328.         self.msg("saving " + self.file)
  329.         self.msg(self.data)
  330.         try:
  331.             cache = open(self.file,"w")
  332.             pickle.dump(self.data, cache)
  333.             cache.close()
  334.         except IOError:
  335.             self.msg("error")
  336.         self.msg(".. done.")       
  337.  
  338.     def read(self, key):           
  339.         self.msg("looking for " + str(key))
  340.         if str(key) in self.data:
  341.             if self.debug:
  342.                 self.msg("hit: " + str(key) + " = " + str(self.data[str(key)]))
  343.             return self.data[str(key)]
  344.            
  345.         self.msg("not cached.")
  346.         return 0
  347.        
  348.     def write(self, key, value):
  349.         self.msg("storing " + str(key))
  350.         self.data[str(key)] = str(value)
  351.        
  352.         if self.debug and self.data[str(key)]:
  353.             self.msg(".. done: " + str(self.data[str(key)]))
  354.        
  355.         if self.safe:
  356.             self.save()
  357.            
  358.         return self.data[str(key)]
  359.  
  360. #### Simple Caching End
  361.  
  362. import pickle
  363. cache = SimpleCache()
  364.  
  365. ####           
  366.        
  367.  
  368.  
  369. def removeIllegalChars(origstring):
  370.  
  371.     if SABnzbdIllegalCharsStyle:
  372.         try:
  373.             return str(origstring).translate(translate_table)
  374.         except:
  375.             return origstring
  376.     else:
  377.         try:
  378.             # convert unicode to ASCII
  379.             newstring = origstring.encode('ascii', 'ignore')
  380.             # replace illegal chars with nothing
  381.             return re.sub("[*:<>|]", "", newstring).strip()
  382.         except:
  383.             return origstring
  384.  
  385.     #end if SABnzbdIllegalStyle
  386.  
  387. #end def removeIllegalChars
  388.  
  389. def isInQueue(download_title):
  390.     queue=xml.dom.minidom.parse(urllib.urlopen(my_SAB+"/sabnzbd/api?mode=qstatus&output=xml"))
  391.     for job in queue.getElementsByTagName("job"):
  392.         filename=job.getElementsByTagName("filename")[0].childNodes[0].data
  393.         regex_download_title_string = removeIllegalChars(download_title)
  394.         regex_download_title = re.compile(regex_download_title_string, re.IGNORECASE)
  395.         if re.match(regex_download_title, filename):
  396.             if debug:
  397.                 print("IS IN QUEUE: " + regex_download_title.pattern)
  398.             #end if debug
  399.             return 1
  400.         #end if re.match
  401.     #end for job
  402.     if debug:
  403.         print("IS NOT IN QUEUE: " + regex_download_title.pattern)
  404.     #end if debug
  405.     return 0
  406. #end def isInQueue
  407.  
  408. def isInQueueSmart(series, season, episode):
  409.     print("ENTERED isInQueueSmart")
  410.     # Compile the regex
  411.     regex_download_title = re.compile(series + " - S" + season + "E" + episode, re.IGNORECASE)
  412.  
  413.     # Get the Queue
  414.     queue=xml.dom.minidom.parse(urllib.urlopen(my_SAB+"/sabnzbd/api?mode=qstatus&output=xml"))
  415.  
  416.     # Process each job in Queue
  417.     for job in queue.getElementsByTagName("job"):
  418.         filename=job.getElementsByTagName("filename")[0].childNodes[0].data
  419.         try:
  420.             if debug:
  421.                 print("CHECK QUEUE: " + filename)
  422.             #end if debug
  423.  
  424.             filename = formatReport(filename)
  425.             series,epstr,eptitle=filename.split(' - ')
  426.             series=cleanSeriesName(series)
  427.             filename=series + " - " + epstr + " - " + eptitle
  428.  
  429.             if debug:
  430.                 print("CHECK REFORMAT QUEUE: " + filename)
  431.             #end if debug
  432.             if re.search(regex_download_title, filename):
  433.                 if debug:
  434.                     print("IS IN QUEUE: " + regex_download_title.pattern)
  435.                 #end if debug
  436.                 return 1
  437.             #end if re.match
  438.         except:
  439.             # Queue Check Failed, so assume it's not in Queue
  440.             pass
  441.     #end for job
  442.     if debug:
  443.         print("IS NOT IN QUEUE: " + regex_download_title.pattern)
  444.     #end if debug
  445.     return 0
  446. #end def isInQueue
  447.  
  448. def isInHistorySmart(series, season, episode):
  449.     # Compile the regex
  450.     regex_download_title = re.compile(series + " - S" + season + "E" + episode, re.IGNORECASE)
  451.  
  452.     # Get the Histroy
  453.     queue=xml.dom.minidom.parse(urllib.urlopen(my_SAB+"/sabnzbd/api?mode=history&output=xml"))
  454.  
  455.     # Process each job in Queue
  456.     for job in queue.getElementsByTagName("slot"):
  457.         jobname=job.getElementsByTagName("name")[0].childNodes[0].data
  458.         try:
  459.             if debug:
  460.                 print("CHECK HISTORY: " + jobname)
  461.             #end if debug
  462.             jobname=reformatReport(filename)
  463.             series,epstr,eptitle=jobname.split(' - ')
  464.             series=cleanSeriesName(series)
  465.             jobname=series + " - " + epstr + " - " + eptitle
  466.             if debug:
  467.                 print("CHECK REFORMAT HISTORY: " + jobname)
  468.             #end if debug
  469.             if re.search(regex_download_title, jobname):
  470.                 if debug:
  471.                     print("IS IN HISTORY: " + regex_download_title.pattern)
  472.                 #end if debug
  473.                 return 1
  474.             #end if re.match
  475.         except:
  476.             # Queue Check Failed, so assume it's not in Queue
  477.             pass
  478.     #end for job
  479.     if debug:
  480.         print("IS NOT IN HISTORY: " + regex_download_title.pattern)
  481.     #end if debug
  482.     return 0
  483. #end def isInHistorySmart
  484.  
  485. def isWanted(series_title):
  486.     if debug:
  487.         print("CHECK WANTED: " + series_title)
  488.     #end if debug
  489.  
  490.     for dir in tv_dirs:
  491.         for filename in os.listdir(dir):
  492.             print("DEBUG: " + filename.lower() )
  493.             print("DEBUG: " + series_title.lower() )
  494.             if debug:
  495.                 print("LOOKING FOR: " + dir + ds + series_title)
  496.             #end if debug
  497.             if filename.lower() == series_title.lower():
  498.                 if debug:
  499.                     print("SHOW WANTED: " + series_title)
  500.                 #end if debug
  501.                 return 1
  502.             #end if os.path
  503.         #end for filename
  504.     #end for dir
  505.     if debug:
  506.         print("SHOW NOT WANTED: " + series_title)
  507.     #end if debug
  508.     return 0
  509. #end def isWanted
  510.  
  511. def isFormatWanted(series_title, report, season, feed_type):
  512.     # Override Format checking for NewzBin feeds
  513.     if feed_type == 'NewzBin':
  514.         if debug:
  515.             print("NEWZBIN FORMAT OVERRIDE: " + report)
  516.         #end if debug
  517.         return 1
  518.     #end if feed_type
  519.  
  520.     # Allow per Show/Season Format OverRide
  521.     for dir in tv_dirs:
  522.         if os.path.exists(dir + ds + series_title):
  523.             for filename in os.listdir(dir + ds + series_title):
  524.                 if filename[9:] == 'format':
  525.                     if filename[1:3] == season:
  526.                         if re.search(filename[4:8], report , re.IGNORECASE):
  527.                             if debug:
  528.                                 print("SHOW FORMAT WANTED: " + report)
  529.                             #end if debug
  530.                             return 1
  531.                         else:
  532.                             if debug:
  533.                                 print("SHOW FORMAT NOT WANTED: " + report)
  534.                             #end if debug
  535.                             return 0
  536.                         #end if re.search
  537.                     #end if file[1:3]
  538.                 #end if file[9:]
  539.             #end for file
  540.         #end if os.path
  541.     #end for dir
  542.  
  543.     # General Format Wanted
  544.     # Used if Show/Season not specified
  545.     format_object = video_formats_re.search( report , re.IGNORECASE)
  546.     if format_object:
  547.         if debug:
  548.             print("FORMAT WANTED: " + report)
  549.         #end if debug
  550.         return 1
  551.     #end if format_object
  552.  
  553.     if debug:
  554.  
  555.         print("FORMAT NOT WANTED: " + video_formats_re.pattern + " " + report)
  556.     #end if debug
  557.  
  558.     raise FormatNotWanted
  559.  
  560. #end def isFormatWanted
  561.  
  562. def isMissing(series_title, season_number, episode_number):
  563.  
  564.     print("LOOKING: " + "Season " + str(season_number) + ", Episode " + str(episode_number))
  565.  
  566.     for dir in tv_dirs:
  567.  
  568.         series_path=dir + ds + showToFolder(series_title) + ds + "Season " + season_number
  569.  
  570.         print("CHECK: " + series_title + " for seasons to IGNORE")
  571.  
  572.         # ignore this season if told to do so (existence of file or directory called ignore Season x)
  573.         if os.path.exists(dir + ds + showToFolder(series_title) + ds + "ignore Season " + season_number):
  574.             if debug:
  575.                 print("IGNORE: Season " + season_number)
  576.             #end if debug
  577.             return 0
  578.         else:
  579.             if debug:
  580.                 print("PROCESS: Season " + season_number)
  581.             #end if debug
  582.         #end if os.path.exists
  583.  
  584.         if os.path.exists(series_path):
  585.             if debug:
  586.                 print("EXIST: " + series_path)
  587.             #end if debug
  588.             for tested_episode in os.listdir(series_path):
  589.                 if debug:
  590.                     print("CHECK: " + tested_episode)
  591.                 #end if debug
  592.                 for r in config['name_parse']:
  593.                     match = r.match(tested_episode)
  594.                     if match:
  595.                         seriesname, seasno, epno, epname = match.groups()
  596.                         if re.search(series_title, seriesname, re.IGNORECASE):
  597.                             if seasno == season_number:
  598.                                 if epno == episode_number:
  599.                                     if debug:
  600.                                         print("MATCH FOUND: " + "Season " + season_number + ", Episode " + episode_number)
  601.                                     #end if debug
  602.                                     return 0
  603.                                 #end if epno
  604.                             #end if seasno
  605.                         #end if seriesname
  606.                     #end if match
  607.                 #end for r
  608.             #end for tested_episode
  609.         else:
  610.             if debug:
  611.                 print("NOT EXIST: " + series_path)
  612.             #end if debug
  613.         #end if os.path.exists
  614.  
  615.         if debug:
  616.             print("MISSING: " + "Season " + season_number + ", Episode " + episode_number)
  617.         #end if debug
  618.     #end for dir
  619.     return 1
  620. #end def isMissing
  621.  
  622. def download(report_id):
  623.  
  624.     print "ADD QUEUE: " + time.strftime("%Y-%m-%d %H:%M:%S")+": "+ report_id
  625.  
  626.     # Check report_id, if it starts http, its not a NewzBin id
  627.     if report_id[:4] == 'http':
  628.         #'Other' NZB RSS
  629.         urllib.urlopen(my_SAB+"/sabnzbd/api?mode=addurl&name="+report_id+my_SAB_params)
  630.     else:
  631.         #NewzBin Style
  632.         urllib.urlopen(my_SAB+"/sabnzbd/api?mode=addid&name="+report_id+my_SAB_params)
  633.     #end if NewzBin
  634.  
  635. #end def download
  636.  
  637.  
  638. def cleanSeriesName(series_title):
  639.     global cache
  640.                  
  641.     theTVDB = Tvdb(debug = tvdb_debug, interactive = tvdb_interactive)
  642.  
  643.     good_series_title = removeIllegalChars(series_title)
  644.     good_series_title = good_series_title.replace("(", "\(").replace(")", "\)")
  645.     good_series_title = re.sub('\.|_', ' ', good_series_title)
  646.  
  647.     if debug:
  648.         print "NZB: ", good_series_title
  649.     #end if debug
  650.    
  651.     try:
  652.         good_series_title = showAlias(good_series_title)                            
  653.  
  654.         if cache.read(good_series_title.lower()):
  655.             good_series_title = cache.read(good_series_title.lower())
  656.         else:
  657.             good_series_title = cache.write(good_series_title.lower(),theTVDB[good_series_title]['seriesname'])
  658.  
  659.         if debug:
  660.             print "TVDB: ", good_series_title
  661.         #end if debug
  662.  
  663.     except tvdb_shownotfound:
  664.         # Didn't find the show @ theTVDB,
  665.         # most likely has 'and' and theTVDB has '&'
  666.         try:
  667.             if cache.read(re.sub(' [aA]nd ', ' & ', good_series_title.lower())):
  668.                 good_series_title = cache.read(re.sub(' [aA]nd ', ' & ', good_series_title.lower()))
  669.             else:
  670.                 good_series_title = cache.write(good_series_title.strtolower(),theTVDB[re.sub(' [aA]nd ', ' & ', good_series_title.strtolower())]['seriesname'])
  671.            
  672.             if debug:
  673.                 print "TVDB: ", good_series_title
  674.             #end if debug
  675.  
  676.         except tvdb_shownotfound:
  677.             # Well, didn't find it a second time, even using '&'
  678.             # return cleaned good_series_title
  679.             good_series_title = good_series_title
  680.             if debug:
  681.                 print "TVDB NOT FOUND: ", good_series_title
  682.             #end if debug
  683.  
  684.     #If Win32 then remove illegal chars
  685.     if sys.platform == "win32" or force_windows_compliant_filenames:
  686.         good_series_title = removeIllegalChars(good_series_title)
  687.     #end if sys.platform
  688.  
  689.     return good_series_title
  690.  
  691. #end def cleanSeriesName
  692.  
  693.  
  694. def formatReport( report ):
  695.     # format into ' - ' seperated parts
  696.     # showname - seasonepisode - title
  697.  
  698.     for r in config['name_parse']:
  699.         match = r.match( report )
  700.         if match:
  701.             seriesname, seasno, epno, epname = match.groups()
  702.  
  703.             # Remove any space dash space that might be left over
  704.             # We're going to put them in anyway but need to make sure we don't 'double' them
  705.             reportdict['seriesname'] = re.sub("\s\-\s|\s\-", "", seriesname)
  706.             reportdict['seasno'] = int(seasno)
  707.             reportdict['epno'] = int(epno)
  708.             reportdict['epname'] = re.sub("\s\-\s|\s\-", "", epname)
  709.  
  710.             # Format the report name
  711.             report = config['with_ep_name'] % (reportdict)
  712.  
  713.             return report
  714.         #end if match
  715.     #end for r
  716.     raise formatError
  717. #end def formatReport
  718.  
  719.  
  720. def showAlias(showname):
  721.     # Takes a showname and matches it to an alias
  722.     # e.g. CSI should map to CSI: Crime Scene Investigation and not CSI: NY
  723.     # as returned by theTVDB api
  724.  
  725.     if re.match('CSI.+?N?.+?Y', showname, re.IGNORECASE):
  726.         print("MATCHED CSI: NY")
  727.         return "CSI: NY"
  728.     #end if re.match
  729.  
  730.     if re.match("CSI Miami", showname, re.IGNORECASE):
  731.         print("MATCHED CSI Miami")
  732.         return "CSI: Miami"
  733.     #end if re.match
  734.  
  735.     if re.match("CSI", showname, re.IGNORECASE):
  736.         print("MATCHED CSI")
  737.         return "CSI: Crime Scene Investigation"
  738.     #end if re.match
  739.  
  740.     if re.match("DEMONS", showname, re.IGNORECASE):
  741.             print("MATCHED DEMONS")
  742.             return "Demons"
  743.     #end if re.match
  744.  
  745.     # Didn't match anything so return the passed showname
  746.     return showname
  747.  
  748. #def showAlias
  749.  
  750.  
  751. def showToFolder(showname):
  752.     # Takes a showname and returns the foldername associated
  753.     # e.g. CSI NY could return CSI New York
  754.  
  755.     if re.match('CSI.+?N?.+?Y', showname, re.IGNORECASE):
  756.         print("MATCHED CSI: NY")
  757.         return "CSI NY"
  758.     #end if re.match
  759.  
  760.     # Didn't match anything so return the passed showname
  761.     return showname
  762.  
  763. #def showToFolder
  764.  
  765.  
  766. def Main():
  767.     for feed in nzbfeeds:
  768.         print("PROCESS NZB FEED: " + feed)
  769.  
  770.         # Set feed type
  771.         # NewzBin feeds have different 'titles'
  772.         if re.search('newzbin', feed, re.IGNORECASE):
  773.             feed_type = 'NewzBin'
  774.             if debug:
  775.                 print("FEED: " + feed_type)
  776.             #end if debug
  777.         else:
  778.             feed_type = 'Other'
  779.             if debug:
  780.                 print("FEED: " + feed_type)
  781.             #end if debug
  782.         #end if re.search
  783.  
  784.         dom=xml.dom.minidom.parse(urllib.urlopen(feed))
  785.         for node in dom.getElementsByTagName("item"):
  786.             report=node.getElementsByTagName("title")[0].childNodes[0].data
  787.             report_original=report
  788.             print "PROCESSING:"+report
  789.             #try-catch block because some of this stuff fails hard when it gets a weird report, and pythons default behavior is to terminate
  790.             try:
  791.                 report=formatReport(report)
  792.  
  793.                 #Split report into 3 parts
  794.                 series,epstr,title=report.split(' - ')
  795.  
  796.                 if daily.match(epstr):
  797.                     year,month,date=epstr.split("-")
  798.                     season=year+"-"+month
  799.                     episode=date
  800.                 else:
  801.                     season=epstr[1:3]
  802.                     episode=epstr[4:]
  803.                 #end if daily.match
  804.  
  805.                 # Clean series name here (reduces number of times the same code is called)
  806.                 series=cleanSeriesName(series)
  807.  
  808.                 toDownload = False
  809.  
  810.                 if not useSmartQueue:
  811.                     if isWanted(series, report, season, feed_type) and isMissing(series, season, episode, feed_type) and (not isInQueue(report_original)):
  812.                         toDownload = True
  813.                     else:
  814.                         toDownload = False
  815.                     #end if isWanted(series)
  816.                 else:
  817.                     if isWanted(series):
  818.                         if isFormatWanted(series, report, season, feed_type):
  819.                             if isMissing(series, season, episode):
  820.                                 if not isInQueueSmart(series, season, episode):
  821.                                     toDownload = True
  822.                                 #end if not isInQueueSmart
  823.                             #end if isMissing
  824.                     #end if isWanted(seies)
  825.                 #end if not useSmartQueue
  826.  
  827.                 if toDownload:
  828.                     if feed_type == 'NewzBin':
  829.                         msgid=node.getElementsByTagName("report:id")[0].childNodes[0].data
  830.                     else:
  831.                         msgid=node.getElementsByTagName("link")[0].childNodes[0].data
  832.                     #end if NewzBin
  833.                     msgid=urllib.quote(msgid)
  834.                     download(msgid)
  835.                 #end if toDownload
  836.  
  837.             except:
  838.                 print("FAILED PROCESSING: " + report)
  839.                 pass
  840.  
  841.             #end try:
  842.         #end for node
  843.     #end for feed
  844. #end def Main
  845.  
  846. if __name__ == '__main__':
  847.     Main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement