Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Cazzar/ShokoMetadata.bundle
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.4.2
Choose a base ref
...
head repository: Cazzar/ShokoMetadata.bundle
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
  • 10 commits
  • 5 files changed
  • 2 contributors

Commits on Dec 9, 2019

  1. Copy the full SHA
    3d2e403 View commit details

Commits on May 10, 2020

  1. Add single season ordering and separate 'IncludeOthers' into two pref…

    …erences (#38)
    
    * Added preference for single season ordering
    harshithmohan authored May 10, 2020
    Copy the full SHA
    bd9ec18 View commit details

Commits on May 17, 2020

  1. Copy the full SHA
    d0b49c6 View commit details

Commits on Jun 12, 2020

  1. Fix issue with multiple movies in one series (#40)

    * Update movie scanner to match series scanner and remove unneeded things
    
    * Fix issue with multiple movies in one series
    
    * Use try_get for movie aid and fix manual movie searching
    
    * Encode the filename (utf-8), remove a blank line
    
    * Fix filename
    
    * Add a missing parenthesis
    
    * Don't scan series in Movie Scanner
    
    * Don't scan extras
    harshithmohan authored Jun 12, 2020
    Copy the full SHA
    4ecdaf7 View commit details

Commits on Jul 15, 2020

  1. Create codeql-analysis.yml

    Cazzar authored Jul 15, 2020
    Copy the full SHA
    bbf3257 View commit details

Commits on Aug 29, 2020

  1. Merge pull request #41 from Cazzar/devel

    Devel
    Cazzar authored Aug 29, 2020
    Copy the full SHA
    c3db3e0 View commit details

Commits on Jan 6, 2021

  1. Copy the full SHA
    036d4f4 View commit details
  2. Merge pull request #44 from harshithmohan/devel-testing

    Make movie collections better
    Cazzar authored Jan 6, 2021
    Copy the full SHA
    e56cd32 View commit details

Commits on Mar 25, 2022

  1. Copy the full SHA
    7b545b5 View commit details
  2. Merge pull request #47 from Cazzar/devel

    Devel
    Cazzar authored Mar 25, 2022
    Copy the full SHA
    a78b876 View commit details
54 changes: 54 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: "CodeQL"

on:
push:
branches: [master, develop]
pull_request:
# The branches below must be a subset of the branches above
branches: [develop]
schedule:
- cron: '0 6 * * 5'

jobs:
analyse:
name: Analyse
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2

# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
115 changes: 81 additions & 34 deletions Contents/Code/__init__.py
Original file line number Diff line number Diff line change
@@ -74,15 +74,40 @@ def Search(self, results, media, lang, manual, movie):

# http://127.0.0.1:8111/api/serie/search?query=Clannad&level=1&apikey=d422dfd2-bdc3-4219-b3bb-08b85aa65579

prelimresults = HttpReq("api/serie/search?query=%s&level=%d&fuzzy=%d" % (urllib.quote(name.encode('utf8')), 1, Prefs['Fuzzy']))
if movie:
if media.filename:
filename = os.path.basename(urllib.unquote(media.filename))

for result in prelimresults:
#for result in group['series']:
score = 100 if result['name'] == name else 85 # TODO: Improve this to respect synonyms./
meta = MetadataSearchResult('%s' % result['id'], result['name'], try_get(result, 'year', None), score, lang)
results.Append(meta)
episode_data = HttpReq("api/ep/getbyfilename?filename=%s" % (urllib.quote(filename.encode('utf8'))))
movie_data = HttpReq("api/serie/fromep?id=%s" % (episode_data['id']))

# results.Sort('score', descending=True)
score = 100 if movie_data['name'] == name else 85 # TODO: Improve this to respect synonyms./
title = movie_data['name'] + ' - ' + episode_data['name']
meta = MetadataSearchResult('%s' % (episode_data['id']), title, try_get(episode_data, 'year', None), score, lang)
results.Append(meta)

else: # For manual searches
prelimresults = HttpReq("api/serie/search?query=%s&level=%d&fuzzy=%d&ismovie=1" % (urllib.quote(name.encode('utf8')), 2, Prefs['Fuzzy']))

for result in prelimresults:
for episode in result['eps']:
title = result['name'] + ' - ' + episode['name']
if title == name: score = 100 # Check if full name matches (Series name + episode name)
elif result['name'] == name: score = 90 # Check if series name matches
else: score = 80
meta = MetadataSearchResult('%s' % (episode['id']), title, try_get(episode, 'year', None), score, lang)
results.Append(meta)

else:
prelimresults = HttpReq("api/serie/search?query=%s&level=%d&fuzzy=%d" % (urllib.quote(name.encode('utf8')), 1, Prefs['Fuzzy']))

for result in prelimresults:
#for result in group['series']:
score = 100 if result['name'] == name else 85 # TODO: Improve this to respect synonyms./
meta = MetadataSearchResult('%s' % result['id'], result['name'], try_get(result, 'year', None), score, lang)
results.Append(meta)

# results.Sort('score', descending=True)

def Update(self, metadata, media, lang, force, movie):
Log("update(%s)" % metadata.id)
@@ -100,18 +125,48 @@ def Update(self, metadata, media, lang, force, movie):
flags = flags | Prefs['hideUsefulMiscTags'] << 3 #0b01000 : Hide Useful Miscellaneous Tags
flags = flags | Prefs['hideSpoilerTags'] << 4 #0b10000 : Hide Plot Spoiler Tags

if movie:
series = HttpReq("api/serie/fromep?id=%s&level=3&allpics=1&tagfilter=%d" % (aid, flags))
movie_episode_data = HttpReq("api/ep?id=%s" % (aid))
aid = try_get(series, 'id', None)
if not aid:
Log('Error! Series not found.')
return

if movie_episode_data['name'] == 'Complete Movie':
movie_name = series['name']
movie_sort_name = series['name']
else:
movie_name = series['name'] + ' - ' + movie_episode_data['name']
movie_sort_name = series['name'] + ' - ' + str(movie_episode_data['epnumber']).zfill(3)

metadata.summary = summary_sanitizer(try_get(series, 'summary'))
metadata.title = movie_name
metadata.title_sort = movie_sort_name
metadata.rating = float(movie_episode_data['rating'])
year = try_get(movie_episode_data, "year", try_get(series, "year", None))

if year:
metadata.year = int(year)

collections = []
if series['localsize'] > 1:
collections.append(series['name'])

else:
series = HttpReq("api/serie?id=%s&level=3&allpics=1&tagfilter=%d" % (aid, flags))

metadata.summary = summary_sanitizer(try_get(series, 'summary'))
metadata.title = series['name']
metadata.rating = float(series['rating'])

groupinfo = HttpReq("api/serie/groups?id=%s&level=2" % aid);
collections = []
for group in groupinfo:
if (len(group['series']) > 1):
collections.append(group['name'])

series = HttpReq("api/serie?id=%s&level=3&allpics=1&tagfilter=%d" % (aid, flags))

# build metadata on the TV show.
#metadata.summary = re.sub(LINK_REGEX, r'\1', try_get(series, 'summary'))
metadata.summary = summary_sanitizer(try_get(series, 'summary'))
metadata.title = series['name']
metadata.rating = float(series['rating'])
year = try_get(series, "year", None)

#if year:
# metadata.year = int(year)
metadata.collections = collections

tags = []
for tag in try_get(series, 'tags', []):
@@ -123,15 +178,6 @@ def Update(self, metadata, media, lang, force, movie):
self.metadata_add(metadata.posters, try_get(series['art'], 'thumb', []))
self.metadata_add(metadata.art, try_get(series['art'], 'fanart', []))

groupinfo = HttpReq("api/serie/groups?id=%s&level=2" % aid);
collections = []
for group in groupinfo:
if (len(group['series']) > 1):
collections.append(group['name'])

metadata.collections = collections



### Generate general content ratings.
### VERY rough approximation to: https://www.healthychildren.org/English/family-life/Media/Pages/TV-Ratings-A-Guide-for-Parents.aspx
@@ -184,13 +230,14 @@ def Update(self, metadata, media, lang, force, movie):
if ep['eptype'] == "Episode": season = 1
elif ep['eptype'] == "Special": season = 0
elif ep['eptype'] == "Credits": season = -1
elif ep['eptype'] == "Trailer": season = -2;
try:
season = int(ep['season'].split('x')[0])
if season <= 0 and ep['eptype'] == 'Episode': season = 1
elif season > 0 and ep['eptype'] == 'Special': season = 0
except:
pass
elif ep['eptype'] == "Trailer": season = -2
if not Prefs['SingleSeasonOrdering']:
try:
season = int(ep['season'].split('x')[0])
if season <= 0 and ep['eptype'] == 'Episode': season = 1
elif season > 0 and ep['eptype'] == 'Special': season = 0
except:
pass

episodeObj = metadata.seasons[season].episodes[ep['epnumber']]
episodeObj.title = ep['name']
7 changes: 7 additions & 0 deletions Contents/DefaultPrefs.json
Original file line number Diff line number Diff line change
@@ -29,6 +29,13 @@
"default": "8111"
},

{
"id": "SingleSeasonOrdering",
"label": "Use single season ordering (IMPORTANT: Make sure the setting in scanner matches with this!)",
"type": "bool",
"default": false
},

{
"id": "Fuzzy",
"label": "Use fuzzy searching in Shoko for matching the titles.",
139 changes: 80 additions & 59 deletions Contents/Resources/Movies/Shoko Movie Scanner.py
Original file line number Diff line number Diff line change
@@ -8,22 +8,46 @@
'Port': 8111,
'Username': 'Default',
'Password': '',
'IncludeOther': True
}

API_KEY = ''

def log(methodName, message, *args):
'''
Create a log message given the message and arguments
'''
logMsg = message
# Replace the arguments in the string
if args:
logMsg = message % args

logMsg = methodName + ' :: ' + logMsg
print logMsg
### Log + LOG_PATH calculated once for all calls ###
import logging, logging.handlers #
RootLogger = logging.getLogger('main')
RootHandler = None
RootFormatting = logging.Formatter('%(message)s') #%(asctime)-15s %(levelname)s -
RootLogger.setLevel(logging.DEBUG)
Log = RootLogger

FileListLogger = logging.getLogger('FileListLogger')
FileListHandler = None
FileListFormatting = logging.Formatter('%(message)s')
FileListLogger.setLevel(logging.DEBUG)
LogFileList = FileListLogger.info

def set_logging(instance, filename):
global RootLogger, RootHandler, RootFormatting, FileListLogger, FileListHandler, FileListFormatting
logger, handler, formatting, backup_count = [RootLogger, RootHandler, RootFormatting, 9] if instance=="Root" else [FileListLogger, FileListHandler, FileListFormatting, 1]
if handler: logger.removeHandler(handler)
handler = logging.handlers.RotatingFileHandler(os.path.join(LOG_PATH, filename), maxBytes=10*1024*1024, backupCount=backup_count) #handler = logging.FileHandler(os.path.join(LOG_PATH, filename), mode)
#handler.setFormatter(formatting)
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
if instance=="Root": RootHandler = handler
else: FileListHandler = handler

### Check config files on boot up then create library variables ### #platform = xxx if callable(getattr(sys,'platform')) else ""
import inspect
LOG_PATH = os.path.abspath(os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), "..", "..", "Logs"))
if not os.path.isdir(LOG_PATH):
path_location = { 'Windows': '%LOCALAPPDATA%\\Plex Media Server',
'MacOSX': '$HOME/Library/Application Support/Plex Media Server',
'Linux': '$PLEX_HOME/Library/Application Support/Plex Media Server' }
try: path = os.path.expandvars(path_location[Platform.OS.lower()] if Platform.OS.lower() in path_location else '~') # Platform.OS: Windows, MacOSX, or Linux
except: pass #os.makedirs(LOG_PATH) # User folder on MacOS-X
LOG_FILE_LIBRARY = LOG_FILE = 'Shoko Metadata Movie Scanner.log' # Log filename library will include the library name, LOG_FILE not and serve as reference
set_logging("Root", LOG_FILE_LIBRARY)


def HttpPost(url, postdata):
@@ -33,16 +57,24 @@ def HttpPost(url, postdata):
return json.load(urllib2.urlopen(req, postdata))


def HttpReq(url, authenticate=True):
log('HttpReq' ,"Requesting: %s", url)
def HttpReq(url, authenticate=True, retry=True):
global API_KEY
Log.info("Requesting: %s", url)
api_string = ''
if authenticate:
api_string = '&apikey=%s' % GetApiKey()

myheaders = {'Accept': 'application/json'}

req = urllib2.Request('http://%s:%s/%s%s' % (Prefs['Hostname'], Prefs['Port'], url, api_string), headers=myheaders)
return json.load(urllib2.urlopen(req))
try:
req = urllib2.Request('http://%s:%s/%s%s' % (Prefs['Hostname'], Prefs['Port'], url, api_string), headers=myheaders)
return json.load(urllib2.urlopen(req))
except Exception, e:
if not retry:
raise e

API_KEY = ''
return HttpReq(url, authenticate, False)


def GetApiKey():
@@ -52,61 +84,50 @@ def GetApiKey():
data = '{"user":"%s", "pass":"%s", "device":"%s"}' % (
Prefs['Username'], Prefs['Password'] if Prefs['Password'] != None else '', 'Shoko Series Scanner For Plex')
resp = HttpPost('api/auth', data)['apikey']
log('GetApiKey', "Got API KEY: %s", resp)
Log.info( "Got API KEY: %s", resp)
API_KEY = resp
return resp

return API_KEY


def Scan(path, files, mediaList, subdirs, language=None, root=None):
log('Scan', 'path: %s', path)
log('Scan', 'files: %s', files)
log('Scan', 'mediaList: %s', mediaList)
log('Scan', 'subdirs: %s', subdirs)
log('Scan', 'language: %s', language)
log('Scan', 'root: %s', root)


Log.debug('path: %s', path)
Log.debug('files: %s', files)
Log.debug('subdirs: %s', subdirs)

# Scan for video files.
VideoFiles.Scan(path, files, mediaList, subdirs, root)

for idx, file in enumerate(files):
log('Scan', 'file: %s', file)
# http://127.0.0.1:8111/api/ep/getbyfilename?apikey=d422dfd2-bdc3-4219-b3bb-08b85aa65579&filename=%5Bjoseole99%5D%20Clannad%20-%2001%20(1280x720%20Blu-ray%20H264)%20%5B8E128DF5%5D.mkv

episode_data = HttpReq("api/ep/getbyfilename?filename=%s" % (urllib.quote(os.path.basename(file))))
if len(episode_data) == 0: break
if (try_get(episode_data, "code", 200) == 404): break

series_data = HttpReq("api/serie/fromep?id=%d&nocast=1&notag=1" % episode_data['id'])
showTitle = series_data['name'].encode("utf-8") #no idea why I need to do this.
log('Scan', 'show title: %s', showTitle)

seasonYear = episode_data['year']
log('Scan', 'season year: %s', seasonYear)
seasonNumber = 0
seasonStr = try_get(episode_data, 'season', None)
if episode_data['eptype'] == 'Credits': seasonNumber = -1 #season -1 for OP/ED
elif episode_data['eptype'] == 'Trailer': seasonNumber = -2 #season -2 for Trailer
elif seasonStr == None:
if episode_data['eptype'] == 'Episode': seasonNumber = 1
elif episode_data['eptype'] == 'Special': seasonNumber = 0
else:
seasonNumber = int(seasonStr.split('x')[0])
if seasonNumber <= 0 and episode_data['eptype'] == 'Episode': seasonNumber = 1

if seasonNumber <= 0 and Prefs['IncludeOther'] == False: continue #Ignore this by choice.

if (try_get(series_data, "ismovie", 0) == 0 or seasonNumber <= 0):
continue
vid = Media.Movie(showTitle, int(seasonYear))
log('Scan', 'vid: %s', vid)
vid.parts.append(file)
mediaList.append(vid)

log('Scan', 'stack media')
try:
Log.info('file: %s', file)
# http://127.0.0.1:8111/api/ep/getbyfilename?apikey=d422dfd2-bdc3-4219-b3bb-08b85aa65579&filename=%5Bjoseole99%5D%20Clannad%20-%2001%20(1280x720%20Blu-ray%20H264)%20%5B8E128DF5%5D.mkv

episode_data = HttpReq("api/ep/getbyfilename?filename=%s" % (urllib.quote(os.path.basename(file))))
if len(episode_data) == 0: continue
if (try_get(episode_data, "code", 200) == 404): continue

series_data = HttpReq("api/serie/fromep?id=%d&nocast=1&notag=1" % episode_data['id'])
if not (try_get(series_data, "ismovie", 0)) or (episode_data['eptype'] != 'Episode'): continue # Skip series and extras
showTitle = series_data['name'].encode("utf-8") #no idea why I need to do this.
Log.info('show title: %s', showTitle)

seasonYear = episode_data['year']
Log.info('season year: %s', seasonYear)

vid = Media.Movie(showTitle, int(seasonYear))
Log.info('vid: %s', vid)
vid.parts.append(file)
mediaList.append(vid)
except Exception as e:
Log.error("Error in Scan: '%s'" % e)
continue

Log.info('Scan', 'stack media')
Stack.Scan(path, files, mediaList, subdirs)
log('Scan', 'media list %s', mediaList)
Log.info('Scan', 'media list %s', mediaList)


def try_get(arr, idx, default=""):
Loading