mirror of
https://github.com/moparisthebest/SickRage
synced 2025-01-07 03:48:02 -05:00
Merge pull request #833 from KontiSR/dev_imdb_checker
First changes for imdb watchlist checker
This commit is contained in:
commit
9eb9400c74
@ -27,6 +27,7 @@
|
||||
|
||||
<script type="text/javascript" src="$sbRoot/js/config.js?$sbPID"></script>
|
||||
<script type="text/javascript" src="$sbRoot/js/rootDirs.js?$sbPID"></script>
|
||||
<script type="text/javascript" src="$sbRoot/js/imdbWatchlist.js?$sbPID"></script>
|
||||
|
||||
<div id="config">
|
||||
<div id="config-content">
|
||||
@ -176,7 +177,26 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<input type="submit" class="btn config_submitter" value="Save Changes" />
|
||||
<fieldset class="component-group-list">
|
||||
<div class="field-pair">
|
||||
<input type="checkbox" name="use_imdbwl" class="enabler" id="use_imdbwl" #if $sickbeard.USE_IMDBWATCHLIST then "checked=\"checked\"" else ""#/>
|
||||
<label class="clearfix" for="use_imdbwl">
|
||||
<span class="component-title">Use IMDB Watchlists</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="content_use_imdbwl">
|
||||
<!-- Multiselect for managing IMDB watchlist csv url's -->
|
||||
<div class="field-pair">
|
||||
<label class="clearfix">
|
||||
<span class="">Manage your IMDB watchlist url's. Each url should contain your list id and user id. They look like: ls014134 and us0918234.</span>
|
||||
#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_imdbWatchlists.tmpl")
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<input type="submit" class="btn config_submitter" value="Save Changes" />
|
||||
</fieldset>
|
||||
|
||||
</fieldset>
|
||||
</div><!-- /component-group1 //-->
|
||||
|
||||
|
33
gui/slick/interfaces/default/inc_imdbWatchlists.tmpl
Normal file
33
gui/slick/interfaces/default/inc_imdbWatchlists.tmpl
Normal file
@ -0,0 +1,33 @@
|
||||
#import sickbeard
|
||||
<span id="sampleImdbWl"></span>
|
||||
|
||||
#if $sickbeard.IMDB_WATCHLISTCSV:
|
||||
#set $backend_pieces = $sickbeard.IMDB_WATCHLISTCSV.split('|')
|
||||
#else:
|
||||
#set $backend_pieces = []
|
||||
#end if
|
||||
|
||||
|
||||
<div style="padding: 10px 0 5px;">
|
||||
<select name="imdbWatchlistCsv" id="imdbWl" size="6" style="min-width: 500px;">
|
||||
#for $imdbwl in $backend_pieces:
|
||||
#if $imdbwl != "":
|
||||
<option value="$imdbwl">$imdbwl</option>
|
||||
#end if
|
||||
#end for
|
||||
</select>
|
||||
</div>
|
||||
<div id="imdbWlControls" style="text-align: center; width: 500px;">
|
||||
<input class="btn" type="button" id="addImdbWl" value="New" />
|
||||
<input class="btn" type="button" id="editImdbWl" value="Edit" />
|
||||
<input class="btn" type="button" id="deleteImdbWl" value="Delete" />
|
||||
|
||||
</div>
|
||||
<input type="hidden" style="display: none" id="ImdbWlText" />
|
||||
<input type="text" style="display: none" id="editImdbWlText" />
|
||||
<div id="imdbWlUpdateControls" style="text-align: center; width: 500px;">
|
||||
<input class="btn" style="display: none" type="button" id="updateImdbWl" value="Update" />
|
||||
</div>
|
||||
|
||||
|
||||
<br />
|
170
gui/slick/js/imdbWatchlist.js
Normal file
170
gui/slick/js/imdbWatchlist.js
Normal file
@ -0,0 +1,170 @@
|
||||
// Avoid `console` errors in browsers that lack a console.
|
||||
(function() {
|
||||
var method;
|
||||
var noop = function noop() {};
|
||||
var methods = [
|
||||
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
|
||||
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
|
||||
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
|
||||
'timeStamp', 'trace', 'warn'
|
||||
];
|
||||
var length = methods.length;
|
||||
var console = (window.console = window.console || {});
|
||||
|
||||
while (length--) {
|
||||
method = methods[length];
|
||||
|
||||
// Only stub undefined methods.
|
||||
if (!console[method]) {
|
||||
console[method] = noop;
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
function addImdbWl(path) {
|
||||
|
||||
if (!path.length)
|
||||
return;
|
||||
|
||||
$('#imdbWl').append('<option value="'+path+'">'+path+'</option>');
|
||||
refreshImdbUrls();
|
||||
$.get(sbRoot+'/config/general/saveImdbWatchlists', { imdbWatchlistString: $('#ImdbWlText').val() });
|
||||
}
|
||||
|
||||
function editImdbWl(path) {
|
||||
|
||||
if (!path.length)
|
||||
return;
|
||||
|
||||
// as long as something is selected
|
||||
if ($("#imdbWl option:selected").length) {
|
||||
|
||||
$("#imdbWl option:selected").text(path);
|
||||
$("#imdbWl option:selected").val(path);
|
||||
}
|
||||
|
||||
refreshImdbUrls();
|
||||
$.get(sbRoot+'/config/general/saveRootDirs', {rootDirString: $('#ImdbWlText').val()});
|
||||
}
|
||||
|
||||
$('#addImdbWl').click(function(){editText()});
|
||||
$('#editImdbWl').click(function(){editText({selectedWl: $("#imdbWl option:selected").val()})});
|
||||
|
||||
$('#deleteImdbWl').click(function() {
|
||||
if ($("#imdbWl option:selected").length) {
|
||||
|
||||
var toDelete = $("#imdbWl option:selected");
|
||||
|
||||
toDelete.remove();
|
||||
syncOptionIDs();
|
||||
|
||||
};
|
||||
|
||||
refreshImdbUrls();
|
||||
$.get(sbRoot+'/config/general/saveImdbWatchlists', {imdbWatchlistString: $('#ImdbWlText').val()});
|
||||
});
|
||||
|
||||
function syncOptionIDs() {
|
||||
// re-sync option ids
|
||||
var i = 0;
|
||||
$('#imdbWl option').each(function() {
|
||||
$(this).attr('id', 'wl-'+(i++));
|
||||
});
|
||||
}
|
||||
|
||||
function refreshImdbUrls() {
|
||||
// Rebuild the string in #ImdbWlText as url|url|url
|
||||
|
||||
if (!$("#imdbWl").length)
|
||||
return;
|
||||
|
||||
var do_disable = 'true';
|
||||
|
||||
// if something's selected then we have some behavior to figure out
|
||||
if ($("#imdbWl option:selected").length) {
|
||||
do_disable = '';
|
||||
}
|
||||
|
||||
// update the elements
|
||||
$('#deleteImdbWl').prop('disabled', do_disable);
|
||||
$('#editImdbWl').prop('disabled', do_disable);
|
||||
|
||||
var log_str = '';
|
||||
var dir_text = '';
|
||||
|
||||
$('#imdbWl option').each(function() {
|
||||
log_str += $(this).val();
|
||||
//Check if this is a valid IMDB link before adding it
|
||||
|
||||
if (checkIMDBUrl(log_str)) {
|
||||
if (dir_text == '') {
|
||||
dir_text = $(this).val()
|
||||
}
|
||||
else {
|
||||
dir_text += '|' + $(this).val();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//console.log(log_str);
|
||||
|
||||
$('#ImdbWlText').val(dir_text);
|
||||
$('#ImdbWlText').change();
|
||||
//console.log('ImdbWlText: '+$('#ImdbWlText').val());
|
||||
}
|
||||
|
||||
function checkIMDBUrl(url) {
|
||||
if (url.match(/http.*:\/\/www\.imdb\.com\/.*/gi) &&
|
||||
url.match(/ls[0-9]+/gi) &&
|
||||
url.match(/ur[0-9]+/gi)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
alert(url + ' is not a valid IMDB csv export!');
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
$('#imdbWl').click(refreshImdbUrls);
|
||||
|
||||
// set up buttons on page load
|
||||
refreshImdbUrls();
|
||||
|
||||
function editText(optionid) {
|
||||
var updateVal = "";
|
||||
if (optionid) {
|
||||
updateVal = 'update-' + optionid.selectedWl;
|
||||
$('#editImdbWlText').val(optionid.selectedWl);
|
||||
}
|
||||
else {
|
||||
updateVal = 'add';
|
||||
$('#editImdbWlText').val("");
|
||||
}
|
||||
$('#updateImdbWl').attr('action', updateVal);
|
||||
$('#editImdbWlText').attr('style','display: block; width: 100%; margin-top: 4px; margin-bottom: 4px;');
|
||||
$('#imdbWl').prop('disabled', 'true');
|
||||
$('#updateImdbWl').attr('style','display: block;');
|
||||
$('#editImdbWlText').select();
|
||||
}
|
||||
|
||||
$('#updateImdbWl').click(function(){
|
||||
// Update the Multiselect after clicking on the Update button
|
||||
var updateText = $('#editImdbWlText').val();
|
||||
if (checkIMDBUrl(updateText)) {
|
||||
if ($('#updateImdbWl').attr('action') == 'add') {
|
||||
addImdbWl(updateText);
|
||||
}
|
||||
else {
|
||||
editImdbWl(updateText);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
$('#editImdbWlText').attr('style','display: none; width: 100%');
|
||||
$('#imdbWl').prop('disabled', '');
|
||||
$('#updateImdbWl').attr('style','display: none;');
|
||||
});
|
||||
|
||||
});
|
@ -8,18 +8,27 @@
|
||||
"""Unittests for tvdb_api
|
||||
"""
|
||||
|
||||
import os
|
||||
import os,os.path
|
||||
import sys
|
||||
print sys.path
|
||||
import datetime
|
||||
import unittest
|
||||
|
||||
# Force parent directory onto path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
#sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import tvdb_api
|
||||
sys.path.append(os.path.abspath('../../tests'))
|
||||
|
||||
|
||||
import sickbeard
|
||||
|
||||
|
||||
from tvdb_api import Tvdb
|
||||
import tvdb_ui
|
||||
from tvdb_api import (tvdb_shownotfound, tvdb_seasonnotfound,
|
||||
tvdb_episodenotfound, tvdb_attributenotfound)
|
||||
from lib import xmltodict
|
||||
import lib
|
||||
|
||||
class test_tvdb_basic(unittest.TestCase):
|
||||
# Used to store the cached instance of Tvdb()
|
||||
|
@ -522,10 +522,14 @@ class Tvdb:
|
||||
|
||||
if self.config['search_all_languages']:
|
||||
self.config['url_getSeries'] = u"%(base_url)s/api/GetSeries.php" % self.config
|
||||
self.config['url_getSeriesImdb'] = u"%(base_url)s/api/GetSeriesByRemoteID.php" % self.config
|
||||
self.config['params_getSeries'] = {"seriesname": "", "language": "all"}
|
||||
self.config['params_getSeriesByImdb'] = {"imdbid": "", "language": "all"}
|
||||
else:
|
||||
self.config['url_getSeries'] = u"%(base_url)s/api/GetSeries.php" % self.config
|
||||
self.config['url_getSeriesImdb'] = u"%(base_url)s/api/GetSeriesByRemoteID.php" % self.config
|
||||
self.config['params_getSeries'] = {"seriesname": "", "language": self.config['language']}
|
||||
self.config['params_getSeriesByImdb'] = {"imdbid": "", "language": self.config['language']}
|
||||
|
||||
self.config['url_epInfo'] = u"%(base_url)s/api/%(apikey)s/series/%%s/all/%%s.xml" % self.config
|
||||
self.config['url_epInfo_zip'] = u"%(base_url)s/api/%(apikey)s/series/%%s/all/%%s.zip" % self.config
|
||||
@ -674,16 +678,20 @@ class Tvdb:
|
||||
data = data.strip()
|
||||
return data
|
||||
|
||||
def search(self, series):
|
||||
def search(self, series, imdbid=None):
|
||||
"""This searches TheTVDB.com for the series name
|
||||
and returns the result list
|
||||
"""
|
||||
series = series.encode("utf-8")
|
||||
log().debug("Searching for show %s" % series)
|
||||
self.config['params_getSeries']['seriesname'] = series
|
||||
self.config['params_getSeriesByImdb']['imdbid'] = imdbid
|
||||
|
||||
try:
|
||||
seriesFound = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']).values()[0]
|
||||
if imdbid:
|
||||
seriesFound = self._getetsrc(self.config['url_getSeriesImdb'], self.config['params_getSeriesByImdb']).values()[0]
|
||||
else:
|
||||
seriesFound = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']).values()[0]
|
||||
return seriesFound
|
||||
except:
|
||||
return []
|
||||
|
@ -39,6 +39,7 @@ from sickbeard.config import CheckSection, check_setting_int, check_setting_str,
|
||||
naming_ep_type
|
||||
from sickbeard import searchBacklog, showUpdater, versionChecker, properFinder, autoPostProcesser, \
|
||||
subtitles, traktChecker
|
||||
from sickbeard.automations import imdbChecker
|
||||
from sickbeard import helpers, db, exceptions, show_queue, search_queue, scheduler, show_name_helpers
|
||||
from sickbeard import logger
|
||||
from sickbeard import naming
|
||||
@ -465,6 +466,7 @@ def initialize(consoleLogging=True):
|
||||
USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD, XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, \
|
||||
XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, BACKLOG_FREQUENCY, \
|
||||
USE_TRAKT, TRAKT_USERNAME, TRAKT_PASSWORD, TRAKT_API, TRAKT_REMOVE_WATCHLIST, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_USE_RECOMMENDED, TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, \
|
||||
USE_IMDBWATCHLIST, IMDB_WATCHLISTCSV, imdbWatchlistScheduler, \
|
||||
USE_PLEX, PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, PLEX_UPDATE_LIBRARY, \
|
||||
PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, DEFAULT_BACKLOG_FREQUENCY, MIN_BACKLOG_FREQUENCY, BACKLOG_STARTUP, SKIP_REMOVED_FILES, \
|
||||
showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, UPDATE_SHOWS_ON_START, SORT_ARTICLE, showList, loadingShowList, \
|
||||
@ -523,6 +525,7 @@ def initialize(consoleLogging=True):
|
||||
CheckSection(CFG, 'Pushalot')
|
||||
CheckSection(CFG, 'Pushbullet')
|
||||
CheckSection(CFG, 'Subtitles')
|
||||
CheckSection(CFG, 'IMDBWatchlist')
|
||||
|
||||
# wanted branch
|
||||
BRANCH = check_setting_str(CFG, 'General', 'branch', '')
|
||||
@ -572,7 +575,7 @@ def initialize(consoleLogging=True):
|
||||
|
||||
if WEB_PORT < 21 or WEB_PORT > 65535:
|
||||
WEB_PORT = 8081
|
||||
|
||||
|
||||
WEB_HOST = check_setting_str(CFG, 'General', 'web_host', '0.0.0.0')
|
||||
WEB_IPV6 = bool(check_setting_int(CFG, 'General', 'web_ipv6', 0))
|
||||
WEB_ROOT = check_setting_str(CFG, 'General', 'web_root', '').rstrip("/")
|
||||
@ -834,7 +837,11 @@ def initialize(consoleLogging=True):
|
||||
TRAKT_USE_RECOMMENDED = bool(check_setting_int(CFG, 'Trakt', 'trakt_use_recommended', 0))
|
||||
TRAKT_SYNC = bool(check_setting_int(CFG, 'Trakt', 'trakt_sync', 0))
|
||||
TRAKT_DEFAULT_INDEXER = check_setting_int(CFG, 'Trakt', 'trakt_default_indexer', 1)
|
||||
|
||||
|
||||
### IMDB Watchlist set default values for config
|
||||
USE_IMDBWATCHLIST = bool(check_setting_int(CFG, 'IMDBWatchlist', 'use_imdbwatchlist', 0))
|
||||
IMDB_WATCHLISTCSV = check_setting_str(CFG, 'IMDBWatchlist', 'imdb_watchlistcsv', '')
|
||||
|
||||
CheckSection(CFG, 'pyTivo')
|
||||
USE_PYTIVO = bool(check_setting_int(CFG, 'pyTivo', 'use_pytivo', 0))
|
||||
PYTIVO_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'pyTivo', 'pytivo_notify_onsnatch', 0))
|
||||
@ -1147,6 +1154,11 @@ def initialize(consoleLogging=True):
|
||||
cycleTime=datetime.timedelta(hours=SUBTITLES_FINDER_FREQUENCY),
|
||||
threadName="FINDSUBTITLES",
|
||||
silent=not USE_SUBTITLES)
|
||||
|
||||
imdbWatchlistScheduler = scheduler.Scheduler(imdbChecker.IMDB(),
|
||||
cycleTime=datetime.timedelta(hours=1),
|
||||
threadName="IMDBWATCHLIST",
|
||||
silent=not USE_IMDBWATCHLIST)
|
||||
|
||||
showList = []
|
||||
loadingShowList = {}
|
||||
@ -1159,7 +1171,7 @@ def start():
|
||||
global __INITIALIZED__, backlogSearchScheduler, \
|
||||
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
|
||||
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
|
||||
subtitlesFinderScheduler, USE_SUBTITLES, traktCheckerScheduler, \
|
||||
subtitlesFinderScheduler, USE_SUBTITLES, traktCheckerScheduler, imdbWatchlistScheduler, \
|
||||
dailySearchScheduler, events, started
|
||||
|
||||
with INIT_LOCK:
|
||||
@ -1200,7 +1212,10 @@ def start():
|
||||
# start the trakt checker
|
||||
if USE_TRAKT:
|
||||
traktCheckerScheduler.start()
|
||||
|
||||
|
||||
if USE_IMDBWATCHLIST:
|
||||
imdbWatchlistScheduler.start()
|
||||
|
||||
started = True
|
||||
|
||||
|
||||
@ -1208,7 +1223,7 @@ def halt():
|
||||
global __INITIALIZED__, backlogSearchScheduler, \
|
||||
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
|
||||
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
|
||||
subtitlesFinderScheduler, traktCheckerScheduler, \
|
||||
subtitlesFinderScheduler, traktCheckerScheduler, imdbWatchlistScheduler, \
|
||||
dailySearchScheduler, events, started
|
||||
|
||||
with INIT_LOCK:
|
||||
@ -1281,6 +1296,14 @@ def halt():
|
||||
traktCheckerScheduler.join(10)
|
||||
except:
|
||||
pass
|
||||
|
||||
if USE_IMDBWATCHLIST:
|
||||
imdbWatchlistScheduler.stop.set()
|
||||
logger.log(u"Waiting for the IMDBWATCHLIST thread to exit")
|
||||
try:
|
||||
imdbWatchlistScheduler.join(10)
|
||||
except:
|
||||
pass
|
||||
|
||||
if DOWNLOAD_PROPERS:
|
||||
properFinderScheduler.stop.set()
|
||||
@ -1680,7 +1703,11 @@ def save_config():
|
||||
new_config['Trakt']['trakt_use_recommended'] = int(TRAKT_USE_RECOMMENDED)
|
||||
new_config['Trakt']['trakt_sync'] = int(TRAKT_SYNC)
|
||||
new_config['Trakt']['trakt_default_indexer'] = int(TRAKT_DEFAULT_INDEXER)
|
||||
|
||||
|
||||
new_config['IMDBWatchlist'] = {}
|
||||
new_config['IMDBWatchlist']['use_imdbwatchlist'] = int(USE_IMDBWATCHLIST)
|
||||
new_config['IMDBWatchlist']['imdb_watchlistcsv'] = IMDB_WATCHLISTCSV
|
||||
|
||||
new_config['pyTivo'] = {}
|
||||
new_config['pyTivo']['use_pytivo'] = int(USE_PYTIVO)
|
||||
new_config['pyTivo']['pytivo_notify_onsnatch'] = int(PYTIVO_NOTIFY_ONSNATCH)
|
||||
|
0
sickbeard/automations/__init__.py
Normal file
0
sickbeard/automations/__init__.py
Normal file
230
sickbeard/automations/imdbChecker.py
Normal file
230
sickbeard/automations/imdbChecker.py
Normal file
@ -0,0 +1,230 @@
|
||||
# Author: KontiSR
|
||||
# URL: https://github.com/echel0n/SickRage
|
||||
#
|
||||
# This file is part of SickRage.
|
||||
#
|
||||
# SickRage is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# SickRage 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
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import urllib2, urllib
|
||||
import shutil
|
||||
import urlparse
|
||||
import os, datetime
|
||||
import requests
|
||||
import cookielib
|
||||
import re
|
||||
from urllib2 import HTTPError, URLError
|
||||
|
||||
import sickbeard
|
||||
from sickbeard import encodingKludge as ek
|
||||
from sickbeard import logger
|
||||
from sickbeard import helpers
|
||||
from sickbeard import search_queue
|
||||
from sickbeard.common import SKIPPED, WANTED
|
||||
from lib.tvdb_api.tvdb_api import *
|
||||
|
||||
class ImdbBase():
|
||||
def _download(self, baseurl, querystring=""):
|
||||
fullurl = baseurl + urllib.urlencode(querystring)
|
||||
|
||||
req = urllib2.Request(fullurl)
|
||||
try:
|
||||
response = urllib2.urlopen(req)
|
||||
except HTTPError as e:
|
||||
logger.log('Could not download IMDB watchlist', logger.DEBUG)
|
||||
#print 'Error code: ', e.code
|
||||
return False
|
||||
except URLError as e:
|
||||
logger.log('Could not download IMDB watchlist', logger.DEBUG)
|
||||
#print 'Reason: ', e.reason
|
||||
return False
|
||||
|
||||
redirurl = response.geturl()
|
||||
htmlResponse = response.read()
|
||||
|
||||
validHtml = True#BeautifulSoup(htmlResponse, 'html.parser')
|
||||
if validHtml:
|
||||
return htmlResponse
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class IMDB(ImdbBase):
|
||||
listOfImdbIds = []
|
||||
def __init__(self):
|
||||
self.listOfImdbIds = []
|
||||
|
||||
def run(self, force=False):
|
||||
try:
|
||||
# add shows from trakt.tv watchlist
|
||||
if sickbeard.USE_IMDBWATCHLIST:
|
||||
self.listOfImdbIds = [] # its about to all get re-added
|
||||
self.checkWatchlist() # Check the | separated watchlists (csv) urls
|
||||
if len(self.listOfImdbIds):
|
||||
self.updateShowsInDb() # Update the db with possible new shows
|
||||
|
||||
except Exception:
|
||||
logger.log(traceback.format_exc(), logger.DEBUG)
|
||||
|
||||
def _getTTs(self, html):
|
||||
nrAddedTTs = 0
|
||||
### Get the tt's (shows) from the ajax html. E.a. [ tt1958961|imdb|8.1|8.1|list, tt1958961|imdb|8.1|8.1|list ]
|
||||
if not html:
|
||||
return False
|
||||
|
||||
parsedshows = re.findall("(tt[0-9]+)\\|imdb\\|([.0-9]+)", html)
|
||||
if not parsedshows:
|
||||
return False
|
||||
|
||||
for show in parsedshows:
|
||||
if show[0] not in [x['imdbid'] for x in self.listOfImdbIds]:
|
||||
self.listOfImdbIds.append({"imdbid" : show[0], "score" : show[1]})
|
||||
nrAddedTTs += 1
|
||||
|
||||
if nrAddedTTs > 0:
|
||||
return nrAddedTTs
|
||||
|
||||
return False
|
||||
|
||||
def checkWatchlist(self):
|
||||
|
||||
### Get imdbListId from the csv url's
|
||||
AjaxUrls = self._getImdbAjaxUrls(sickbeard.IMDB_WATCHLISTCSV)
|
||||
|
||||
### Get imdbUserId from the csv url's
|
||||
for url in AjaxUrls:
|
||||
getImdbHtml = self._download(url)
|
||||
nrAdded = self._getTTs(getImdbHtml)
|
||||
|
||||
if self.listOfImdbIds:
|
||||
return self.listOfImdbIds
|
||||
|
||||
return False
|
||||
|
||||
'''
|
||||
Tries to use the csvUrls as a comma separated list of imdb csv urls,
|
||||
to retrieve a userid and listid for each of the csv url.
|
||||
For each csv url an Ajax url is created. Thats used to get the list of Tvshows.
|
||||
'''
|
||||
def _getImdbAjaxUrls(self, csvUrls):
|
||||
ajaxUrls = []
|
||||
ajaxUrlBase = u"http://www.imdb.com/list/_ajax/list_filter?"
|
||||
|
||||
reUserId = re.compile(".*(ur[0-9]+)")
|
||||
reListId = re.compile(".*(ls[0-9]+)")
|
||||
|
||||
#if "|" in csvUrls:
|
||||
#print "Multiple Watchlists detected"
|
||||
csvurl = csvUrls.split("|")
|
||||
for url in csvurl:
|
||||
userIdMatch = reUserId.match(url)
|
||||
listIdMatch = reListId.match(url)
|
||||
|
||||
if userIdMatch and listIdMatch:
|
||||
query = {"list_id" : listIdMatch.groups()[0],
|
||||
"list_class" : "WATCHLIST",
|
||||
"view" : "compact",
|
||||
"list_type" : "Titles",
|
||||
"filter" : '{"title_type":["tv_series"]}',
|
||||
"sort_field" : "created",
|
||||
"sort_direction" : "desc",
|
||||
"user_id" : userIdMatch.groups()[0] }
|
||||
ajaxUrls.append(ajaxUrlBase + urllib.urlencode(query))
|
||||
if ajaxUrls:
|
||||
return ajaxUrls
|
||||
|
||||
return False
|
||||
|
||||
def updateShowsInDb(self):
|
||||
nrOfaddedShows = 0
|
||||
# Get list with thetvdb and imdbIds from DB (tt1234324)
|
||||
|
||||
|
||||
# Get thetvdb indexer_id, showname from tvdb using the IMDB id. ttxxxxx
|
||||
# Use "[{listOfImdbIds}]" for updating the db, if the show isn't in it
|
||||
tvdb_instance = Tvdb(cache = True, useZip = True)
|
||||
for watchlistShow in self.listOfImdbIds:
|
||||
if watchlistShow['imdbid'] not in [x.imdbid for x in sickbeard.showList ]:
|
||||
TvdbShow = tvdb_instance.search('',imdbid=watchlistShow['imdbid'])
|
||||
if TvdbShow:
|
||||
self._addDefaultShow(1, TvdbShow['id'], TvdbShow['seriesname'], False)
|
||||
nrOfaddedShows += 1
|
||||
|
||||
return nrOfaddedShows if nrOfaddedShows > 0 else False
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _addDefaultShow(self, indexer, indexer_id, name, status):
|
||||
"""
|
||||
Adds a new show with the default settings
|
||||
"""
|
||||
if not helpers.findCertainShow(sickbeard.showList, int(indexer_id)):
|
||||
logger.log(u"Adding show " + str(indexer_id))
|
||||
root_dirs = sickbeard.ROOT_DIRS.split('|')
|
||||
|
||||
try:
|
||||
location = root_dirs[int(root_dirs[0]) + 1]
|
||||
except:
|
||||
location = None
|
||||
|
||||
if location:
|
||||
showPath = ek.ek(os.path.join, location, helpers.sanitizeFileName(name))
|
||||
dir_exists = helpers.makeDir(showPath)
|
||||
if not dir_exists:
|
||||
logger.log(u"Unable to create the folder " + showPath + ", can't add the show", logger.ERROR)
|
||||
return
|
||||
else:
|
||||
helpers.chmodAsParent(showPath)
|
||||
|
||||
sickbeard.showQueueScheduler.action.addShow(int(indexer), int(indexer_id), showPath, status,
|
||||
int(sickbeard.QUALITY_DEFAULT),
|
||||
int(sickbeard.FLATTEN_FOLDERS_DEFAULT),
|
||||
paused=False, anime = False)
|
||||
else:
|
||||
logger.log(u"There was an error creating the show, no root directory setting found", logger.ERROR)
|
||||
return
|
||||
|
||||
# imdbWatchlistTv = "http://www.imdb.com/user/%s/watchlist?ref_=wl_ref_typ&sort=list_order,asc&mode=simple&page=%s&title_type=tvSeries"
|
||||
# imdbWatchlistTv2 = "http://www.imdb.com/list/export?list_id=ls009966268&author_id=ur35235230&ref_=wl_exp"
|
||||
# imdbUserId = "ur5968686"
|
||||
# imdbListId = "ls005547625"
|
||||
# imdbWlPage = "1"
|
||||
# ajaxUrlBase = u"http://www.imdb.com/list/_ajax/list_filter?"
|
||||
# ajaxUrlQueryString = u"list_id=%s&list_class=WATCHLIST&view=compact&list_type=Titles&filter={\"title_type\":[\"tv_series\"]}&sort_field=created&sort_direction=desc&user_id=%s" % (imdbListId, imdbUserId)
|
||||
#
|
||||
# query = {"list_id" : imdbListId,
|
||||
# "list_class" : "WATCHLIST",
|
||||
# "view" : "compact",
|
||||
# "list_type" : "Titles",
|
||||
# "filter" : '{"title_type":["tv_series"]}',
|
||||
# "sort_field" : "created",
|
||||
# "sort_direction" : "desc",
|
||||
# "user_id" : imdbUserId }
|
||||
#
|
||||
# imdbwatchlistcsv = "http://www.imdb.com/list/export?list_id=ls005547625&author_id=ur5968686&ref_=wl_exp"
|
||||
# imdbWatchListTvFullURL = ajaxUrlBase + urllib.urlencode(query)
|
||||
# # /download("%s%s" % (baseurl, searchurl), "test.csv")
|
||||
#
|
||||
# IMDBobj = IMDB()
|
||||
#
|
||||
# #Test one csv
|
||||
# imdbIds = IMDBobj.checkWatchlist(imdbwatchlistcsv)
|
||||
# print IMDBobj.listOfImdbIds
|
||||
#
|
||||
# # Test two csv's
|
||||
# imdbIds = IMDBobj.checkWatchlist(imdbwatchlistcsv + "|" + imdbWatchlistTv2)
|
||||
# print IMDBobj.listOfImdbIds
|
||||
#
|
||||
# print imdbIds
|
||||
|
@ -1425,7 +1425,9 @@ class ConfigGeneral(MainHandler):
|
||||
|
||||
def saveRootDirs(self, rootDirString=None):
|
||||
sickbeard.ROOT_DIRS = rootDirString
|
||||
|
||||
|
||||
def saveImdbWatchlists(self, imdbWatchlistString=None):
|
||||
sickbeard.IMDB_WATCHLISTCSV = imdbWatchlistString
|
||||
|
||||
def saveAddShowDefaults(self, defaultStatus, anyQualities, bestQualities, defaultFlattenFolders, subtitles=False,
|
||||
anime=False, scene=False):
|
||||
@ -1485,7 +1487,7 @@ class ConfigGeneral(MainHandler):
|
||||
handle_reverse_proxy=None, sort_article=None, auto_update=None, notify_on_update=None,
|
||||
proxy_setting=None, anon_redirect=None, git_path=None, calendar_unprotected=None,
|
||||
fuzzy_dating=None, trim_zero=None, date_preset=None, date_preset_na=None, time_preset=None,
|
||||
indexer_timeout=None, play_videos=None, rootDir=None):
|
||||
indexer_timeout=None, play_videos=None, rootDir=None, use_imdbwl=None, imdbWatchlistCsv=None):
|
||||
|
||||
results = []
|
||||
|
||||
@ -1495,6 +1497,7 @@ class ConfigGeneral(MainHandler):
|
||||
config.change_VERSION_NOTIFY(config.checkbox_to_value(version_notify))
|
||||
sickbeard.AUTO_UPDATE = config.checkbox_to_value(auto_update)
|
||||
sickbeard.NOTIFY_ON_UPDATE = config.checkbox_to_value(notify_on_update)
|
||||
sickbeard.USE_IMDBWATCHLIST = config.checkbox_to_value(use_imdbwl)
|
||||
# sickbeard.LOG_DIR is set in config.change_LOG_DIR()
|
||||
|
||||
sickbeard.UPDATE_SHOWS_ON_START = config.checkbox_to_value(update_shows_on_start)
|
||||
|
@ -206,7 +206,8 @@ def setUp_test_episode_file():
|
||||
|
||||
|
||||
def tearDown_test_episode_file():
|
||||
shutil.rmtree(FILEDIR)
|
||||
if os.path.exists(FILEDIR):
|
||||
shutil.rmtree(FILEDIR)
|
||||
|
||||
|
||||
def setUp_test_show_dir():
|
||||
@ -215,7 +216,8 @@ def setUp_test_show_dir():
|
||||
|
||||
|
||||
def tearDown_test_show_dir():
|
||||
shutil.rmtree(SHOWDIR)
|
||||
if os.path.exists(SHOWDIR):
|
||||
shutil.rmtree(SHOWDIR)
|
||||
|
||||
tearDown_test_db()
|
||||
|
||||
|
152
tests/test_tvdb_api.py
Normal file
152
tests/test_tvdb_api.py
Normal file
@ -0,0 +1,152 @@
|
||||
"""Unittests for tvdb_api
|
||||
"""
|
||||
import unittest
|
||||
import test_lib as test
|
||||
|
||||
import sys, os.path
|
||||
sys.path.append(os.path.abspath('..'))
|
||||
sys.path.append(os.path.abspath('../lib'))
|
||||
|
||||
print sys.path
|
||||
|
||||
from sickbeard import show_name_helpers, scene_exceptions, common, name_cache
|
||||
|
||||
import sickbeard
|
||||
from sickbeard import db
|
||||
from sickbeard.databases import cache_db
|
||||
from sickbeard.tv import TVShow as Show
|
||||
|
||||
from lib.tvdb_api.tvdb_api import *
|
||||
#import tvdb_api as tvdb_api
|
||||
import tvdb_api
|
||||
|
||||
|
||||
|
||||
# class test_tvdb_basic(test.SickbeardTestDBCase):
|
||||
# # Used to store the cached instance of Tvdb()
|
||||
# t = None
|
||||
#
|
||||
# def setUp(self):
|
||||
# if self.t is None:
|
||||
# self.__class__.t = Tvdb(cache = True, banners = False)
|
||||
#
|
||||
# def test_different_case(self):
|
||||
# """Checks the auto-correction of show names is working.
|
||||
# It should correct the weirdly capitalised 'sCruBs' to 'Scrubs'
|
||||
# """
|
||||
# self.assertEquals(self.t['scrubs'][1][4]['episodename'], 'My Old Lady')
|
||||
# self.assertEquals(self.t['sCruBs']['seriesname'], 'Scrubs')
|
||||
#
|
||||
# def test_spaces(self):
|
||||
# """Checks shownames with spaces
|
||||
# """
|
||||
# self.assertEquals(self.t['My Name Is Earl']['seriesname'], 'My Name Is Earl')
|
||||
# self.assertEquals(self.t['My Name Is Earl'][1][4]['episodename'], 'Faked His Own Death')
|
||||
#
|
||||
# def test_numeric(self):
|
||||
# """Checks numeric show names
|
||||
# """
|
||||
# self.assertEquals(self.t['24'][2][20]['episodename'], 'Day 2: 3:00 A.M.-4:00 A.M.')
|
||||
# self.assertEquals(self.t['24']['seriesname'], '24')
|
||||
#
|
||||
# def test_show_iter(self):
|
||||
# """Iterating over a show returns each seasons
|
||||
# """
|
||||
# self.assertEquals(
|
||||
# len(
|
||||
# [season for season in self.t['Life on Mars']]
|
||||
# ),
|
||||
# 2
|
||||
# )
|
||||
#
|
||||
# def test_season_iter(self):
|
||||
# """Iterating over a show returns episodes
|
||||
# """
|
||||
# self.assertEquals(
|
||||
# len(
|
||||
# [episode for episode in self.t['Life on Mars'][1]]
|
||||
# ),
|
||||
# 8
|
||||
# )
|
||||
#
|
||||
# def test_get_episode_overview(self):
|
||||
# """Checks episode overview is retrieved correctly.
|
||||
# """
|
||||
# self.assertEquals(
|
||||
# self.t['Battlestar Galactica (2003)'][1][6]['overview'].startswith(
|
||||
# 'When a new copy of Doral, a Cylon who had been previously'),
|
||||
# True
|
||||
# )
|
||||
#
|
||||
# def test_get_parent(self):
|
||||
# """Check accessing series from episode instance
|
||||
# """
|
||||
# show = self.t['Battlestar Galactica (2003)']
|
||||
# season = show[1]
|
||||
# episode = show[1][1]
|
||||
#
|
||||
# self.assertEquals(
|
||||
# season.show,
|
||||
# show
|
||||
# )
|
||||
#
|
||||
# self.assertEquals(
|
||||
# episode.season,
|
||||
# season
|
||||
# )
|
||||
#
|
||||
# self.assertEquals(
|
||||
# episode.season.show,
|
||||
# show
|
||||
# )
|
||||
#
|
||||
# def test_no_season(self):
|
||||
# show = self.t['Katekyo Hitman Reborn']
|
||||
# print tvdb_api
|
||||
# print show[1][1]
|
||||
|
||||
|
||||
class searchTvdbImdbid(test.SickbeardTestDBCase):
|
||||
# Used to store the cached instance of Tvdb()
|
||||
t = None
|
||||
|
||||
def setUp(self):
|
||||
if self.t is None:
|
||||
self.__class__.t = Tvdb(cache = True, useZip = True)
|
||||
|
||||
def test_search(self):
|
||||
"""Test Tvdb.search method
|
||||
"""
|
||||
results = self.t.search("",imdbid='tt0903747')
|
||||
all_ids = results['seriesid']
|
||||
self.assertTrue('81189' in all_ids)
|
||||
|
||||
|
||||
class test_tvdb_show_search(test.SickbeardTestDBCase):
|
||||
# Used to store the cached instance of Tvdb()
|
||||
t = None
|
||||
|
||||
def setUp(self):
|
||||
if self.t is None:
|
||||
self.__class__.t = Tvdb(cache = True, useZip = True)
|
||||
|
||||
def test_search(self):
|
||||
"""Test Tvdb.search method
|
||||
"""
|
||||
results = self.t.search("my name is earl")
|
||||
all_ids = results['seriesid']
|
||||
self.assertTrue('75397' in all_ids)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "=================="
|
||||
print "STARTING - PostProcessor TESTS"
|
||||
print "=================="
|
||||
print "######################################################################"
|
||||
print "###Test Search Tvdb for show breaking bad, using the imdb id"
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(searchTvdbImdbid)
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
print "######################################################################"
|
||||
print "###Test Search Tvdb for show my name is earl, using the show name"
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(test_tvdb_show_search)
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
Loading…
Reference in New Issue
Block a user