Skip to content

Commit c6f8a3f

Browse files
authored
Merge pull request #40 from anxdpanic/dev
add kodi logging
2 parents 42bcd31 + a9f0088 commit c6f8a3f

File tree

9 files changed

+114
-30
lines changed

9 files changed

+114
-30
lines changed

addon.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
[add] helix api
1414
[add] add usher.live_request and usher.video_request
1515
[add] MobileClient().revoke_token and MobileClient().get_app_access_token queries
16+
[add] Kodi logging
1617
</news>
1718
<assets>
1819
<icon>icon.png</icon>

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
[add] helix api
99
[add] add usher.live_request and usher.video_request
1010
[add] MobileClient().revoke_token and MobileClient().get_app_access_token queries
11+
[add] Kodi logging
1112

1213
1.1.0
1314
*** Twitch API V5 is deprecated and will be removed entirely on 2/14/18

resources/lib/twitch/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# -*- encoding: utf-8 -*-
22

3-
import xbmcaddon
4-
5-
VERSION = xbmcaddon.Addon('script.module.python.twitch').getAddonInfo('version')
3+
VERSION = '2.0.0'
64
CLIENT_ID = ''
75
CLIENT_SECRET = ''
86
OAUTH_TOKEN = ''

resources/lib/twitch/api/usher.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
# -*- encoding: utf-8 -*-
2-
3-
from twitch.logging import log # NOQA
4-
5-
log.warning('By using this module you are violating the Twitch TOS') # NOQA
2+
# By using this module you are violating the Twitch TOS
63

74
from twitch import keys
85
from twitch.api.parameters import Boolean
96
from twitch.parser import m3u8, clip_embed
107
from twitch.queries import ClipsQuery, HiddenApiQuery, UsherQuery
118
from twitch.queries import query
9+
from twitch.logging import log
1210

1311
from six.moves.urllib.parse import urlencode
1412

@@ -57,7 +55,9 @@ def live_request(channel):
5755
q.add_param(keys.ALLOW_SPECTRE, Boolean.TRUE)
5856
q.add_param(keys.ALLOW_AUDIO_ONLY, Boolean.TRUE)
5957
url = '?'.join([q.url, urlencode(q.params)])
60-
return {'url': url, 'headers': q.headers}
58+
request_dict = {'url': url, 'headers': q.headers}
59+
log.debug('live_request: |{0}|'.format(str(request_dict)))
60+
return request_dict
6161

6262

6363
@query
@@ -95,7 +95,9 @@ def video_request(video_id):
9595
q.add_param(keys.ALLOW_SOURCE, Boolean.TRUE)
9696
q.add_param(keys.ALLOW_AUDIO_ONLY, Boolean.TRUE)
9797
url = '?'.join([q.url, urlencode(q.params)])
98-
return {'url': url, 'headers': q.headers}
98+
request_dict = {'url': url, 'headers': q.headers}
99+
log.debug('video_request: |{0}|'.format(str(request_dict)))
100+
return request_dict
99101
else:
100102
raise NotImplementedError('Unknown Video Type')
101103

resources/lib/twitch/api/v5/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# -*- encoding: utf-8 -*-
22
# https://dev.twitch.tv/docs/
33
# V5 is deprecated and will be removed entirely on 2/14/18
4+
from twitch.logging import log
5+
6+
log.deprecated_api_version('V5', 'Helix', '2/14/18')
47

58
from twitch.api.v5 import bits # NOQA
69
from twitch.api.v5 import channel_feed # NOQA

resources/lib/twitch/api/v5/channels.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from twitch.api.parameters import Boolean, BroadcastType, Cursor, Direction, Duration, Language, VideoSort
66
from twitch.queries import V5Query as Qry
77
from twitch.queries import query
8+
from twitch.logging import log
89

910

1011
# required scope: channel_read
@@ -126,6 +127,7 @@ def reset_stream_key(channel_id):
126127
# deprecated
127128
@query
128129
def get_community(channel_id):
130+
log.deprecated_query('channels.get_community', 'channels.get_communities')
129131
q = Qry('channels/{channel_id}/community')
130132
q.add_urlkw(keys.CHANNEL_ID, channel_id)
131133
return q
@@ -143,6 +145,7 @@ def get_communities(channel_id):
143145
# deprecated
144146
@query
145147
def set_community(channel_id, community_id):
148+
log.deprecated_query('channels.set_community', 'channels.set_communities')
146149
q = Qry('channels/{channel_id}/community/{community_id}', method=methods.PUT)
147150
q.add_urlkw(keys.CHANNEL_ID, channel_id)
148151
q.add_urlkw(keys.COMMUNITY_ID, community_id)

resources/lib/twitch/logging.py

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import
3-
3+
import re
44
import logging
5+
import copy
56

67
try:
78
from logging import NullHandler
@@ -10,11 +11,83 @@ class NullHandler(logging.Handler):
1011
def emit(self, record):
1112
pass
1213

13-
log = logging.getLogger('twitch')
14-
log.addHandler(NullHandler())
14+
try:
15+
import xbmc
16+
except ImportError:
17+
xbmc = None
18+
19+
20+
def _mask(message):
21+
mask = '*' * 11
22+
masked_message = re.sub(r'((?:OAuth|Bearer)\s)[^\'"]+', r'\1' + mask, message)
23+
masked_message = re.sub(r'(["\']email["\']:\s*[\'"])[^\'"]+', r'\1' + mask, masked_message)
24+
masked_message = re.sub(r'(USER-IP=[\'"])[^\'"]+', r'\1' + mask, masked_message)
25+
masked_message = re.sub(r'(["\']client_secret["\']:\s*[\'"])[^\'"]+', r'\1' + mask, masked_message)
26+
masked_message = re.sub(r'(client_secret=).+?(&|$|\|)', r'\1' + mask + r'\2', masked_message)
27+
return masked_message
28+
29+
30+
def _add_leader(message):
31+
if xbmc:
32+
message = 'script.module.python.twitch: %s' % message
33+
return message
34+
35+
36+
def prep_log_message(message):
37+
message = copy.deepcopy(message)
38+
message = _mask(message)
39+
message = _add_leader(message)
40+
return message
41+
42+
43+
class Log:
44+
def __init__(self):
45+
if xbmc:
46+
self._log = xbmc.log
47+
else:
48+
self._log = logging.getLogger('twitch')
49+
self._log.addHandler(NullHandler())
50+
51+
def info(self, message):
52+
message = prep_log_message(message)
53+
if xbmc:
54+
self._log(message, xbmc.LOGNOTICE)
55+
else:
56+
self._log.info(message)
57+
58+
def debug(self, message):
59+
message = prep_log_message(message)
60+
if xbmc:
61+
self._log(message, xbmc.LOGDEBUG)
62+
else:
63+
self._log.debug(message)
64+
65+
def warning(self, message):
66+
message = prep_log_message(message)
67+
if xbmc:
68+
self._log(message, xbmc.LOGWARNING)
69+
else:
70+
self._log.debug(message)
71+
72+
def error(self, message):
73+
message = prep_log_message(message)
74+
if xbmc:
75+
self._log(message, xbmc.LOGERROR)
76+
else:
77+
self._log.error(message)
78+
79+
def critical(self, message):
80+
message = prep_log_message(message)
81+
if xbmc:
82+
self._log(message, xbmc.LOGFATAL)
83+
else:
84+
self._log.critical(message)
85+
86+
def deprecated_query(self, old, new):
87+
self.warning('DEPRECATED call to |{0}| detected, please use |{1}| instead'.format(old, new))
88+
89+
def deprecated_api_version(self, old, new, eol_date):
90+
self.warning('API version |{0}| is deprecated, update to |{1}| by |{2}|'.format(old, new, eol_date))
1591

1692

17-
def deprecation_warning(logger, old, new):
18-
logger.warning("DEPRECATED call to '%s\' detected, "
19-
"please use '%s' instead",
20-
old, new)
93+
log = Log()

resources/lib/twitch/queries.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from twitch import CLIENT_ID, OAUTH_TOKEN, APP_TOKEN
66
from twitch.exceptions import ResourceUnavailableException
7-
from twitch.logging import log
7+
from twitch.logging import log, prep_log_message
88
from twitch.scraper import download, get_json, get_json_and_headers
99
from twitch import methods
1010

@@ -91,7 +91,7 @@ def execute(self, f):
9191
try:
9292
return f(self.url, self.params, self.headers, self.data, self.method)
9393
except:
94-
raise ResourceUnavailableException(str(self))
94+
raise ResourceUnavailableException(prep_log_message(str(self)))
9595

9696

9797
class DownloadQuery(_Query):
@@ -193,18 +193,17 @@ def __init__(self, path, use_app_token=False, method=methods.GET):
193193
def assert_new(d, k):
194194
if k in d:
195195
v = d.get(k)
196-
raise ValueError("Key '{0}' already set to '{1}'".format(k, v))
196+
raise ValueError('Key |{0}| already set to |{1}|'.format(k, v))
197197

198198

199199
# TODO maybe rename
200200
def query(f):
201201
def wrapper(*args, **kwargs):
202202
qry = f(*args, **kwargs)
203203
if not isinstance(qry, _Query):
204-
raise ValueError('{0} did not return a Query, was: {1}'.format(f.__name__, repr(qry)))
205-
log.debug('%s QUERY: url: %s, params: %s, data: %s, '
206-
'headers: %r, target_func: %r',
207-
qry.method, qry.url, qry.params, qry.data, qry.headers, f.__name__)
204+
raise ValueError('|{0}| did not return a Query, was: |{1}|'.format(f.__name__, repr(qry)))
205+
log.debug('{0} QUERY: url: |{1}|, params: |{2}|, data: |{3}|, headers: |{4}|, target_func: |{5}|'
206+
.format(qry.method, qry.url, qry.params, qry.data, qry.headers, f.__name__))
208207
return qry.execute()
209208

210209
return wrapper

resources/lib/twitch/scraper.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def get_json(baseurl, parameters={}, headers={}, data={}, method=methods.GET):
3535
method = methods.validate(method)
3636
jsonString = download(baseurl, parameters, headers, data, method)
3737
jsonDict = json.loads(jsonString)
38-
log.debug(json.dumps(jsonDict, indent=4, sort_keys=True))
38+
log.debug('url: |{0}| parameters: |{1}|\n{2}'.format(baseurl, parameters, json.dumps(jsonDict, indent=4, sort_keys=True)))
3939
return jsonDict
4040

4141

@@ -51,7 +51,7 @@ def get_json_and_headers(baseurl, parameters={}, headers={}, data={}, method=met
5151
method = methods.validate(method)
5252
content = download(baseurl, parameters, headers, data, method, response_headers=True)
5353
content['response'] = json.loads(content['response'])
54-
log.debug(json.dumps(content['response'], indent=4, sort_keys=True))
54+
log.debug('url: |{0}| parameters: |{1}|\n{2}'.format(baseurl, parameters, json.dumps(content['response'], indent=4, sort_keys=True)))
5555
return content
5656

5757

@@ -67,29 +67,33 @@ def download(baseurl, parameters={}, headers={}, data={}, method=methods.GET, re
6767
@returns String of data from URL or {'response': {}, 'headers': {}} if response_headers is True
6868
'''
6969
method = methods.validate(method)
70-
if isinstance(parameters, dict):
70+
71+
if not parameters:
72+
url = baseurl
73+
elif isinstance(parameters, dict):
7174
url = '?'.join([baseurl, urlencode(parameters)])
7275
else:
7376
_parameters = ''
7477
for param in parameters:
7578
_parameters += '{0}={1}&'.format(param[0], quote_plus(str(param[1])))
7679
_parameters = _parameters.rstrip('&')
7780
url = '?'.join([baseurl, _parameters])
78-
log.debug('Downloading: ' + url)
81+
82+
log.debug('Downloading: |{0}|'.format(url))
7983
content = ""
8084
for _ in range(MAX_RETRIES):
8185
try:
8286
headers.update({USER_AGENT: USER_AGENT_STRING})
8387
response = requests.request(method=method, url=url, headers=headers, data=data, verify=SSL_VERIFICATION)
8488
content = response.content
8589
if not content:
86-
content = '{"status": %d}' % response.status_code
90+
content = '{{"status": {0}}}'.format(response.status_code)
8791
break
8892
except Exception as err:
8993
if not isinstance(err, URLError):
90-
log.debug("Error %s during HTTP Request, abort", repr(err))
94+
log.debug('Error |{0}| during HTTP Request, abort'.format(repr(err)))
9195
raise # propagate non-URLError
92-
log.debug("Error %s during HTTP Request, retrying", repr(err))
96+
log.debug('Error |{0}| during HTTP Request, retrying'.format(repr(err)))
9397
else:
9498
raise
9599

0 commit comments

Comments
 (0)