mirror of
https://github.com/Hellowlol/bw_plex.git
synced 2026-05-12 17:28:30 -05:00
allow multiple themes to the same show, add tvtunes
TODO fix plex.
This commit is contained in:
@@ -97,6 +97,10 @@ class HashTable(object):
|
||||
""" Store a list of hashes in the hash table
|
||||
associated with a particular name (or integer ID) and time.
|
||||
"""
|
||||
#import logging
|
||||
#logging.basicConfig(level=logging.DEBUG)
|
||||
#LOG = logging.getLogger()
|
||||
#LOG.debug('Store shit')
|
||||
id_ = self.name_to_id(name, add_if_missing=True)
|
||||
# Now insert the hashes
|
||||
hashmask = (1 << self.hashbits) - 1
|
||||
|
||||
+67
-150
@@ -8,6 +8,7 @@ import subprocess
|
||||
import tempfile
|
||||
import shutil
|
||||
import time
|
||||
import itertools
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
@@ -77,7 +78,7 @@ def download_theme_plex(media, force=False):
|
||||
if theme is None:
|
||||
theme = media.show().theme
|
||||
|
||||
name = '%s__%s' % (re.sub('[\'\"\\\/;,-]+', '', name), rk) # make a proper cleaning in misc.
|
||||
name = '%s__%s__%s' % (re.sub('[\'\"\\\/;,-]+', '', name), rk, int(time.time())) # make a proper cleaning in misc.
|
||||
f_name = '%s.mp3' % name
|
||||
f_path = os.path.join(THEMES, f_name)
|
||||
|
||||
@@ -136,11 +137,6 @@ def matcher():
|
||||
def get_offset_end(vid, hashtable, check_if_missing=False):
|
||||
an = analyzer()
|
||||
match = matcher()
|
||||
|
||||
# Or should we just check here?? untested.
|
||||
#if vid not in hashtable.names and check_if_missing:
|
||||
# an.ingest(vid, hashtable)
|
||||
|
||||
start_time = -1
|
||||
end_time = -1
|
||||
|
||||
@@ -243,10 +239,8 @@ def find_offset_ffmpeg(afile, trim=600, dev=7, duration_audio=0.5, duration_vide
|
||||
#
|
||||
# ffmpeg -i "W:\Dexter\Season 01\dexter.s01e01.720p.bluray.x264-orpheus.mkv" -t 600 -vf "select='gt(scene,0.4)',showinfo,blackdetect=d=0.5:pix_th=0.10" -af silencedetect=n=-50dB:d=0.5 -f null -
|
||||
#
|
||||
cmd = [
|
||||
'ffmpeg', '-i', afile, '-t', str(trim), '-vf',
|
||||
v, '-af', a, '-f', 'null', '-'
|
||||
]
|
||||
cmd = ['ffmpeg', '-i', afile, '-t', str(trim), '-vf',
|
||||
v, '-af', a, '-f', 'null', '-']
|
||||
|
||||
LOG.debug('Calling find_offset_ffmpeg with command %s', ' '.join(cmd))
|
||||
|
||||
@@ -306,7 +300,7 @@ def get_valid_filename(s):
|
||||
return clean_tail
|
||||
|
||||
|
||||
def convert_and_trim(afile, fs=8000, trim=None, theme=False):
|
||||
def convert_and_trim(afile, fs=8000, trim=None, theme=False, filename=None):
|
||||
tmp = tempfile.NamedTemporaryFile(mode='r+b',
|
||||
prefix='offset_',
|
||||
suffix='.wav')
|
||||
@@ -335,6 +329,11 @@ def convert_and_trim(afile, fs=8000, trim=None, theme=False):
|
||||
LOG.exception(e)
|
||||
raise Exception("FFMpeg failed")
|
||||
|
||||
# Check if we passed a url.
|
||||
if '://' in afile and filename:
|
||||
filename = filename + '.wav'
|
||||
afile = os.path.join(THEMES, filename)
|
||||
|
||||
if theme:
|
||||
shutil.move(tmp_name, afile)
|
||||
LOG.debug('Done converted and moved %s to %s' % (afile, THEMES))
|
||||
@@ -366,11 +365,20 @@ def convert_and_trim_to_mp3(afile, fs=8000, trim=None, outfile=None):
|
||||
|
||||
return outfile
|
||||
|
||||
|
||||
def search_tunes(name, rk):
|
||||
# Pretty much everything is solen from https://github.com/robwebset/script.tvtunes/blob/master/resources/lib/themeFetcher.py
|
||||
# Pretty much everything is stolen from
|
||||
# https://github.com/robwebset/script.tvtunes/blob/master/resources/lib/themeFetcher.py
|
||||
# Thanks!
|
||||
|
||||
titles = ['theme', 'opening', 'main title']
|
||||
baseurl = 'http://www.televisiontunes.com'
|
||||
|
||||
def real_url(url):
|
||||
res = requests.get(url)
|
||||
sub_soup = BeautifulSoup(res.text, 'html5lib')
|
||||
link = sub_soup.find('a', id='download_song')
|
||||
return baseurl + link['href']
|
||||
|
||||
res = requests.get('http://www.televisiontunes.com/search.php', params={'q': name})
|
||||
result = defaultdict(list)
|
||||
if res:
|
||||
@@ -379,28 +387,18 @@ def search_tunes(name, rk):
|
||||
search_results = soup.select('div.jp-title > ul > li > a')
|
||||
if search_results:
|
||||
for sr in search_results:
|
||||
# Since this can be may shows lets atleast try to get the correct one.
|
||||
sname = sr.text.strip()
|
||||
if sname == name:
|
||||
result['%s__%s' % (name, rk)].append(baseurl + sr['href'])
|
||||
txt = sr.text.strip().split(' - ')
|
||||
if len(txt) == 2:
|
||||
sname = txt[0].strip()
|
||||
title = txt[1].strip()
|
||||
else:
|
||||
sname = txt[0].strip()
|
||||
title = ''
|
||||
if sname.lower() == name.lower():
|
||||
if title and any([i for i in titles if i and i.lower() in title.lower()]):
|
||||
result['%s__%s__%s' % (name, rk, int(time.time()))].append(real_url(baseurl + sr['href']))
|
||||
|
||||
fin_res = {}
|
||||
|
||||
if result:
|
||||
# Find the real download url.
|
||||
for k, v in result.items():
|
||||
final_urls = []
|
||||
for item in v:
|
||||
res2 = requests.get(item)
|
||||
if res2:
|
||||
sub_soup = BeautifulSoup(res2.text, 'html5lib')
|
||||
link = sub_soup.find('a', id='download_song')
|
||||
final_urls.append(baseurl + link['href'])
|
||||
|
||||
# this is buggy fix me plx
|
||||
fin_res[k] = final_urls
|
||||
|
||||
return fin_res
|
||||
return result
|
||||
|
||||
|
||||
def search_for_theme_youtube(name, rk=1337, save_path=None, url=None):
|
||||
@@ -438,8 +436,8 @@ def search_for_theme_youtube(name, rk=1337, save_path=None, url=None):
|
||||
'logger': LOG,
|
||||
}
|
||||
# https://github.com/rg3/youtube-dl/issues/6923
|
||||
#ydl_opts['external_downloader'] = 'aria2c'
|
||||
#ydl_opts['external_downloader_args'] = []#['-x', '8', '-s', '8', '-k', '256k']
|
||||
# ydl_opts['external_downloader'] = 'aria2c'
|
||||
# ydl_opts['external_downloader_args'] = []#['-x', '8', '-s', '8', '-k', '256k']
|
||||
|
||||
|
||||
ydl = youtube_dl.YoutubeDL(ydl_opts)
|
||||
@@ -467,28 +465,44 @@ def search_for_theme_youtube(name, rk=1337, save_path=None, url=None):
|
||||
|
||||
|
||||
def download_theme(media, ht, theme_source=None):
|
||||
global PMS
|
||||
if media.TYPE == 'show':
|
||||
name = media.title
|
||||
rk = media.ratingKey
|
||||
#theme = media.theme
|
||||
_theme = media.theme
|
||||
else:
|
||||
name = media.grandparentTitle
|
||||
rk = media.grandparentRatingKey
|
||||
#theme = media.grandparentTheme
|
||||
#if theme is None:
|
||||
# theme = media.show().theme
|
||||
_theme = media.grandparentTheme
|
||||
if _theme is None:
|
||||
_theme = media.show().theme
|
||||
|
||||
if theme_source is None:
|
||||
theme_source = CONFIG.get('theme_source', 'youtube')
|
||||
theme_source = CONFIG.get('theme_source', 'plex')
|
||||
|
||||
if theme_source == 'youtube':
|
||||
theme = search_for_theme_youtube(name, rk, THEMES)
|
||||
|
||||
theme = convert_and_trim(theme, fs=11025, theme=True)
|
||||
elif theme_source == 'tvtunes':
|
||||
theme = search_tunes(name, rk)
|
||||
theme = list(itertools.chain.from_iterable(theme.values()))
|
||||
|
||||
analyzer().ingest(ht, theme)
|
||||
elif theme_source == 'plex': # TODO fix me
|
||||
# Crap, how should we grab pms.
|
||||
theme = PMS.url(_theme, includeToken=True)
|
||||
|
||||
if not isinstance(theme, list):
|
||||
theme = [theme]
|
||||
|
||||
final = []
|
||||
for th in theme:
|
||||
# Filename is just added so we can pass a url to convert_and_trim
|
||||
th = convert_and_trim(th, fs=11025, theme=True, filename='%s__%s__%s' % (name, rk, int(time.time())))
|
||||
analyzer().ingest(ht, th)
|
||||
final.append(th)
|
||||
|
||||
return final
|
||||
|
||||
return theme
|
||||
|
||||
def get_hashtable():
|
||||
LOG.debug('Getting hashtable')
|
||||
@@ -535,34 +549,34 @@ def get_hashtable():
|
||||
"""Cheaper way to lookup stuff."""
|
||||
th = bool(self.get_theme(media))
|
||||
|
||||
if add_if_missing is False:
|
||||
return th
|
||||
else:
|
||||
if th is False and add_if_missing is True:
|
||||
th = download_theme(media, self)
|
||||
if th:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
def get_theme(self, media):
|
||||
if media.TYPE == 'show':
|
||||
name = media.title
|
||||
rk = media.ratingKey
|
||||
else:
|
||||
rk = media.grandparentRatingKey
|
||||
name = media.grandparentTitle
|
||||
|
||||
d = self.get_themes()
|
||||
d = self.get_themes().get(rk, [])
|
||||
LOG.debug('Checking if %s has %s themes', name, len(d))
|
||||
|
||||
return d.get(rk, [])
|
||||
return d
|
||||
|
||||
def get_themes(self):
|
||||
d = defaultdict(list)
|
||||
for n in self.names:
|
||||
try:
|
||||
rk = os.path.basename(n).split('__')[1]
|
||||
d[rk].append(n)
|
||||
d[int(rk)].append(n)
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
return d
|
||||
|
||||
HashTable.save = save
|
||||
@@ -586,103 +600,6 @@ def get_hashtable():
|
||||
return HT
|
||||
|
||||
|
||||
|
||||
|
||||
'''
|
||||
def get_hashtable():
|
||||
LOG.debug('Getting hashtable')
|
||||
from bw_plex.audfprint.hash_table import HashTable
|
||||
|
||||
# Patch HashTable.
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
import pickle
|
||||
import gzip
|
||||
|
||||
def load(self, name=None):
|
||||
if name is None:
|
||||
self.__filename = name
|
||||
|
||||
self.load_pkl(name)
|
||||
return self
|
||||
|
||||
def save(self, name=None, params=None, file_object=None):
|
||||
LOG.debug('Saving HashTable')
|
||||
# Merge in any provided params
|
||||
if params:
|
||||
for key in params:
|
||||
self.params[key] = params[key]
|
||||
|
||||
if file_object:
|
||||
f = file_object
|
||||
self.__filename = f.name
|
||||
else:
|
||||
|
||||
if name is None:
|
||||
f = self.__filename
|
||||
else:
|
||||
self.__filename = f = name
|
||||
|
||||
f = gzip.open(f, 'wb')
|
||||
|
||||
pickle.dump(self, f, pickle.HIGHEST_PROTOCOL)
|
||||
self.dirty = False
|
||||
return self
|
||||
|
||||
def has_theme(self, media):
|
||||
"""Cheaper way to lookup stuff."""
|
||||
return bool(self.get_theme(media))
|
||||
|
||||
def get_theme(self, media, add_if_missing=True):
|
||||
if media.TYPE == 'show':
|
||||
rk = media.ratingKey
|
||||
else:
|
||||
rk = media.grandparentRatingKey
|
||||
|
||||
d = self.get_themes()
|
||||
|
||||
if not d.get(rk) and add_if_missing:
|
||||
download_theme(media, self)
|
||||
return self.get_themes().get(rk, [])
|
||||
|
||||
return d.get(rk, [])
|
||||
|
||||
def get_themes(self):
|
||||
d = defaultdict(list)
|
||||
for n in self.names:
|
||||
try:
|
||||
rk = os.path.basename(n).split('__')[1]
|
||||
d[rk].append(n)
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
return d
|
||||
|
||||
HashTable.save = save
|
||||
HashTable.load = load
|
||||
HashTable.has_theme = has_theme
|
||||
HashTable.get_themes = get_themes
|
||||
HashTable.get_theme = get_theme
|
||||
|
||||
if os.path.exists(FP_HASHES):
|
||||
HT = HashTable(FP_HASHES)
|
||||
HT.__filename = FP_HASHES
|
||||
LOG.info('Loading existing files in db')
|
||||
for n in HT.names:
|
||||
LOG.debug(n)
|
||||
|
||||
else:
|
||||
LOG.info('Creating new hashtable db')
|
||||
HT = HashTable()
|
||||
HT.__filename = FP_HASHES
|
||||
HT.save(FP_HASHES)
|
||||
HT.load(FP_HASHES)
|
||||
|
||||
return HT
|
||||
'''
|
||||
|
||||
|
||||
def download_subtitle(episode):
|
||||
import srt
|
||||
episode.reload()
|
||||
|
||||
+26
-26
@@ -84,8 +84,8 @@ def process_to_db(media, theme=None, vid=None, start=None, end=None, ffmpeg_end=
|
||||
"""
|
||||
global HT
|
||||
|
||||
# This will download the theme add add it to the hashtable
|
||||
# if its missing
|
||||
# This will download the theme and add it to
|
||||
# the hashtable if its missing
|
||||
if theme is None:
|
||||
HT.has_theme(media)
|
||||
|
||||
@@ -96,38 +96,38 @@ def process_to_db(media, theme=None, vid=None, start=None, end=None, ffmpeg_end=
|
||||
if vid is None:
|
||||
vid = convert_and_trim(check_file_access(media), fs=11025, trim=600)
|
||||
|
||||
# Lets skip the start time for now. This need to be added later to support shows
|
||||
# that have show, theme song show.
|
||||
# Find the start and the end of the theme in the video file.
|
||||
if end is None:
|
||||
start, end = get_offset_end(vid, HT)
|
||||
|
||||
# Guess when the intro ended using blackframes and audio silence.
|
||||
if ffmpeg_end is None:
|
||||
ffmpeg_end = find_offset_ffmpeg(check_file_access(media))
|
||||
|
||||
# Check for recap.
|
||||
if recap is None:
|
||||
recap = has_recap(media, CONFIG.get('words'), audio=vid)
|
||||
recap = has_recap(media, CONFIG.get('words', []), audio=vid)
|
||||
|
||||
if end is not None:
|
||||
with session_scope() as se:
|
||||
try:
|
||||
se.query(Preprocessed).filter_by(ratingKey=media.ratingKey).one()
|
||||
except NoResultFound:
|
||||
p = Preprocessed(show_name=media.grandparentTitle,
|
||||
ep_title=media.title,
|
||||
theme_end=end,
|
||||
theme_start=start,
|
||||
theme_start_str=to_time(start),
|
||||
theme_end_str=to_time(end),
|
||||
ffmpeg_end=ffmpeg_end,
|
||||
ffmpeg_end_str=to_time(ff),
|
||||
duration=media.duration,
|
||||
ratingKey=media.ratingKey,
|
||||
grandparentRatingKey=media.grandparentRatingKey,
|
||||
prettyname=media._prettyfilename(),
|
||||
updatedAt=media.updatedAt,
|
||||
has_recap=recap)
|
||||
se.add(p)
|
||||
LOG.debug('Added %s to media.db', name)
|
||||
with session_scope() as se:
|
||||
try:
|
||||
se.query(Preprocessed).filter_by(ratingKey=media.ratingKey).one()
|
||||
except NoResultFound:
|
||||
p = Preprocessed(show_name=media.grandparentTitle,
|
||||
ep_title=media.title,
|
||||
theme_end=end,
|
||||
theme_start=start,
|
||||
theme_start_str=to_time(start),
|
||||
theme_end_str=to_time(end),
|
||||
ffmpeg_end=ffmpeg_end,
|
||||
ffmpeg_end_str=to_time(ff),
|
||||
duration=media.duration,
|
||||
ratingKey=media.ratingKey,
|
||||
grandparentRatingKey=media.grandparentRatingKey,
|
||||
prettyname=media._prettyfilename(),
|
||||
updatedAt=media.updatedAt,
|
||||
has_recap=recap)
|
||||
se.add(p)
|
||||
LOG.debug('Added %s to media.db', name)
|
||||
|
||||
|
||||
@click.group(help='CLI tool that monitors pms and jumps the client to after the theme.')
|
||||
|
||||
Reference in New Issue
Block a user