Advertisement
Guest User

Untitled

a guest
Mar 13th, 2012
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.93 KB | None | 0 0
  1. import sys, os
  2. import xbmc, xbmcgui, xbmcaddon, xbmcplugin
  3. import unicodedata
  4. import urllib
  5. import re
  6.  
  7. import datetime
  8.  
  9. # plugin modes
  10. MODE_FIRST = 10
  11. MODE_SECOND = 20
  12. MODE_HELP = 30
  13.  
  14. # parameter keys
  15. PARAMETER_KEY_MODE = "mode"
  16.  
  17. __addon__ = xbmcaddon.Addon(id='plugin.video.missingmovies')
  18. __addonid__ = __addon__.getAddonInfo('id')
  19. __scriptdebug__ = __addon__.getSetting("debug") == "true"
  20. __fileextensions__ = ['mpg', 'mpeg', 'avi', 'flv', 'wmv', 'mkv', '264', '3g2', '3gp', 'ifo', 'mp4', 'mov', 'iso', 'divx', 'ogm']
  21. __fileextensions__.extend(__addon__.getSetting("custom_file_extensions").split(";"))
  22. __handle__ = int(sys.argv[1])
  23. __language__ = __addon__.getLocalizedString
  24. __outputfile__ = os.path.join(__addon__.getSetting("output_dir"), __addon__.getSetting("output_file"));
  25.  
  26. def log(txt, severity=xbmc.LOGDEBUG):
  27. if __scriptdebug__ and severity == xbmc.LOGINFO:
  28. severity = xbmc.LOGNOTICE
  29. try:
  30. message = (u"%s" % txt)
  31. xbmc.log(msg=message, level=severity)
  32. except UnicodeEncodeError:
  33. message = ("UnicodeEncodeError")
  34. xbmc.log(msg=message, level=xbmc.LOGWARNING)
  35.  
  36. log("MISSING MOVIE VIEWER STARTED.", xbmc.LOGNOTICE);
  37.  
  38. def string_startswith_case_insensitive(stringA, stringB):
  39. return stringA.lower().startswith( stringB.lower() )
  40.  
  41. def remove_duplicates(files):
  42. # converting it to a set and back drops all duplicates
  43. return list(set(files))
  44.  
  45. def output_to_file(list):
  46. f = open(__outputfile__, 'a')
  47. for item in list:
  48. file = item + '\n'
  49. f.write(file.encode('utf8'))
  50. f.close()
  51.  
  52. def get_sources():
  53. sources = eval(xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Files.GetSources", "params": {"media": "video"}, "id": 1}'))['result']['sources']
  54. sources = [ unicode(xbmc.validatePath(s['file']), 'utf8') for s in sources ]
  55.  
  56. results = []
  57. for s in sources:
  58. log("FOUND SOURCE: %s" % s, xbmc.LOGINFO)
  59. if s.startswith('addons://'):
  60. log("%s is an addon source, ignoring..." % s, xbmc.LOGINFO)
  61. sources.remove(s)
  62. elif s.startswith('multipath://'):
  63. log("%s is a multipath source, splitting and adding individuals..." % s, xbmc.LOGINFO)
  64. s = s.replace('multipath://', '')
  65. parts = s.split('/')
  66. parts = [ urllib.unquote(f) for f in parts ]
  67.  
  68. for b in parts:
  69. if b:
  70. log("%s is a straight forward source, adding.." % b, xbmc.LOGINFO)
  71. results.append(b)
  72. else:
  73. log("%s is a straight forward source, adding..." % s, xbmc.LOGINFO)
  74. results.append(s)
  75.  
  76. return results
  77.  
  78. def strip_username_password(s):
  79. if s.find('@') != -1:
  80. s = s[0:6] + s[s.find('@') + 1:]
  81. return s
  82.  
  83. def get_movie_sources():
  84. result = eval(xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params":{"properties": ["file"]}, "id": 1}'))
  85. if 'movies' not in result['result']:
  86. return []
  87.  
  88. movies = result['result']['movies']
  89. log(movies, xbmc.LOGDEBUG)
  90. files = [ unicode(item['file'], 'utf8') for item in movies ]
  91. files = [ os.path.dirname(f) for f in files ]
  92. files = remove_duplicates(files)
  93.  
  94. sources = remove_duplicates(get_sources())
  95.  
  96. results = []
  97. for f in files:
  98. for s in sources:
  99. if f[-1] != '/' and f.find('/') != -1:
  100. f += '/'
  101. elif f[-1] != os.sep and f.find(os.sep) != -1:
  102. f += os.sep
  103. f = strip_username_password(f)
  104.  
  105. if string_startswith_case_insensitive(f, s):
  106. log("%s was confirmed as a movie source using %s" % (s, f), xbmc.LOGINFO)
  107. results.append(s)
  108. sources.remove(s)
  109.  
  110.  
  111. return results
  112.  
  113. def get_tv_files(show_errors):
  114. result = eval(xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "id": 1}'))
  115. log("VideoLibrary.GetTVShows results: %s" % result, xbmc.LOGDEBUG)
  116. if 'tvshows' not in result['result']:
  117. return []
  118.  
  119. tv_shows = result['result']['tvshows']
  120. files = []
  121.  
  122. for tv_show in tv_shows:
  123. show_id = tv_show['tvshowid']
  124. show_name = tv_show['label']
  125.  
  126. episode_result = eval(xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["file"]}, "id": 1}' % show_id))
  127.  
  128. try:
  129. episodes = episode_result['result']['episodes']
  130. files.extend([ strip_username_password(unicode(e['file'], 'utf8')) for e in episodes ])
  131. except KeyError:
  132. if show_errors:
  133. xbmcgui.Dialog().ok(__language__(30203), __language__(30207) + show_name, __language__(30204))
  134.  
  135. return files
  136.  
  137. def get_tv_sources():
  138. files = get_tv_files(False)
  139. files = [ os.path.dirname(f) for f in files ]
  140. files = remove_duplicates(files)
  141.  
  142. sources = remove_duplicates(get_sources())
  143.  
  144. results = []
  145. for f in files:
  146. for s in sources:
  147. if f[-1] != '/' and f.find('/') != -1:
  148. f += '/'
  149. elif f[-1] != os.sep and f.find(os.sep) != -1:
  150. f += os.sep
  151. f = strip_username_password(f)
  152.  
  153. if string_startswith_case_insensitive(f, s):
  154. log("%s was confirmed as a TV source using %s" % (s, f), xbmc.LOGINFO)
  155. results.append(s)
  156. sources.remove(s)
  157. return results
  158.  
  159. def file_has_extensions(filename, extensions):
  160. # get the file extension, without a leading colon.
  161. name, extension = os.path.splitext(os.path.basename(filename))
  162. name = name.lower()
  163. extension = extension[1:].lower()
  164. extensions = [ f.lower() for f in extensions ]
  165.  
  166. if extension == '' or (extension == 'ifo' and name != 'video_ts'):
  167. return False
  168.  
  169. return extension in extensions
  170.  
  171. def ends_on_sep(path):
  172. if path[-1] == '/' or path[-1] == os.sep:
  173. return True
  174. return False
  175.  
  176. def get_files(path):
  177. path = path.replace("\\", "/")
  178.  
  179. results = []
  180.  
  181. #for some reason xbmc throws an exception when doing GetDirectory on an empty source directory. it works when one file is in there. so catch that
  182. try:
  183. result = eval(xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Files.GetDirectory", "params":{"directory": "%s"}, "id": 1}' % path))
  184. except NameError:
  185. return results
  186.  
  187. for item in result['result']['files']:
  188. f = item['file']
  189.  
  190. if ends_on_sep(f):
  191. results.extend(get_files(f))
  192. elif file_has_extensions(f, __fileextensions__):
  193. results.append(unicode(strip_username_password(urllib.unquote(f)), 'utf8'))
  194. return results
  195.  
  196. # utility functions
  197. def parameters_string_to_dict(parameters):
  198. ''' Convert parameters encoded in a URL to a dict. '''
  199. paramDict = {}
  200. if parameters:
  201. paramPairs = parameters[1:].split("&")
  202. for paramsPair in paramPairs:
  203. paramSplits = paramsPair.split('=')
  204. if (len(paramSplits)) == 2:
  205. paramDict[paramSplits[0]] = paramSplits[1]
  206. return paramDict
  207.  
  208. def addDirectoryItem(name, isFolder=True, parameters={}, totalItems=1):
  209. ''' Add a list item to the XBMC UI. '''
  210. li = xbmcgui.ListItem(name)
  211.  
  212. url = sys.argv[0] + '?' + urllib.urlencode(parameters)
  213.  
  214. if not isFolder:
  215. url = name
  216. return xbmcplugin.addDirectoryItem(handle=__handle__, url=url, listitem=li, isFolder=isFolder,totalItems=totalItems)
  217.  
  218. # UI builder functions
  219. def show_root_menu():
  220. ''' Show the plugin root menu. '''
  221. addDirectoryItem(name=__language__(30200), parameters={ PARAMETER_KEY_MODE: MODE_FIRST }, isFolder=True)
  222. addDirectoryItem(name=__language__(30201), parameters={ PARAMETER_KEY_MODE: MODE_SECOND }, isFolder=True)
  223. addDirectoryItem(name=__language__(30202), parameters={ PARAMETER_KEY_MODE: MODE_HELP }, isFolder=True)
  224. xbmcplugin.endOfDirectory(handle=__handle__, succeeded=True)
  225.  
  226. def show_movie_submenu():
  227. ''' Show movies missing from the library. '''
  228. movie_sources = remove_duplicates(get_movie_sources())
  229. if len(movie_sources) == 0 or len(movie_sources[0]) == 0:
  230. xbmcgui.Dialog().ok(__language__(30203), __language__(30205), __language__(30204))
  231. log("No movie sources!", xbmc.LOGERROR)
  232. xbmcplugin.endOfDirectory(handle=__handle__, succeeded=False)
  233. return
  234.  
  235. result = eval(xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params":{"properties": ["file"]}, "id": 1}'))
  236. movies = result['result']['movies']
  237.  
  238. library_files = []
  239. missing = []
  240.  
  241. log("SEARCHING MOVIES", xbmc.LOGNOTICE)
  242. # this magic section adds the files from trailers and sets!
  243. for m in movies:
  244. f = m['file']
  245.  
  246. if f.startswith("videodb://"):
  247. set_files = eval(xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Files.GetDirectory", "params": {"directory": "%s"}, "id": 1}' % f))
  248.  
  249. sub_files = []
  250. sub_trailers = []
  251.  
  252. for item in set_files['result']['files']:
  253. sub_files.append(strip_username_password(unicode(item['file'], 'utf8')))
  254. try:
  255. trailer = item['trailer']
  256. if not trailer.startswith('http://'):
  257. library_files.append(strip_username_password(unicode(trailer, 'utf8')))
  258. except KeyError:
  259. pass
  260.  
  261. library_files.extend(sub_files)
  262. library_files.extend(sub_trailers)
  263. elif f.startswith('stack://'):
  264. f = f.replace('stack://', '')
  265. parts = f.split(' , ')
  266.  
  267. parts = [ strip_username_password(unicode(f, 'utf8')) for f in parts ]
  268.  
  269. for b in parts:
  270. library_files.append(b)
  271. else:
  272. library_files.append(strip_username_password(unicode(f, 'utf8')))
  273. try:
  274. trailer = m['trailer']
  275. if not trailer.startswith('http://'):
  276. library_files.append(strip_username_password(unicode(trailer, 'utf8')))
  277. except KeyError:
  278. pass
  279.  
  280. library_files = set(library_files)
  281.  
  282. for movie_source in movie_sources:
  283. movie_files = set(get_files(movie_source))
  284.  
  285. if not library_files.issuperset(movie_files):
  286. log("%s contains missing movies!" % movie_source, xbmc.LOGNOTICE)
  287. l = list(movie_files.difference(library_files))
  288. l.sort()
  289. missing.extend(l)
  290.  
  291. log("library files: %s" % library_files, xbmc.LOGINFO)
  292. log("missing movies: %s" % l, xbmc.LOGNOTICE)
  293.  
  294. if __outputfile__:
  295. output_to_file(missing);
  296.  
  297. for movie_file in missing:
  298. # get the end of the filename without the extension
  299. if os.path.splitext(movie_file.lower())[0].endswith("trailer"):
  300. log("%s is a trailer and will be ignored!" % movie_file, xbmc.LOGINFO)
  301. else:
  302. addDirectoryItem(movie_file, isFolder=False, totalItems=len(missing))
  303.  
  304. xbmcplugin.endOfDirectory(handle=__handle__, succeeded=True)
  305.  
  306. def show_tvshow_submenu():
  307. ''' Show TV shows missing from the library. '''
  308. tv_sources = remove_duplicates(get_tv_sources())
  309. if len(tv_sources) == 0 or len(tv_sources[0]) == 0:
  310. xbmcgui.Dialog().ok(__language__(30203), __language__(30206), __language__(30204))
  311. log("No TV sources!", xbmc.LOGERROR)
  312. xbmcplugin.endOfDirectory(handle=__handle__, succeeded=False)
  313. return
  314.  
  315. library_files = set(get_tv_files(True))
  316. missing = []
  317.  
  318. log("SEARCHING TV SHOWS", xbmc.LOGNOTICE);
  319. for tv_source in tv_sources:
  320. tv_files = set(get_files(tv_source))
  321.  
  322. if not library_files.issuperset(tv_files):
  323. log("%s contains missing TV shows!" % tv_source, xbmc.LOGNOTICE)
  324. l = list(tv_files.difference(library_files))
  325. l.sort()
  326. missing.extend(l)
  327.  
  328. log("library files: %s" % library_files, xbmc.LOGNOTICE)
  329. log("missing episodes: %s" % l, xbmc.LOGNOTICE)
  330.  
  331. if __outputfile__:
  332. output_to_file(missing)
  333.  
  334. for tv_file in missing:
  335. addDirectoryItem(tv_file, isFolder=False)
  336.  
  337. xbmcplugin.endOfDirectory(handle=__handle__, succeeded=True)
  338.  
  339. def show_help():
  340. xbmcgui.Dialog().ok(__language__(30202), __language__(30208))
  341.  
  342. # parameter values
  343. params = parameters_string_to_dict(sys.argv[2])
  344. mode = int(params.get(PARAMETER_KEY_MODE, "0"))
  345.  
  346. # Depending on the mode, call the appropriate function to build the UI.
  347. if not sys.argv[2]:
  348. # new start
  349. ok = show_root_menu()
  350. elif mode == MODE_FIRST:
  351. ok = show_movie_submenu()
  352. elif mode == MODE_SECOND:
  353. ok = show_tvshow_submenu()
  354. elif mode == MODE_HELP:
  355. ok = show_help()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement