Guest User

Untitled

a guest
Oct 26th, 2014
333
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.83 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. ####################################################################################
  4. ## INFORMATION
  5. ####################################################################################
  6. ## Developed by: Steven Johnson (minor modifications by egretsareherons)
  7. ## (a minor modifications by aross01)
  8. ## (a minor modification by STEEVo)
  9. ##
  10. ## Last Updated: 02/26/2014 5:05PM MST
  11. ##
  12. ## Description: Auto-Delete Watched Items In Plex
  13. ##
  14. ## Required Configurations:
  15. ## - PC (Blank = AutoDetect | W = Windows | L = Linux/Unix/MAC)
  16. ## - Host (Hostname or IP | Blank = 127.0.0.1)
  17. ## - Port (Port | Blank = 32400)
  18. ## - SectionList - A list of sections to operate on. If this is blank, the script
  19. ## will get a list of all sections from the server & operate on all, except
  20. ## for the sections listed in IgnoreSections
  21. ## - IgnoreSections - Only used if SectionList is blank. When SectionList is blank,
  22. ## the script will operate on all available sections of your install
  23. ## except for the ones listed here.
  24. ## - Delete (1 = Delete | Blank = 0 (For Testing or Review))
  25. ## - Move (1 = move files to DestinationDir, 0 = don't move)
  26. ## - Copy (1 = copy files to DestinationDir, 0 = don't copy)
  27. ## - Shows ( ["Show1","Show2"]; = Kept Shows OR [""]; = DEL ALL SHOWS )
  28. ## - OnDeck ( 1 = Keep If On Deck | Blank = Delete Regardless if onDeck )
  29. ## - DestinationDir - the place to move or copy your watched files for later manual deletion
  30. ## - DestinationSection - if your destination dir is also a configured section, set the
  31. ## number here so TriggerRescan knows to rescan that section when changes are made.
  32. ## only used if TriggerRescan is True;
  33. ## - TriggerRescan - automatically trigger a deep rescan of changed sections. True or False.
  34. ##
  35. ## - KeepMode (Blank = Disabled | W = "Watched" | A = "Added")
  36. ## Method used to keep items for X number of days (specified by DaysToKeep below.)
  37. ## You may choose to base the keep on the last "watched" or "added" date.
  38. ## - DaysToKeep ("30" = Keep items for 30 days following the KeepMode selected)
  39. ##
  40. ####################################################################################
  41. ####################################################################################
  42.  
  43. PC = ""
  44. Host = ""
  45. Port = ""
  46. SectionList = [3]
  47. IgnoreSections = []
  48. Delete = "1"
  49. Move = "0"
  50. Copy = "0"
  51. Shows = []
  52. OnDeck = ""
  53. DestinationDir = ""
  54. DestinationSection = ""
  55. TriggerRescan = True
  56. KeepMode = ""
  57. DaysToKeep = 30
  58. ####################################################################################
  59. ## NO NEED TO EDIT BELOW THIS LINE
  60. ####################################################################################
  61. import os
  62. import xml.dom.minidom
  63. import platform
  64. import re
  65. import shutil
  66. import datetime
  67. import glob
  68. try:
  69. import urllib.request as urllib2
  70. except:
  71. import urllib2
  72.  
  73.  
  74. ####################################################################################
  75. ## Check On Deck
  76. ####################################################################################
  77. def CheckOnDeck( CheckDeckFile ):
  78. InTheDeck = 0
  79. for DeckVideoNode in deck.getElementsByTagName("Video"):
  80. DeckMediaNode = DeckVideoNode.getElementsByTagName("Media")
  81. for DeckMedia in DeckMediaNode:
  82. DeckPartNode = DeckMedia.getElementsByTagName("Part")
  83. for DeckPart in DeckPartNode:
  84. Deckfile = DeckPart.getAttribute("file")
  85. if CheckDeckFile==Deckfile:
  86. InTheDeck += 1
  87. else:
  88. InTheDeck += 0
  89. return InTheDeck
  90.  
  91. ####################################################################################
  92. ## Check Shows And Delete If Configured
  93. ####################################################################################
  94. def CheckShows( CheckFile ):
  95. global FileCount
  96. global DeleteCount
  97. global MoveCount
  98. global CopyCount
  99. global FlaggedCount
  100. global OnDeckCount
  101. global ShowsCount
  102. global DestinationDir
  103. FileCount += 1
  104. CantDelete = 0
  105. ShowFound = ""
  106. changed = 0
  107.  
  108. ## -- CHECK SHOWS --
  109. for Show in Shows:
  110. Show = re.sub('[^A-Za-z0-9 ]+', '', Show).strip()
  111. if Show=="":
  112. CantDelete = 0
  113. else:
  114. if (' ' in Show) == True:
  115. if all(str(Word) in CheckFile for Word in Show.split()):
  116. CantDelete += 1
  117. ShowFound = "[" + Show + "]"
  118. ShowsCount += 1
  119. else:
  120. CantDelete += 0
  121. else:
  122. if Show in CheckFile:
  123. CantDelete += 1
  124. ShowFound = "[" + Show + "]"
  125. ShowsCount += 1
  126. else:
  127. CantDelete += 0
  128.  
  129. ## -- Check OnDeck --
  130. if OnDeck=="1":
  131. IsOnDeck = CheckOnDeck(CheckFile);
  132. if IsOnDeck==0:
  133. CantDelete += 0
  134. else:
  135. CantDelete += 1
  136. ShowFound = "[OnDeck]" + ShowFound
  137. OnDeckCount += 1
  138.  
  139. ## -- Check if video older than days to keep [Viewed method] --
  140. if KeepMode=="W":
  141. if DaysToKeep > DaysSinceVideoLastViewed:
  142. CantDelete += 1
  143. ShowsCount += 1
  144. # ShowFound = " | Days Since Viewed:" + str(DaysSinceVideoLastViewed) +" |" + ShowFound
  145. ## -- Check if video older than days to keep [Added method] --
  146. if KeepMode=="A":
  147. if DaysToKeep > DaysSinceVideoAdded:
  148. CantDelete += 1
  149. ShowsCount += 1
  150. # ShowFound = " | Days Since Added:" + str(DaysSinceVideoAdded) +" |" + ShowFound
  151.  
  152. ## -- DELETE SHOWS --
  153. if CantDelete == 0:
  154. if Delete=="1":
  155. #print("**[DELETED] " + CheckFile)
  156. similairFiles = os.path.splitext(file)[0] + "*"
  157. print("Looking for " + similairFiles)
  158. for deleteFile in glob.glob(similairFiles):
  159. try:
  160. os.remove(deleteFile)
  161. print("**[DELETED] " + deleteFile)
  162. changed = 1
  163. DeleteCount += 1
  164. except Exception as e:
  165. print ("error deleting file: %s" % e)
  166. elif Move == "1":
  167. try:
  168. os.utime(os.path.realpath(CheckFile), None)
  169. shutil.move(os.path.realpath(CheckFile), DestinationDir)
  170. print("**[MOVED] " + CheckFile)
  171. changed = 1
  172. except Exception as e:
  173. print ("error moving file: %s" % e)
  174. if os.path.islink(CheckFile):
  175. os.unlink(CheckFile)
  176. MoveCount += 1
  177. elif Copy == "1":
  178. try:
  179. shutil.copy(os.path.realpath(CheckFile), DestinationDir)
  180. changed = 1
  181. except Exception as e:
  182. print ("error copying file: %s" % e)
  183. print("**[COPIED] " + CheckFile)
  184. CopyCount += 1
  185.  
  186. else:
  187. print("**[FLAGGED] " + CheckFile)
  188. FlaggedCount += 1
  189. else:
  190. print("[KEEPING]")
  191. return changed
  192.  
  193.  
  194.  
  195. ####################################################################################
  196. ## Checking URL
  197. ####################################################################################
  198. if Host=="":
  199. Host="127.0.0.1"
  200. if Port=="":
  201. Port="32400"
  202.  
  203.  
  204. print("----------------------------------------------------------------------------")
  205. print(" Detected Settings")
  206. print("----------------------------------------------------------------------------")
  207. print("Host: " + Host)
  208. print("Port: " + Port)
  209. #print("Section: " + Section)
  210. #print("URL: " + URL)
  211. #print("OnDeck URL: " + OnDeckURL)
  212.  
  213. if KeepMode=="W":
  214. print("Keep Mode: Keeping for " + str(DaysToKeep) + " days following the date last viewed")
  215. elif KeepMode=="A":
  216. print("Keep Mode: Keeping viewed items that were added to the library less than " + str(DaysToKeep) + " days ago")
  217. else:
  218. print("Keep Mode: DISABLED")
  219.  
  220. ####################################################################################
  221. ## Checking Shows
  222. ####################################################################################
  223. NoDelete = " | "
  224. ShowCount = len(Shows)
  225. print("Show Count: " + str(ShowCount))
  226.  
  227. for Show in Shows:
  228. Show = re.sub('[^A-Za-z0-9 ]+', '', Show).strip()
  229. if Show=="":
  230. NoDelete += "(None Listed) | "
  231. ShowCount -= 1
  232. else:
  233. NoDelete += Show + " | "
  234.  
  235. print("Number of Shows Detected For Keeping: " + str(ShowCount))
  236. print ("Shows to Keep:" + NoDelete)
  237.  
  238. ###################################################################################
  239. ## Checking Delete
  240. ####################################################################################
  241. if Delete=="1":
  242. print("Delete: ***Enabled***")
  243. else:
  244. print("Delete: Disabled - Flagging Only")
  245.  
  246. if OnDeck=="1":
  247. print("Delete OnDeck: No")
  248. else:
  249. print("Delete OnDeck: Yes")
  250.  
  251. ####################################################################################
  252. ## Checking OS
  253. ####################################################################################
  254. AD = ""
  255. if PC=="":
  256. AD = "(Auto Detected)"
  257. if platform.system()=="Windows":
  258. PC = "W"
  259. elif platform.system()=="Linux":
  260. PC = "L"
  261. elif platform.system()=="Darwin":
  262. PC = "L"
  263.  
  264. FileCount = 0
  265. DeleteCount = 0
  266. MoveCount = 0
  267. CopyCount = 0
  268. FlaggedCount = 0
  269. OnDeckCount = 0
  270. ShowsCount = 0
  271. RescannedSections = []
  272.  
  273.  
  274. ####################################################################################
  275. ## Get list of sections
  276. ####################################################################################
  277.  
  278. if PC=="L":
  279. print("Operating System: Linux " + AD)
  280. import urllib2
  281. elif PC=="W":
  282. print("Operating System: Windows " + AD)
  283. import urllib.request
  284. else:
  285. print("Operating System: ** Not Configured ** (" + platform.system() + ") is not recognized.")
  286. exit()
  287.  
  288. if not SectionList:
  289. URL = ("http://" + Host + ":" + Port + "/library/sections/")
  290. doc = xml.dom.minidom.parse(urllib2.urlopen(URL))
  291. for Section in doc.getElementsByTagName("Directory"):
  292. if Section.getAttribute("key") not in IgnoreSections:
  293. SectionList.append(Section.getAttribute("key"))
  294.  
  295. SectionList.sort(key=int)
  296. print ("Section List Mode: Auto")
  297. print ("Operating on sections: " + ','.join(str(x) for x in SectionList))
  298. print ("Skipping Sections: " + ','.join(str(x) for x in IgnoreSections))
  299.  
  300. else:
  301. print ("Section List Mode: User-defined")
  302. print ("Operating on user-defined sections: " + ','.join(str(x) for x in SectionList))
  303.  
  304.  
  305. ####################################################################################
  306. ## Loop on sections
  307. ####################################################################################
  308. rescan_destination = False
  309.  
  310. for Section in SectionList:
  311. Section = str(Section)
  312. URL = ("http://" + Host + ":" + Port + "/library/sections/" + Section + "/recentlyViewed")
  313. OnDeckURL = ("http://" + Host + ":" + Port + "/library/sections/" + Section + "/onDeck")
  314. ####################################################################################
  315. ## Setting OS Based Variables
  316. ####################################################################################
  317. if PC=="L":
  318. doc = xml.dom.minidom.parse(urllib2.urlopen(URL))
  319. deck = xml.dom.minidom.parse(urllib2.urlopen(OnDeckURL))
  320. elif PC=="W":
  321. doc = xml.dom.minidom.parse(urllib.request.urlopen(URL))
  322. deck = xml.dom.minidom.parse(urllib.request.urlopen(OnDeckURL))
  323. SectionName = doc.getElementsByTagName("MediaContainer")[0].getAttribute("title1")
  324. print("")
  325. print("--------- Section "+ Section +": " + SectionName + " -----------------------------------")
  326.  
  327.  
  328.  
  329. ####################################################################################
  330. ## Get Files for Watched Shows
  331. ####################################################################################
  332. changed = 0
  333. for VideoNode in doc.getElementsByTagName("Video"):
  334. view = VideoNode.getAttribute("viewCount")
  335. if view == '':
  336. view = 0
  337. view = int(view)
  338. ################################################################
  339. ###Find number of days between date video was viewed and today
  340. lastViewedAt = VideoNode.getAttribute("lastViewedAt")
  341. d1 = datetime.datetime.today()
  342. d2 = datetime.datetime.fromtimestamp(float(lastViewedAt))
  343. DaysSinceVideoLastViewed = (d1 - d2).days
  344. ################################################################
  345. ################################################################
  346. ###Find number of days between date video was added and today
  347. addedAt = VideoNode.getAttribute("addedAt")
  348. d1 = datetime.datetime.today()
  349. da2 = datetime.datetime.fromtimestamp(float(addedAt))
  350. DaysSinceVideoAdded = (d1 - da2).days
  351. ################################################################
  352. MediaNode = VideoNode.getElementsByTagName("Media")
  353. for Media in MediaNode:
  354. PartNode = Media.getElementsByTagName("Part")
  355. for Part in PartNode:
  356. file = Part.getAttribute("file")
  357. #NEW (Removed by Mustang):
  358. #if PC == 'L':
  359. #file = urllib2.unquote(file.encode('utf-8')).decode('utf-8')
  360. #else:
  361. #import urllib
  362. #file = urllib.parse.unquote(file.encode('utf-8')).decode('utf-8')
  363.  
  364. if str(view)!="0":
  365. print(" ")
  366. if KeepMode=="W":
  367. if str(view)!="0":
  368. print ("Viewed:" + str(view) + "x | Days Since Viewed: " + str(DaysSinceVideoLastViewed) + " | " + file)
  369. if view > 0:
  370. if os.path.isfile(file):
  371. changed += CheckShows(file);
  372. else:
  373. print("##[NOT FOUND] " + file)
  374. if KeepMode=="A":
  375. if str(view)!="0":
  376. print ("Viewed:" + str(view) + "x | Days Since Added: " + str(DaysSinceVideoAdded) + " | " + file)
  377. if view > 0:
  378. if os.path.isfile(file):
  379. changed += CheckShows(file);
  380. else:
  381. print("##[NOT FOUND] " + file)
  382. if KeepMode=="":
  383. if str(view)!="0":
  384. print ("Viewed:" + str(view) + "x | Days Since Viewed: " + str(DaysSinceVideoLastViewed) + " Added: " + str(DaysSinceVideoAdded) + " | " + file)
  385. if view > 0:
  386. if os.path.isfile(file):
  387. changed += CheckShows(file);
  388. else:
  389. print("##[NOT FOUND] " + file)
  390.  
  391. # rescan this section if necessary
  392. if TriggerRescan and changed:
  393. URL = ("http://" + Host + ":" + Port + "/library/sections/" + Section + "/refresh?deep=1")
  394. blah = urllib2.urlopen(URL)
  395. RescannedSections.append(SectionName + '(' + Section + ')')
  396. rescan_destination = True
  397.  
  398. # rescan destination section if necessary
  399. if TriggerRescan and DestinationSection and rescan_destination:
  400. URL = ("http://" + Host + ":" + Port + "/library/sections/" + str(DestinationSection) + "/refresh?deep=1")
  401. blah = urllib2.urlopen(URL)
  402. RescannedSections.append('[destination dir]' + '(' + str(DestinationSection) + ')')
  403.  
  404.  
  405. print("")
  406. print("----------------------------------------------------------------------------")
  407. print("----------------------------------------------------------------------------")
  408. print(" Summary -- Script Completed Successfully")
  409. print("----------------------------------------------------------------------------")
  410. print("")
  411. print(" Total File Count " + str(FileCount))
  412. print(" Kept Show Files " + str(ShowsCount))
  413. print(" On Deck Files " + str(OnDeckCount))
  414. print(" Deleted Files " + str(DeleteCount))
  415. print(" Moved Files " + str(MoveCount))
  416. print(" Copied Files " + str(CopyCount))
  417. print(" Flagged Files " + str(FlaggedCount))
  418. print(" Rescanned Sections " + ', '.join(str(x) for x in RescannedSections) )
  419. print("")
  420. print("----------------------------------------------------------------------------")
  421. print("----------------------------------------------------------------------------")
Advertisement
Add Comment
Please, Sign In to add comment