Skip to content

Commit a05c231

Browse files
committed
Merge pull request #111 from dagalufh/micke-work
Micke work
2 parents 97c323e + e0ce84c commit a05c231

31 files changed

+4560
-2051
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Desktop.ini
88
# Recycle Bin used on file shares
99
$RECYCLE.BIN/
1010

11+
# Ignore the UAS cache
12+
http/uas
13+
1114
# Windows Installer files
1215
*.cab
1316
*.msi
30.6 KB
Binary file not shown.
93 KB
Binary file not shown.

Contents/Code/__init__.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,27 @@
1111
######################################################################################################################
1212

1313
#********* Constants used **********
14-
PREFIX = '/utils/webtools'
14+
PREFIX = '/applications/webtools'
15+
1516
NAME = 'WebTools'
1617
ICON = 'WebTools.png'
17-
VERSION = '1.1'
18+
VERSION = '2.0'
19+
AUTHTOKEN = ''
20+
SECRETKEY = ''
1821

1922
#********** Imports needed *********
2023
import os, io, time
2124
from subprocess import call
22-
#import xml.etree.ElementTree as et
23-
#from webSrv import startWeb, stopWeb, webServer
2425
from webSrv import startWeb, stopWeb
2526
from random import randint
27+
import uuid #Used for secrectKey
28+
2629

30+
import datetime
2731

2832
#********** Initialize *********
2933
def Start():
34+
global SECRETKEY
3035
PLUGIN_VERSION = VERSION
3136
print("******** Started %s on %s **********" %(NAME + ' V' + PLUGIN_VERSION, Platform.OS))
3237
Log.Debug("******* Started %s on %s ***********" %(NAME + ' V' + PLUGIN_VERSION, Platform.OS))
@@ -37,9 +42,17 @@ def Start():
3742
ObjectContainer.view_group = 'List'
3843
makeSettings()
3944

40-
# tornado = webServer()
41-
# tornado.startWeb()
42-
startWeb()
45+
# Get the secret key used to access the PMS framework ********** FUTURE USE ***************
46+
SECRETKEY = genSecretKeyAsStr()
47+
startWeb(SECRETKEY)
48+
49+
####################################################################################################
50+
# Generate secret key
51+
####################################################################################################
52+
''' This will generate the secret key, used to access the framework '''
53+
@route(PREFIX + '/genSecretKeyAsStr')
54+
def genSecretKeyAsStr():
55+
return str(uuid.uuid4())
4356

4457
####################################################################################################
4558
# Make Settings file
@@ -86,12 +99,12 @@ def makeSettings():
8699
def MainMenu():
87100
Log.Debug("********** Starting MainMenu **********")
88101
oc = ObjectContainer()
89-
oc.add(DirectoryObject(key=Callback(MainMenu), title="To access this channel, go to"))
102+
oc.add(DirectoryObject(key=Callback(MainMenu), title="To access this channel, type the url's below to a new browser tab"))
90103
if Prefs['Force_SSL']:
91-
oc.add(DirectoryObject(key=Callback(MainMenu), title='https://' + Network.Address + ':' + Prefs['WEB_Port_https'] + '/index.html'))
104+
oc.add(DirectoryObject(key=Callback(MainMenu), title='https://' + Network.Address + ':' + Prefs['WEB_Port_https']))
92105
else:
93-
oc.add(DirectoryObject(key=Callback(MainMenu), title='http://' + Network.Address + ':' + Prefs['WEB_Port_http'] + '/index.html'))
94-
oc.add(DirectoryObject(key=Callback(MainMenu), title='https://' + Network.Address + ':' + Prefs['WEB_Port_https'] + '/index.html'))
106+
oc.add(DirectoryObject(key=Callback(MainMenu), title='http://' + Network.Address + ':' + Prefs['WEB_Port_http']))
107+
oc.add(DirectoryObject(key=Callback(MainMenu), title='https://' + Network.Address + ':' + Prefs['WEB_Port_https']))
95108
oc.add(PrefsObject(title='Preferences', thumb=R('icon-prefs.png')))
96109
Log.Debug("********** Ending MainMenu **********")
97110
return oc
@@ -101,22 +114,12 @@ def MainMenu():
101114
####################################################################################################
102115
@route(PREFIX + '/ValidatePrefs')
103116
def ValidatePrefs():
104-
105-
106-
107-
# r = threading.Thread(target=Restart)
108-
# r.start()
117+
# HTTP.Request('http://127.0.0.1:32400/:/plugins/com.plexapp.plugins.WebTool/restart', immediate=True)
109118
Restart()
110119

111120
@route(PREFIX + '/Restart')
112121
def Restart():
113-
# HTTP.Request('http://127.0.0.1:32400/:/plugins/com.plexapp.plugins.' + NAME + '/restart', immediate=True)
114-
# stopWeb()
115122
time.sleep(3)
116-
startWeb()
117-
123+
startWeb(SECRETKEY)
118124
return
119125

120-
121-
122-

Contents/Code/findUnmatched.py

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
######################################################################################################################
2+
# findUnmatched unit
3+
# A WebTools bundle plugin
4+
#
5+
# Author: dane22, a Plex Community member
6+
#
7+
#
8+
######################################################################################################################
9+
10+
import urllib
11+
import unicodedata
12+
import json
13+
14+
class findUnmatched(object):
15+
# Defaults used by the rest of the class
16+
def __init__(self):
17+
Log.Debug('******* Starting findUnmatched *******')
18+
self.MovieChuncks = 20
19+
self.CoreUrl = 'http://127.0.0.1:32400/library/sections/'
20+
self.default_IGNORED_FILES = ['imdb.nfo', '.DS_Store', '__db.001', 'Thumbs.db', '.plexignore']
21+
self.default_IGNORED_DIRS = ['.@__thumb', '.AppleDouble', 'lost+found']
22+
self.default_VALID_EXTENSIONS = ['.m4v', '.3gp', '.nsv', '.ts', '.ty', '.strm', '.rm', '.rmvb', '.m3u',
23+
'.mov', '.qt', '.divx', '.xvid', '.bivx', '.vob', '.nrg', '.img', '.iso',
24+
'.pva', '.wmv', '.asf', '.asx', '.ogm', '.m2v', '.avi', '.bin', '.dat',
25+
'.dvr-ms', '.mpg', '.mpeg', '.mp4', '.mkv', '.avc', '.vp3', '.svq3', '.nuv',
26+
'.viv', '.dv', '.fli', '.flv', '.rar', '.001', '.wpl', '.zip', '.jpg', '.mp3']
27+
self.default_IGNORED_EXTENSIONS = ['.srt', '.xml', '.idx', '.jpg', '.sub', '.nfo', '.png', '.gif', '.txt', '.rtf',
28+
'.m3u', '.rar', '.sfv', '.md5', '.ico', '.doc', '.zip', '.SRT2UTF-8']
29+
self.default_ALL_EXTENSIONS = False
30+
self.default_ENABLE_PLEXIGNORE = True
31+
self.default_IGNORE_HIDDEN = True
32+
33+
''' Grap the tornado req, and process it '''
34+
def reqprocess(self, req):
35+
function = req.get_argument('function', 'missing')
36+
if function == 'missing':
37+
req.clear()
38+
req.set_status(412)
39+
req.finish("<html><body>Missing function parameter</body></html>")
40+
elif function == 'scanSection':
41+
# Call scanSection with the url
42+
return self.scanSection(req)
43+
else:
44+
req.clear()
45+
req.set_status(412)
46+
req.finish("<html><body>Unknown function call</body></html>")
47+
48+
''' Grap the tornado req, and process it for a PUT request'''
49+
def reqprocessPost(self, req):
50+
function = req.get_argument('function', 'missing')
51+
if function == 'missing':
52+
req.clear()
53+
req.set_status(412)
54+
req.finish("<html><body>Missing function parameter</body></html>")
55+
elif function == 'setSettingstoDefault':
56+
return self.setSettingstoDefault(req)
57+
else:
58+
req.clear()
59+
req.set_status(412)
60+
req.finish("<html><body>Unknown function call</body></html>")
61+
62+
# Save defaults to settings
63+
def setSettingstoDefault(self, req, internal = False):
64+
try:
65+
print 'Ged Set Settings to default'
66+
Log.Debug('findUnmatched set settings to default')
67+
defaults = {}
68+
defaults['IGNORED_FILES'] = self.default_IGNORED_FILES
69+
defaults['IGNORED_DIRS'] = self.default_IGNORED_DIRS
70+
defaults['VALID_EXTENSIONS'] = self.default_VALID_EXTENSIONS
71+
defaults['IGNORED_EXTENSIONS'] = self.default_IGNORED_EXTENSIONS
72+
defaults['ALL_EXTENSIONS'] = self.default_ALL_EXTENSIONS
73+
defaults['ENABLE_PLEXIGNORE'] = self.default_ENABLE_PLEXIGNORE
74+
defaults['IGNORE_HIDDEN'] = self.default_IGNORE_HIDDEN
75+
Dict['findUnmatched'] = defaults
76+
Dict.Save()
77+
req.clear()
78+
req.set_status(200)
79+
req.set_header('Content-Type', 'application/json; charset=utf-8')
80+
req.finish(json.dumps(Dict['findUnmatched']))
81+
except Exception, e:
82+
print 'GED Exception in setSettingstoDefault', str(e)
83+
Log.Debug('Fatal error happened in setSettingstoDefault: ' + str(e))
84+
req.clear()
85+
req.set_status(500)
86+
req.set_header('Content-Type', 'application/json; charset=utf-8')
87+
req.finish('Fatal error happened in getUpdateList: ' + str(e))
88+
89+
90+
# Main call for function.....
91+
def scanSection(self, req):
92+
93+
# Scan the file system
94+
def getFiles(filePath):
95+
try:
96+
97+
Log.Debug('******* Starting getFiles with a path of %s ***********' %(filePath))
98+
print 'GED ******* Starting getFiles with a path of %s ***********' %(filePath)
99+
scannedFiles = []
100+
101+
# Check if Ignored files setting has been populated yet
102+
print 'GED findUnmatched-IGNORED_FILES', Dict['findUnmatched-IGNORED_FILES']
103+
if Dict['findUnmatched-IGNORED_FILES'] == None:
104+
Dict['findUnmatched-IGNORED_FILES'] = self.default_IGNORED_FILES
105+
106+
107+
108+
109+
return []
110+
111+
112+
except Exception, e:
113+
print 'GED Exception', str(e)
114+
115+
116+
117+
118+
# Get a list of all files in a Movie Library
119+
def scanMovieDb(sectionNumber):
120+
try:
121+
mediasFromDB = []
122+
Log.Debug('Starting scanMovieDb for section %s' %(sectionNumber))
123+
# # Start by getting the totals of this section
124+
# totalSize = XML.ElementFromURL(self.CoreUrl + sectionNumber + '/all?X-Plex-Container-Start=1&X-Plex-Container-Size=0').get('totalSize')
125+
# Log.Debug('Total size of medias are %s' %(totalSize))
126+
# So let's walk the library
127+
iStart = 1
128+
while True:
129+
# Grap a chunk from the server
130+
medias = XML.ElementFromURL(self.CoreUrl + sectionNumber + '/all?X-Plex-Container-Start=' + str(iStart) + '&X-Plex-Container-Size=' + str(self.MovieChuncks)).xpath('//Part')
131+
# Walk the chunk
132+
for part in medias:
133+
# iCurrent += 1
134+
filename = part.get('file')
135+
filename = urllib.quote(unicodedata.normalize('NFKC', urllib.unquote(filename).decode('utf8')).encode('utf8'))
136+
# Remove esc backslash if present and on Windows
137+
if Platform.OS == "Windows":
138+
filename = filename.replace(':%5C%5C', ':%5C')
139+
mediasFromDB.append(filename)
140+
iStart += self.MovieChuncks
141+
if len(medias) == 0:
142+
break
143+
return mediasFromDB
144+
except Exception, e:
145+
Log.Debug('Fatal error in scanMovieDb: ' + str(e))
146+
# End scanMovieDb
147+
148+
# ************ Main function ************
149+
Log.Debug('scanSection started')
150+
try:
151+
# Grap the section number from the req
152+
sectionNumber = req.get_argument('section', 'missing')
153+
if sectionNumber == 'missing':
154+
req.clear()
155+
req.set_status(412)
156+
req.finish("<html><body>Missing section parameter</body></html>")
157+
# Let's find out the info of section here
158+
response = XML.ElementFromURL(self.CoreUrl).xpath('//Directory[@key=' + sectionNumber + ']')
159+
sectionTitle = response[0].get('title')
160+
sectionType = response[0].get('type')
161+
locations = response[0].xpath('//Directory[@key=' + sectionNumber + ']/Location')
162+
sectionLocations = []
163+
for location in locations:
164+
sectionLocations.append(location.get('path'))
165+
Log.Debug('Going to scan section %s with a title of %s and a type of %s and locations as %s' %(sectionNumber, sectionTitle, sectionType, str(sectionLocations)))
166+
167+
if sectionType == 'movie':
168+
filesFromDatabase = scanMovieDb(sectionNumber)
169+
170+
171+
# print 'GED filesFromDatabase:', filesFromDatabase
172+
print 'GED number', len(filesFromDatabase)
173+
Log.Debug('************** Files from database *****************')
174+
Log.Debug(filesFromDatabase)
175+
Log.Debug('************** Files from database end *************')
176+
177+
178+
# Now grap files from the filesystem
179+
filesFromFileSystem = []
180+
for filePath in sectionLocations:
181+
filesFromFileSystem.extend(getFiles(filePath))
182+
183+
184+
185+
except Exception, e:
186+
Log.Debug('Fatal error happened in scanSection: ' + str(e))
187+
req.clear()
188+
req.set_status(500)
189+
req.set_header('Content-Type', 'application/json; charset=utf-8')
190+
req.finish('Fatal error happened in scanSection: ' + str(e))
191+
return req
192+

0 commit comments

Comments
 (0)