Subliminal update
This commit is contained in:
1 parent
4dfd8b4cd5
commit
67c87444de
163 files changed
+22377
-804
No files matched your search
@@ -18,7 +18,8 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from guessit import Guess
|
||||
from __future__ import unicode_literals
|
||||
from guessit import base_text_type, Guess
|
||||
from guessit.patterns import canonical_form
|
||||
from guessit.textutils import clean_string
|
||||
import logging
|
||||
@@ -41,7 +42,7 @@ def format_guess(guess):
|
||||
if prop in ('season', 'episodeNumber', 'year', 'cdNumber',
|
||||
'cdNumberTotal', 'bonusNumber', 'filmNumber'):
|
||||
guess[prop] = int(guess[prop])
|
||||
elif isinstance(value, basestring):
|
||||
elif isinstance(value, base_text_type):
|
||||
if prop in ('edition',):
|
||||
value = clean_string(value)
|
||||
guess[prop] = canonical_form(value)
|
||||
@@ -63,7 +64,7 @@ def find_and_split_node(node, strategy, logger):
|
||||
|
||||
if isinstance(result, Guess):
|
||||
if confidence is None:
|
||||
confidence = result.confidence(result.keys()[0])
|
||||
confidence = result.confidence(list(result.keys())[0])
|
||||
else:
|
||||
if confidence is None:
|
||||
confidence = 1.0
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.transfo import found_property
|
||||
import logging
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# GuessIt - A library for guessing information from filenames
|
||||
# Copyright (c) 2012 Nicolas Wack <wackou@gmail.com>
|
||||
#
|
||||
# GuessIt is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the Lesser GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GuessIt is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# Lesser GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the Lesser GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
#from guessit.transfo import SingleNodeGuesser
|
||||
#from guessit.date import search_year
|
||||
from guessit.country import Country
|
||||
from guessit import Guess
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def process(mtree):
|
||||
for node in mtree.unidentified_leaves():
|
||||
# only keep explicit groups (enclosed in parentheses/brackets)
|
||||
if len(node.node_idx) == 2:
|
||||
try:
|
||||
country = Country(node.value[1:-1], strict=True)
|
||||
if node.value[0] + node.value[-1] not in ['()', '[]', '{}']:
|
||||
continue
|
||||
node.guess = Guess(country=country, confidence=1.0)
|
||||
|
||||
except ValueError:
|
||||
pass
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.date import search_date
|
||||
import logging
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.transfo import found_property
|
||||
from guessit.patterns import non_episode_title, unlikely_series
|
||||
import logging
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit import Guess
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.patterns import episode_rexps
|
||||
@@ -27,30 +28,35 @@ import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def number_list(s):
|
||||
return re.sub('[^0-9]+', ' ', s).split()
|
||||
return list(re.sub('[^0-9]+', ' ', s).split())
|
||||
|
||||
def guess_episodes_rexps(string):
|
||||
for rexp, confidence, span_adjust in episode_rexps:
|
||||
match = re.search(rexp, string, re.IGNORECASE)
|
||||
if match:
|
||||
result = (Guess(match.groupdict(), confidence=confidence),
|
||||
(match.start() + span_adjust[0],
|
||||
match.end() + span_adjust[1]))
|
||||
guess = Guess(match.groupdict(), confidence=confidence)
|
||||
span = (match.start() + span_adjust[0],
|
||||
match.end() + span_adjust[1])
|
||||
|
||||
# episodes which have a season > 25 are most likely errors
|
||||
# (Simpsons is at 23!)
|
||||
if int(result[0].get('season', 0)) > 25:
|
||||
# (Simpsons is at 24!)
|
||||
if int(guess.get('season', 0)) > 25:
|
||||
continue
|
||||
|
||||
# decide whether we have only a single episode number or an
|
||||
# episode list
|
||||
if result[0].get('episodeNumber'):
|
||||
eplist = number_list(result[0]['episodeNumber'])
|
||||
result[0].set('episodeNumber', int(eplist[0]), confidence=confidence)
|
||||
if guess.get('episodeNumber'):
|
||||
eplist = number_list(guess['episodeNumber'])
|
||||
guess.set('episodeNumber', int(eplist[0]), confidence=confidence)
|
||||
|
||||
if len(eplist) > 1:
|
||||
result[0].set('episodeList', map(int, eplist), confidence=confidence)
|
||||
guess.set('episodeList', list(map(int, eplist)), confidence=confidence)
|
||||
|
||||
return result
|
||||
if guess.get('bonusNumber'):
|
||||
eplist = number_list(guess['bonusNumber'])
|
||||
guess.set('bonusNumber', int(eplist[0]), confidence=confidence)
|
||||
|
||||
return guess, span
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
@@ -18,9 +18,12 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit import Guess
|
||||
from guessit.patterns import (subtitle_exts, video_exts, episode_rexps,
|
||||
find_properties, canonical_form)
|
||||
from guessit.date import valid_year
|
||||
from guessit.textutils import clean_string
|
||||
import os.path
|
||||
import re
|
||||
import mimetypes
|
||||
@@ -28,34 +31,22 @@ import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# List of well known movies and series, hardcoded because they cannot be
|
||||
# guessed appropriately otherwise
|
||||
MOVIES = [ 'OSS 117' ]
|
||||
SERIES = [ 'Band of Brothers' ]
|
||||
|
||||
def guess_filetype(filename, filetype):
|
||||
other = {}
|
||||
|
||||
# look at the extension first
|
||||
fileext = os.path.splitext(filename)[1][1:].lower()
|
||||
if fileext in subtitle_exts:
|
||||
if 'movie' in filetype:
|
||||
filetype = 'moviesubtitle'
|
||||
elif 'episode' in filetype:
|
||||
filetype = 'episodesubtitle'
|
||||
else:
|
||||
filetype = 'subtitle'
|
||||
other = { 'container': fileext }
|
||||
elif fileext in video_exts:
|
||||
if filetype == 'autodetect':
|
||||
filetype = 'video'
|
||||
other = { 'container': fileext }
|
||||
else:
|
||||
if filetype == 'autodetect':
|
||||
filetype = 'unknown'
|
||||
other = { 'extension': fileext }
|
||||
MOVIES = [ m.lower() for m in MOVIES ]
|
||||
SERIES = [ s.lower() for s in SERIES ]
|
||||
|
||||
def guess_filetype(mtree, filetype):
|
||||
# put the filetype inside a dummy container to be able to have the
|
||||
# following functions work correctly as closures
|
||||
# this is a workaround for python 2 which doesn't have the
|
||||
# 'nonlocal' keyword (python 3 does have it)
|
||||
filetype_container = [filetype]
|
||||
other = {}
|
||||
filename = mtree.string
|
||||
|
||||
def upgrade_episode():
|
||||
if filetype_container[0] == 'video':
|
||||
@@ -69,14 +60,82 @@ def guess_filetype(filename, filetype):
|
||||
elif filetype_container[0] == 'subtitle':
|
||||
filetype_container[0] = 'moviesubtitle'
|
||||
|
||||
def upgrade_subtitle():
|
||||
if 'movie' in filetype_container[0]:
|
||||
filetype_container[0] = 'moviesubtitle'
|
||||
elif 'episode' in filetype_container[0]:
|
||||
filetype_container[0] = 'episodesubtitle'
|
||||
else:
|
||||
filetype_container[0] = 'subtitle'
|
||||
|
||||
def upgrade(type='unknown'):
|
||||
if filetype_container[0] == 'autodetect':
|
||||
filetype_container[0] = type
|
||||
|
||||
|
||||
# look at the extension first
|
||||
fileext = os.path.splitext(filename)[1][1:].lower()
|
||||
if fileext in subtitle_exts:
|
||||
upgrade_subtitle()
|
||||
other = { 'container': fileext }
|
||||
elif fileext in video_exts:
|
||||
upgrade(type='video')
|
||||
other = { 'container': fileext }
|
||||
else:
|
||||
upgrade(type='unknown')
|
||||
other = { 'extension': fileext }
|
||||
|
||||
|
||||
|
||||
# check whether we are in a 'Movies', 'Tv Shows', ... folder
|
||||
folder_rexps = [ (r'Movies?', upgrade_movie),
|
||||
(r'Tv ?Shows?', upgrade_episode),
|
||||
(r'Series', upgrade_episode)
|
||||
]
|
||||
for frexp, upgrade_func in folder_rexps:
|
||||
frexp = re.compile(frexp, re.IGNORECASE)
|
||||
for pathgroup in mtree.children:
|
||||
if frexp.match(pathgroup.value):
|
||||
upgrade_func()
|
||||
|
||||
# check for a few specific cases which will unintentionally make the
|
||||
# following heuristics confused (eg: OSS 117 will look like an episode,
|
||||
# season 1, epnum 17, when it is in fact a movie)
|
||||
fname = clean_string(filename).lower()
|
||||
for m in MOVIES:
|
||||
if m in fname:
|
||||
upgrade_movie()
|
||||
for s in SERIES:
|
||||
if s in fname:
|
||||
upgrade_episode()
|
||||
|
||||
# now look whether there are some specific hints for episode vs movie
|
||||
if filetype in ('video', 'subtitle'):
|
||||
if filetype_container[0] in ('video', 'subtitle'):
|
||||
# if we have an episode_rexp (eg: s02e13), it is an episode
|
||||
for rexp, _, _ in episode_rexps:
|
||||
match = re.search(rexp, filename, re.IGNORECASE)
|
||||
if match:
|
||||
upgrade_episode()
|
||||
break
|
||||
|
||||
# if we have a 3-4 digit number that's not a year, maybe an episode
|
||||
match = re.search(r'[^0-9]([0-9]{3,4})[^0-9]', filename)
|
||||
if match:
|
||||
fullnumber = int(match.group()[1:-1])
|
||||
#season = fullnumber // 100
|
||||
epnumber = fullnumber % 100
|
||||
possible = True
|
||||
|
||||
# check for validity
|
||||
if epnumber > 40:
|
||||
possible = False
|
||||
if valid_year(fullnumber):
|
||||
possible = False
|
||||
|
||||
if possible:
|
||||
upgrade_episode()
|
||||
|
||||
# if we have certain properties characteristic of episodes, it is an ep
|
||||
for prop, value, _, _ in find_properties(filename):
|
||||
log.debug('prop: %s = %s' % (prop, value))
|
||||
if prop == 'episodeFormat':
|
||||
@@ -87,6 +146,7 @@ def guess_filetype(filename, filetype):
|
||||
upgrade_episode()
|
||||
break
|
||||
|
||||
# origin-specific type
|
||||
if 'tvu.org.ru' in filename:
|
||||
upgrade_episode()
|
||||
|
||||
@@ -98,7 +158,7 @@ def guess_filetype(filename, filetype):
|
||||
|
||||
|
||||
def process(mtree, filetype='autodetect'):
|
||||
filetype, other = guess_filetype(mtree.string, filetype)
|
||||
filetype, other = guess_filetype(mtree, filetype)
|
||||
|
||||
mtree.guess.set('type', filetype, confidence=1.0)
|
||||
log.debug('Found with confidence %.2f: %s' % (1.0, mtree.guess))
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit import Guess
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.language import search_language
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit import Guess
|
||||
import logging
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.patterns import find_properties
|
||||
import logging
|
||||
|
||||
@@ -18,24 +18,53 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.patterns import properties, canonical_form
|
||||
import re
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
CODECS = properties['videoCodec']
|
||||
FORMATS = properties['format']
|
||||
|
||||
def adjust_metadata(md):
|
||||
codec = canonical_form(md['videoCodec'])
|
||||
if codec in FORMATS:
|
||||
md['format'] = codec
|
||||
del md['videoCodec']
|
||||
return md
|
||||
|
||||
|
||||
def guess_release_group(string):
|
||||
group_names = [ r'\.(Xvid)-(?P<releaseGroup>.*?)[ \.]',
|
||||
r'\.(DivX)-(?P<releaseGroup>.*?)[\. ]',
|
||||
r'\.(DVDivX)-(?P<releaseGroup>.*?)[\. ]',
|
||||
]
|
||||
|
||||
# first try to see whether we have both a known codec and a known release group
|
||||
group_names = [ r'\.(?P<videoCodec>' + codec + r')-(?P<releaseGroup>.*?)[ \.]'
|
||||
for codec in (CODECS + FORMATS) ]
|
||||
|
||||
for rexp in group_names:
|
||||
match = re.search(rexp, string, re.IGNORECASE)
|
||||
if match:
|
||||
metadata = match.groupdict()
|
||||
metadata.update({ 'videoCodec': match.group(1) })
|
||||
return metadata, (match.start() + 1, match.end() - 1)
|
||||
if canonical_form(metadata['releaseGroup']) in properties['releaseGroup']:
|
||||
return adjust_metadata(metadata), (match.start(1), match.end(2))
|
||||
|
||||
# pick anything as releaseGroup as long as we have a codec in front
|
||||
# this doesn't include a potential dash ('-') ending the release group
|
||||
# eg: [...].X264-HiS@SiLUHD-English.[...]
|
||||
group_names = [ r'\.(?P<videoCodec>' + codec + r')-(?P<releaseGroup>.*?)(-(.*?))?[ \.]'
|
||||
for codec in (CODECS + FORMATS) ]
|
||||
|
||||
for rexp in group_names:
|
||||
match = re.search(rexp, string, re.IGNORECASE)
|
||||
if match:
|
||||
return adjust_metadata(match.groupdict()), (match.start(1), match.end(2))
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit import Guess
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.patterns import video_rexps, sep
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit import Guess
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.patterns import weak_episode_rexps
|
||||
@@ -40,8 +41,13 @@ def guess_weak_episodes_rexps(string, node):
|
||||
|
||||
epnum = int(metadata['episodeNumber'])
|
||||
if epnum > 100:
|
||||
return Guess({ 'season': epnum // 100,
|
||||
'episodeNumber': epnum % 100 },
|
||||
season, epnum = epnum // 100, epnum % 100
|
||||
# episodes which have a season > 25 are most likely errors
|
||||
# (Simpsons is at 23!)
|
||||
if season > 25:
|
||||
continue
|
||||
return Guess({ 'season': season,
|
||||
'episodeNumber': epnum },
|
||||
confidence=0.6), span
|
||||
else:
|
||||
return Guess(metadata, confidence=0.3), span
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.patterns import websites
|
||||
import logging
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.transfo import SingleNodeGuesser
|
||||
from guessit.date import search_year
|
||||
import logging
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.patterns import subtitle_exts
|
||||
import logging
|
||||
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.textutils import find_first_level_groups
|
||||
from guessit.patterns import group_delimiters
|
||||
import functools
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -33,10 +35,10 @@ def process(mtree):
|
||||
groups = find_first_level_groups(c.value, group_delimiters[0])
|
||||
for delimiters in group_delimiters:
|
||||
flatten = lambda l, x: l + find_first_level_groups(x, delimiters)
|
||||
groups = reduce(flatten, groups, [])
|
||||
groups = functools.reduce(flatten, groups, [])
|
||||
|
||||
# do not do this at this moment, it is not strong enough and can break other
|
||||
# patterns, such as dates, etc...
|
||||
#groups = reduce(lambda l, x: l + x.split('-'), groups, [])
|
||||
#groups = functools.reduce(lambda l, x: l + x.split('-'), groups, [])
|
||||
|
||||
c.split_on_components(groups)
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit.patterns import sep
|
||||
import re
|
||||
import logging
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from guessit import fileutils
|
||||
import os.path
|
||||
import logging
|
||||
|
||||
Reference in new issue
Block a user