Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python
- # -*- coding: utf-8 -*-
- ####################################################################################
- ## INFORMATION
- ####################################################################################
- ## Developed by: Steven Johnson (minor modifications by egretsareherons)
- ## (a minor modifications by aross01)
- ## (a minor modification by STEEVo)
- ##
- ## Last Updated: 02/26/2014 5:05PM MST
- ##
- ## Description: Auto-Delete Watched Items In Plex
- ##
- ## Required Configurations:
- ## - PC (Blank = AutoDetect | W = Windows | L = Linux/Unix/MAC)
- ## - Host (Hostname or IP | Blank = 127.0.0.1)
- ## - Port (Port | Blank = 32400)
- ## - SectionList - A list of sections to operate on. If this is blank, the script
- ## will get a list of all sections from the server & operate on all, except
- ## for the sections listed in IgnoreSections
- ## - IgnoreSections - Only used if SectionList is blank. When SectionList is blank,
- ## the script will operate on all available sections of your install
- ## except for the ones listed here.
- ## - Delete (1 = Delete | Blank = 0 (For Testing or Review))
- ## - Move (1 = move files to DestinationDir, 0 = don't move)
- ## - Copy (1 = copy files to DestinationDir, 0 = don't copy)
- ## - Shows ( ["Show1","Show2"]; = Kept Shows OR [""]; = DEL ALL SHOWS )
- ## - OnDeck ( 1 = Keep If On Deck | Blank = Delete Regardless if onDeck )
- ## - DestinationDir - the place to move or copy your watched files for later manual deletion
- ## - DestinationSection - if your destination dir is also a configured section, set the
- ## number here so TriggerRescan knows to rescan that section when changes are made.
- ## only used if TriggerRescan is True;
- ## - TriggerRescan - automatically trigger a deep rescan of changed sections. True or False.
- ##
- ## - KeepMode (Blank = Disabled | W = "Watched" | A = "Added")
- ## Method used to keep items for X number of days (specified by DaysToKeep below.)
- ## You may choose to base the keep on the last "watched" or "added" date.
- ## - DaysToKeep ("30" = Keep items for 30 days following the KeepMode selected)
- ##
- ####################################################################################
- ####################################################################################
- PC = ""
- Host = ""
- Port = ""
- SectionList = [3]
- IgnoreSections = []
- Delete = "1"
- Move = "0"
- Copy = "0"
- Shows = []
- OnDeck = ""
- DestinationDir = ""
- DestinationSection = ""
- TriggerRescan = True
- KeepMode = ""
- DaysToKeep = 30
- ####################################################################################
- ## NO NEED TO EDIT BELOW THIS LINE
- ####################################################################################
- import os
- import xml.dom.minidom
- import platform
- import re
- import shutil
- import datetime
- import glob
- try:
- import urllib.request as urllib2
- except:
- import urllib2
- ####################################################################################
- ## Check On Deck
- ####################################################################################
- def CheckOnDeck( CheckDeckFile ):
- InTheDeck = 0
- for DeckVideoNode in deck.getElementsByTagName("Video"):
- DeckMediaNode = DeckVideoNode.getElementsByTagName("Media")
- for DeckMedia in DeckMediaNode:
- DeckPartNode = DeckMedia.getElementsByTagName("Part")
- for DeckPart in DeckPartNode:
- Deckfile = DeckPart.getAttribute("file")
- if CheckDeckFile==Deckfile:
- InTheDeck += 1
- else:
- InTheDeck += 0
- return InTheDeck
- ####################################################################################
- ## Check Shows And Delete If Configured
- ####################################################################################
- def CheckShows( CheckFile ):
- global FileCount
- global DeleteCount
- global MoveCount
- global CopyCount
- global FlaggedCount
- global OnDeckCount
- global ShowsCount
- global DestinationDir
- FileCount += 1
- CantDelete = 0
- ShowFound = ""
- changed = 0
- ## -- CHECK SHOWS --
- for Show in Shows:
- Show = re.sub('[^A-Za-z0-9 ]+', '', Show).strip()
- if Show=="":
- CantDelete = 0
- else:
- if (' ' in Show) == True:
- if all(str(Word) in CheckFile for Word in Show.split()):
- CantDelete += 1
- ShowFound = "[" + Show + "]"
- ShowsCount += 1
- else:
- CantDelete += 0
- else:
- if Show in CheckFile:
- CantDelete += 1
- ShowFound = "[" + Show + "]"
- ShowsCount += 1
- else:
- CantDelete += 0
- ## -- Check OnDeck --
- if OnDeck=="1":
- IsOnDeck = CheckOnDeck(CheckFile);
- if IsOnDeck==0:
- CantDelete += 0
- else:
- CantDelete += 1
- ShowFound = "[OnDeck]" + ShowFound
- OnDeckCount += 1
- ## -- Check if video older than days to keep [Viewed method] --
- if KeepMode=="W":
- if DaysToKeep > DaysSinceVideoLastViewed:
- CantDelete += 1
- ShowsCount += 1
- # ShowFound = " | Days Since Viewed:" + str(DaysSinceVideoLastViewed) +" |" + ShowFound
- ## -- Check if video older than days to keep [Added method] --
- if KeepMode=="A":
- if DaysToKeep > DaysSinceVideoAdded:
- CantDelete += 1
- ShowsCount += 1
- # ShowFound = " | Days Since Added:" + str(DaysSinceVideoAdded) +" |" + ShowFound
- ## -- DELETE SHOWS --
- if CantDelete == 0:
- if Delete=="1":
- #print("**[DELETED] " + CheckFile)
- similairFiles = os.path.splitext(file)[0] + "*"
- print("Looking for " + similairFiles)
- for deleteFile in glob.glob(similairFiles):
- try:
- os.remove(deleteFile)
- print("**[DELETED] " + deleteFile)
- changed = 1
- DeleteCount += 1
- except Exception as e:
- print ("error deleting file: %s" % e)
- elif Move == "1":
- try:
- os.utime(os.path.realpath(CheckFile), None)
- shutil.move(os.path.realpath(CheckFile), DestinationDir)
- print("**[MOVED] " + CheckFile)
- changed = 1
- except Exception as e:
- print ("error moving file: %s" % e)
- if os.path.islink(CheckFile):
- os.unlink(CheckFile)
- MoveCount += 1
- elif Copy == "1":
- try:
- shutil.copy(os.path.realpath(CheckFile), DestinationDir)
- changed = 1
- except Exception as e:
- print ("error copying file: %s" % e)
- print("**[COPIED] " + CheckFile)
- CopyCount += 1
- else:
- print("**[FLAGGED] " + CheckFile)
- FlaggedCount += 1
- else:
- print("[KEEPING]")
- return changed
- ####################################################################################
- ## Checking URL
- ####################################################################################
- if Host=="":
- Host="127.0.0.1"
- if Port=="":
- Port="32400"
- print("----------------------------------------------------------------------------")
- print(" Detected Settings")
- print("----------------------------------------------------------------------------")
- print("Host: " + Host)
- print("Port: " + Port)
- #print("Section: " + Section)
- #print("URL: " + URL)
- #print("OnDeck URL: " + OnDeckURL)
- if KeepMode=="W":
- print("Keep Mode: Keeping for " + str(DaysToKeep) + " days following the date last viewed")
- elif KeepMode=="A":
- print("Keep Mode: Keeping viewed items that were added to the library less than " + str(DaysToKeep) + " days ago")
- else:
- print("Keep Mode: DISABLED")
- ####################################################################################
- ## Checking Shows
- ####################################################################################
- NoDelete = " | "
- ShowCount = len(Shows)
- print("Show Count: " + str(ShowCount))
- for Show in Shows:
- Show = re.sub('[^A-Za-z0-9 ]+', '', Show).strip()
- if Show=="":
- NoDelete += "(None Listed) | "
- ShowCount -= 1
- else:
- NoDelete += Show + " | "
- print("Number of Shows Detected For Keeping: " + str(ShowCount))
- print ("Shows to Keep:" + NoDelete)
- ###################################################################################
- ## Checking Delete
- ####################################################################################
- if Delete=="1":
- print("Delete: ***Enabled***")
- else:
- print("Delete: Disabled - Flagging Only")
- if OnDeck=="1":
- print("Delete OnDeck: No")
- else:
- print("Delete OnDeck: Yes")
- ####################################################################################
- ## Checking OS
- ####################################################################################
- AD = ""
- if PC=="":
- AD = "(Auto Detected)"
- if platform.system()=="Windows":
- PC = "W"
- elif platform.system()=="Linux":
- PC = "L"
- elif platform.system()=="Darwin":
- PC = "L"
- FileCount = 0
- DeleteCount = 0
- MoveCount = 0
- CopyCount = 0
- FlaggedCount = 0
- OnDeckCount = 0
- ShowsCount = 0
- RescannedSections = []
- ####################################################################################
- ## Get list of sections
- ####################################################################################
- if PC=="L":
- print("Operating System: Linux " + AD)
- import urllib2
- elif PC=="W":
- print("Operating System: Windows " + AD)
- import urllib.request
- else:
- print("Operating System: ** Not Configured ** (" + platform.system() + ") is not recognized.")
- exit()
- if not SectionList:
- URL = ("http://" + Host + ":" + Port + "/library/sections/")
- doc = xml.dom.minidom.parse(urllib2.urlopen(URL))
- for Section in doc.getElementsByTagName("Directory"):
- if Section.getAttribute("key") not in IgnoreSections:
- SectionList.append(Section.getAttribute("key"))
- SectionList.sort(key=int)
- print ("Section List Mode: Auto")
- print ("Operating on sections: " + ','.join(str(x) for x in SectionList))
- print ("Skipping Sections: " + ','.join(str(x) for x in IgnoreSections))
- else:
- print ("Section List Mode: User-defined")
- print ("Operating on user-defined sections: " + ','.join(str(x) for x in SectionList))
- ####################################################################################
- ## Loop on sections
- ####################################################################################
- rescan_destination = False
- for Section in SectionList:
- Section = str(Section)
- URL = ("http://" + Host + ":" + Port + "/library/sections/" + Section + "/recentlyViewed")
- OnDeckURL = ("http://" + Host + ":" + Port + "/library/sections/" + Section + "/onDeck")
- ####################################################################################
- ## Setting OS Based Variables
- ####################################################################################
- if PC=="L":
- doc = xml.dom.minidom.parse(urllib2.urlopen(URL))
- deck = xml.dom.minidom.parse(urllib2.urlopen(OnDeckURL))
- elif PC=="W":
- doc = xml.dom.minidom.parse(urllib.request.urlopen(URL))
- deck = xml.dom.minidom.parse(urllib.request.urlopen(OnDeckURL))
- SectionName = doc.getElementsByTagName("MediaContainer")[0].getAttribute("title1")
- print("")
- print("--------- Section "+ Section +": " + SectionName + " -----------------------------------")
- ####################################################################################
- ## Get Files for Watched Shows
- ####################################################################################
- changed = 0
- for VideoNode in doc.getElementsByTagName("Video"):
- view = VideoNode.getAttribute("viewCount")
- if view == '':
- view = 0
- view = int(view)
- ################################################################
- ###Find number of days between date video was viewed and today
- lastViewedAt = VideoNode.getAttribute("lastViewedAt")
- d1 = datetime.datetime.today()
- d2 = datetime.datetime.fromtimestamp(float(lastViewedAt))
- DaysSinceVideoLastViewed = (d1 - d2).days
- ################################################################
- ################################################################
- ###Find number of days between date video was added and today
- addedAt = VideoNode.getAttribute("addedAt")
- d1 = datetime.datetime.today()
- da2 = datetime.datetime.fromtimestamp(float(addedAt))
- DaysSinceVideoAdded = (d1 - da2).days
- ################################################################
- MediaNode = VideoNode.getElementsByTagName("Media")
- for Media in MediaNode:
- PartNode = Media.getElementsByTagName("Part")
- for Part in PartNode:
- file = Part.getAttribute("file")
- #NEW (Removed by Mustang):
- #if PC == 'L':
- #file = urllib2.unquote(file.encode('utf-8')).decode('utf-8')
- #else:
- #import urllib
- #file = urllib.parse.unquote(file.encode('utf-8')).decode('utf-8')
- if str(view)!="0":
- print(" ")
- if KeepMode=="W":
- if str(view)!="0":
- print ("Viewed:" + str(view) + "x | Days Since Viewed: " + str(DaysSinceVideoLastViewed) + " | " + file)
- if view > 0:
- if os.path.isfile(file):
- changed += CheckShows(file);
- else:
- print("##[NOT FOUND] " + file)
- if KeepMode=="A":
- if str(view)!="0":
- print ("Viewed:" + str(view) + "x | Days Since Added: " + str(DaysSinceVideoAdded) + " | " + file)
- if view > 0:
- if os.path.isfile(file):
- changed += CheckShows(file);
- else:
- print("##[NOT FOUND] " + file)
- if KeepMode=="":
- if str(view)!="0":
- print ("Viewed:" + str(view) + "x | Days Since Viewed: " + str(DaysSinceVideoLastViewed) + " Added: " + str(DaysSinceVideoAdded) + " | " + file)
- if view > 0:
- if os.path.isfile(file):
- changed += CheckShows(file);
- else:
- print("##[NOT FOUND] " + file)
- # rescan this section if necessary
- if TriggerRescan and changed:
- URL = ("http://" + Host + ":" + Port + "/library/sections/" + Section + "/refresh?deep=1")
- blah = urllib2.urlopen(URL)
- RescannedSections.append(SectionName + '(' + Section + ')')
- rescan_destination = True
- # rescan destination section if necessary
- if TriggerRescan and DestinationSection and rescan_destination:
- URL = ("http://" + Host + ":" + Port + "/library/sections/" + str(DestinationSection) + "/refresh?deep=1")
- blah = urllib2.urlopen(URL)
- RescannedSections.append('[destination dir]' + '(' + str(DestinationSection) + ')')
- print("")
- print("----------------------------------------------------------------------------")
- print("----------------------------------------------------------------------------")
- print(" Summary -- Script Completed Successfully")
- print("----------------------------------------------------------------------------")
- print("")
- print(" Total File Count " + str(FileCount))
- print(" Kept Show Files " + str(ShowsCount))
- print(" On Deck Files " + str(OnDeckCount))
- print(" Deleted Files " + str(DeleteCount))
- print(" Moved Files " + str(MoveCount))
- print(" Copied Files " + str(CopyCount))
- print(" Flagged Files " + str(FlaggedCount))
- print(" Rescanned Sections " + ', '.join(str(x) for x in RescannedSections) )
- print("")
- print("----------------------------------------------------------------------------")
- print("----------------------------------------------------------------------------")
Advertisement
Add Comment
Please, Sign In to add comment