Browse Source

Update TZlocal 2.0.0b3 (410a838) → 2.1b1 (dd79171).

Change Emby notifier to add unofficial support for Jellyfin.
Change Filelist torrent provider.
tags/release_0.21.27^2
JackDandy 5 years ago
parent
commit
8a616c666e
  1. 9
      CHANGES.md
  2. 1
      HACKS.txt
  3. 2
      lib/tzlocal/unix.py
  4. 12
      lib/tzlocal/utils.py
  5. 12
      lib/tzlocal/windows_tz.py
  6. 4
      sickbeard/notifiers/emby.py
  7. 221
      sickbeard/providers/filelist.py

9
CHANGES.md

@ -1,4 +1,11 @@
### 0.21.26 (2020-04-13 00:30:00 UTC) ### 0.21.27 (2020-04-22 02:50:00 UTC)
* Update TZlocal 2.0.0b3 (410a838) to 2.1b1 (dd79171)
* Change Emby notifier to add unofficial support for Jellyfin
* Change Filelist torrent provider
### 0.21.26 (2020-04-13 00:30:00 UTC)
* Fix AttributeError in anime manager while editing show (part deux) * Fix AttributeError in anime manager while editing show (part deux)
* Fix use lib logger instead of global logger * Fix use lib logger instead of global logger

1
HACKS.txt

@ -25,4 +25,3 @@ Libs with customisations...
/lib/tmdbsimple /lib/tmdbsimple
/lib/tornado /lib/tornado
/lib/tvdb_api/tvdb_api.py /lib/tvdb_api/tvdb_api.py
/lib/tzlocal/unix.py

2
lib/tzlocal/unix.py

@ -138,7 +138,7 @@ def _get_localzone(_root='/'):
if os.path.exists(tzpath) and os.path.islink(tzpath): if os.path.exists(tzpath) and os.path.islink(tzpath):
tzpath = os.path.realpath(tzpath) tzpath = os.path.realpath(tzpath)
start = tzpath.find("/")+1 start = tzpath.find("/")+1
while start is not 0: while start != 0:
tzpath = tzpath[start:] tzpath = tzpath[start:]
try: try:
return pytz.timezone(tzpath) return pytz.timezone(tzpath)

12
lib/tzlocal/utils.py

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time
import datetime import datetime
import calendar
def get_system_offset(): def get_system_offset():
@ -11,8 +13,14 @@ def get_system_offset():
To keep compatibility with Windows, we're always importing time module here. To keep compatibility with Windows, we're always importing time module here.
""" """
import time
if time.daylight and time.localtime().tm_isdst > 0: localtime = calendar.timegm(time.localtime())
gmtime = calendar.timegm(time.gmtime())
offset = gmtime - localtime
# We could get the localtime and gmtime on either side of a second switch
# so we check that the difference is less than one minute, because nobody
# has that small DST differences.
if abs(offset - time.altzone) < 60:
return -time.altzone return -time.altzone
else: else:
return -time.timezone return -time.timezone

12
lib/tzlocal/windows_tz.py

@ -87,6 +87,7 @@ win_tz = {'AUS Central Standard Time': 'Australia/Darwin',
'Pacific Standard Time (Mexico)': 'America/Tijuana', 'Pacific Standard Time (Mexico)': 'America/Tijuana',
'Pakistan Standard Time': 'Asia/Karachi', 'Pakistan Standard Time': 'Asia/Karachi',
'Paraguay Standard Time': 'America/Asuncion', 'Paraguay Standard Time': 'America/Asuncion',
'Qyzylorda Standard Time': 'Asia/Qyzylorda',
'Romance Standard Time': 'Europe/Paris', 'Romance Standard Time': 'Europe/Paris',
'Russia Time Zone 10': 'Asia/Srednekolymsk', 'Russia Time Zone 10': 'Asia/Srednekolymsk',
'Russia Time Zone 11': 'Asia/Kamchatka', 'Russia Time Zone 11': 'Asia/Kamchatka',
@ -127,6 +128,7 @@ win_tz = {'AUS Central Standard Time': 'Australia/Darwin',
'Ulaanbaatar Standard Time': 'Asia/Ulaanbaatar', 'Ulaanbaatar Standard Time': 'Asia/Ulaanbaatar',
'Venezuela Standard Time': 'America/Caracas', 'Venezuela Standard Time': 'America/Caracas',
'Vladivostok Standard Time': 'Asia/Vladivostok', 'Vladivostok Standard Time': 'Asia/Vladivostok',
'Volgograd Standard Time': 'Europe/Volgograd',
'W. Australia Standard Time': 'Australia/Perth', 'W. Australia Standard Time': 'Australia/Perth',
'W. Central Africa Standard Time': 'Africa/Lagos', 'W. Central Africa Standard Time': 'Africa/Lagos',
'W. Europe Standard Time': 'Europe/Berlin', 'W. Europe Standard Time': 'Europe/Berlin',
@ -287,7 +289,7 @@ tz_win = {'Africa/Abidjan': 'Greenwich Standard Time',
'America/Mendoza': 'Argentina Standard Time', 'America/Mendoza': 'Argentina Standard Time',
'America/Menominee': 'Central Standard Time', 'America/Menominee': 'Central Standard Time',
'America/Merida': 'Central Standard Time (Mexico)', 'America/Merida': 'Central Standard Time (Mexico)',
'America/Metlakatla': 'Pacific Standard Time', 'America/Metlakatla': 'Alaskan Standard Time',
'America/Mexico_City': 'Central Standard Time (Mexico)', 'America/Mexico_City': 'Central Standard Time (Mexico)',
'America/Miquelon': 'Saint Pierre Standard Time', 'America/Miquelon': 'Saint Pierre Standard Time',
'America/Moncton': 'Atlantic Standard Time', 'America/Moncton': 'Atlantic Standard Time',
@ -347,13 +349,13 @@ tz_win = {'Africa/Abidjan': 'Greenwich Standard Time',
'America/Winnipeg': 'Central Standard Time', 'America/Winnipeg': 'Central Standard Time',
'America/Yakutat': 'Alaskan Standard Time', 'America/Yakutat': 'Alaskan Standard Time',
'America/Yellowknife': 'Mountain Standard Time', 'America/Yellowknife': 'Mountain Standard Time',
'Antarctica/Casey': 'W. Australia Standard Time', 'Antarctica/Casey': 'Singapore Standard Time',
'Antarctica/Davis': 'SE Asia Standard Time', 'Antarctica/Davis': 'SE Asia Standard Time',
'Antarctica/DumontDUrville': 'West Pacific Standard Time', 'Antarctica/DumontDUrville': 'West Pacific Standard Time',
'Antarctica/Macquarie': 'Central Pacific Standard Time', 'Antarctica/Macquarie': 'Central Pacific Standard Time',
'Antarctica/Mawson': 'West Asia Standard Time', 'Antarctica/Mawson': 'West Asia Standard Time',
'Antarctica/McMurdo': 'New Zealand Standard Time', 'Antarctica/McMurdo': 'New Zealand Standard Time',
'Antarctica/Palmer': 'Magallanes Standard Time', 'Antarctica/Palmer': 'SA Eastern Standard Time',
'Antarctica/Rothera': 'SA Eastern Standard Time', 'Antarctica/Rothera': 'SA Eastern Standard Time',
'Antarctica/South_Pole': 'New Zealand Standard Time', 'Antarctica/South_Pole': 'New Zealand Standard Time',
'Antarctica/Syowa': 'E. Africa Standard Time', 'Antarctica/Syowa': 'E. Africa Standard Time',
@ -424,7 +426,7 @@ tz_win = {'Africa/Abidjan': 'Greenwich Standard Time',
'Asia/Pyongyang': 'North Korea Standard Time', 'Asia/Pyongyang': 'North Korea Standard Time',
'Asia/Qatar': 'Arab Standard Time', 'Asia/Qatar': 'Arab Standard Time',
'Asia/Qostanay': 'Central Asia Standard Time', 'Asia/Qostanay': 'Central Asia Standard Time',
'Asia/Qyzylorda': 'West Asia Standard Time', 'Asia/Qyzylorda': 'Qyzylorda Standard Time',
'Asia/Rangoon': 'Myanmar Standard Time', 'Asia/Rangoon': 'Myanmar Standard Time',
'Asia/Riyadh': 'Arab Standard Time', 'Asia/Riyadh': 'Arab Standard Time',
'Asia/Saigon': 'SE Asia Standard Time', 'Asia/Saigon': 'SE Asia Standard Time',
@ -592,7 +594,7 @@ tz_win = {'Africa/Abidjan': 'Greenwich Standard Time',
'Europe/Vatican': 'W. Europe Standard Time', 'Europe/Vatican': 'W. Europe Standard Time',
'Europe/Vienna': 'W. Europe Standard Time', 'Europe/Vienna': 'W. Europe Standard Time',
'Europe/Vilnius': 'FLE Standard Time', 'Europe/Vilnius': 'FLE Standard Time',
'Europe/Volgograd': 'Russian Standard Time', 'Europe/Volgograd': 'Volgograd Standard Time',
'Europe/Warsaw': 'Central European Standard Time', 'Europe/Warsaw': 'Central European Standard Time',
'Europe/Zagreb': 'Central European Standard Time', 'Europe/Zagreb': 'Central European Standard Time',
'Europe/Zaporozhye': 'FLE Standard Time', 'Europe/Zaporozhye': 'FLE Standard Time',

4
sickbeard/notifiers/emby.py

@ -53,7 +53,7 @@ class EmbyNotifier(Notifier):
timeout=20, hooks=dict(response=self._cb_response), json=True) timeout=20, hooks=dict(response=self._cb_response), json=True)
return self.response and self.response.get('ok') and 200 == self.response.get('status_code') and \ return self.response and self.response.get('ok') and 200 == self.response.get('status_code') and \
version <= map_list(lambda x: int(x), response.get('Version', '0.0.0.0').split('.')) version <= map_list(lambda x: int(x), (response and response.get('Version') or '0.0.0.0').split('.'))
def update_library(self, show_obj=None, **kwargs): def update_library(self, show_obj=None, **kwargs):
""" Update library function """ Update library function
@ -140,7 +140,7 @@ class EmbyNotifier(Notifier):
cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
cs.settimeout(10) cs.settimeout(10)
result, sock_issue = '', None result, sock_issue = '', None
for server in ('EmbyServer', 'MediaBrowserServer'): for server in ('EmbyServer', 'MediaBrowserServer', 'JellyfinServer'):
bufr = 'who is %s?' % server bufr = 'who is %s?' % server
try: try:
assert len(bufr) == cs.sendto(bufr, ('255.255.255.255', mb_listen_port)), \ assert len(bufr) == cs.sendto(bufr, ('255.255.255.255', mb_listen_port)), \

221
sickbeard/providers/filelist.py

@ -1,111 +1,110 @@
# coding=utf-8 # coding=utf-8
# #
# This file is part of SickGear. # This file is part of SickGear.
# #
# SickGear is free software: you can redistribute it and/or modify # SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# SickGear is distributed in the hope that it will be useful, # SickGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>. # along with SickGear. If not, see <http://www.gnu.org/licenses/>.
import re import re
import traceback import traceback
from . import generic from . import generic
from .. import logger from .. import logger
from ..helpers import try_int from ..helpers import try_int
from bs4_parser import BS4Parser from bs4_parser import BS4Parser
from _23 import unidecode from _23 import unidecode
from six import iteritems from six import iteritems
class FLProvider(generic.TorrentProvider): class FLProvider(generic.TorrentProvider):
def __init__(self): def __init__(self):
generic.TorrentProvider.__init__(self, 'FileList') generic.TorrentProvider.__init__(self, 'FileList')
self.url_base = 'https://filelist.ro/' self.url_base = 'https://filelist.io/'
self.urls = {'config_provider_home_uri': self.url_base, self.urls = {'config_provider_home_uri': self.url_base,
'login_action': self.url_base + 'login.php', 'login_action': self.url_base + 'login.php',
'search': self.url_base + 'browse.php?search=%s&%s&incldead=0'} 'search': self.url_base + 'browse.php?search=%s&%s&incldead=0'}
self.categories = {'Season': [14], 'Episode': [13, 21, 23], 'anime': [24]} self.categories = dict(shows=[13, 21, 23, 27], anime=[24])
self.categories['Cache'] = self.categories['Season'] + self.categories['Episode']
self.url = self.urls['config_provider_home_uri']
self.url = self.urls['config_provider_home_uri']
self.username, self.password, self.minseed, self.minleech = 4 * [None]
self.username, self.password, self.minseed, self.minleech = 4 * [None]
def _authorised(self, **kwargs):
def _authorised(self, **kwargs):
return super(FLProvider, self)._authorised()
return super(FLProvider, self)._authorised()
def _search_provider(self, search_params, **kwargs):
def _search_provider(self, search_params, **kwargs):
results = []
results = [] if not self._authorised():
if not self._authorised(): return results
return results
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
rc = dict([(k, re.compile('(?i)' + v)) for (k, v) in iteritems({'info': 'details', 'get': 'download'})])
rc = dict([(k, re.compile('(?i)' + v)) for (k, v) in iteritems({'info': 'details', 'get': 'download'})]) for mode in search_params:
for mode in search_params: rc['cats'] = re.compile('(?i)cat=(?:%s)' % self._categories_string(mode, template='', delimiter='|'))
rc['cats'] = re.compile('(?i)cat=(?:%s)' % self._categories_string(mode, template='', delimiter='|')) for search_string in search_params[mode]:
for search_string in search_params[mode]: search_string = unidecode(search_string)
search_string = unidecode(search_string)
html = self.get_url(self.urls['search'] % ('+'.join(search_string.split()),
html = self.get_url(self.urls['search'] % ('+'.join(search_string.split()), self._categories_string(mode, template='cats[]=%s')))
self._categories_string(mode, template='cats[]=%s'))) if self.should_skip():
if self.should_skip(): return results
return results
cnt = len(items[mode])
cnt = len(items[mode]) try:
try: if not html or self._has_no_results(html):
if not html or self._has_no_results(html): raise generic.HaltParseException
raise generic.HaltParseException
with BS4Parser(html) as soup:
with BS4Parser(html) as soup: tbl_rows = soup.find_all('div', 'torrentrow')
tbl_rows = soup.find_all('div', 'torrentrow')
if not len(tbl_rows):
if not len(tbl_rows): raise generic.HaltParseException
raise generic.HaltParseException
for tr in tbl_rows:
for tr in tbl_rows: cells = tr.select('span[style*="cell"]')
cells = tr.select('span[style*="cell"]') if 6 > len(cells):
if 6 > len(cells): continue
continue try:
try: seeders, leechers, size = [try_int(n, n) for n in [
seeders, leechers, size = [try_int(n, n) for n in [ cells[x].get_text().strip() for x in (-3, -2, -5)]]
cells[x].get_text().strip() for x in (-3, -2, -5)]] if not tr.find('a', href=rc['cats']) or self._reject_item(seeders, leechers):
if not tr.find('a', href=rc['cats']) or self._reject_item(seeders, leechers): continue
continue
title = tr.find('a', href=rc['info']).get_text().strip()
title = tr.find('a', href=rc['info']).get_text().strip() download_url = self._link(tr.find('a', href=rc['get'])['href'])
download_url = self._link(tr.find('a', href=rc['get'])['href']) except (AttributeError, TypeError, ValueError, IndexError):
except (AttributeError, TypeError, ValueError, IndexError): continue
continue
if title and download_url:
if title and download_url: items[mode].append((title, download_url, seeders, self._bytesizer(size)))
items[mode].append((title, download_url, seeders, self._bytesizer(size)))
except generic.HaltParseException:
except generic.HaltParseException: pass
pass except (BaseException, Exception):
except (BaseException, Exception): logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR)
logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR)
self._log_search(mode, len(items[mode]) - cnt, self.session.response.get('url'))
self._log_search(mode, len(items[mode]) - cnt, self.session.response.get('url'))
results = self._sort_seeding(mode, results + items[mode])
results = self._sort_seeding(mode, results + items[mode])
return results
return results
provider = FLProvider()
provider = FLProvider()

Loading…
Cancel
Save