Skip to content

Commit 112de88

Browse files
authored
Merge pull request #219 from anxdpanic/pr_matrix
1.0.5
2 parents 2ee6ea4 + f03c097 commit 112de88

File tree

11 files changed

+188
-29
lines changed

11 files changed

+188
-29
lines changed

addon.xml

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2-
<addon id="plugin.video.tubed" name="Tubed" version="1.0.4" provider-name="anxdpanic">
2+
<addon id="plugin.video.tubed" name="Tubed" version="1.0.5" provider-name="anxdpanic">
33
<requires>
44
<import addon="xbmc.python" version="3.0.0"/>
55
<import addon="inputstream.adaptive"/>
66
<import addon="script.module.arrow" version="0.15.5+matrix.1"/>
77
<import addon="script.module.requests" version="2.22.0+matrix.1"/>
88
<import addon="script.module.pyxbmct" version="1.3.1+matrix.1"/>
9-
<import addon="script.module.tubed.api" version="1.0.2"/>
9+
<import addon="script.module.tubed.api" version="1.0.12"/>
1010
</requires>
1111
<extension point="xbmc.python.pluginsource" library="resources/lib/addon.py">
1212
<provides>video</provides>
@@ -15,7 +15,8 @@
1515
<extension point="xbmc.service" library="resources/lib/service.py"/>
1616
<extension point="xbmc.addon.metadata">
1717
<news>
18-
- added weblate translations
18+
- add tv client login for access to age gated content
19+
- updated translations from Weblate
1920
</news>
2021
<assets>
2122
<icon>resources/media/icon.png</icon>

resources/language/resource.language.en_gb/strings.po

+8
Original file line numberDiff line numberDiff line change
@@ -1059,3 +1059,11 @@ msgstr ""
10591059
msgctxt "#30257"
10601060
msgid "No entries found"
10611061
msgstr ""
1062+
1063+
msgctxt "#30258"
1064+
msgid "v3 Data API Client"
1065+
msgstr ""
1066+
1067+
msgctxt "#30259"
1068+
msgid "YouTube-TV API Client"
1069+
msgstr ""

resources/lib/src/api/api.py

+63
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,29 @@ def __init__(self, language='en-US', region='US'):
4646

4747
self._api.ACCESS_TOKEN = self.users.access_token
4848

49+
self._api.ACCESS_TOKEN_TV = self.users.tv_access_token
50+
4951
self._usher = usher
5052

5153
self.quality = self._usher.Quality
5254

5355
self.api = v3
5456
self.client = oauth.Client()
57+
self.tv_client = oauth.Client(str(CREDENTIALS.TV_ID), str(CREDENTIALS.TV_SECRET))
58+
5559
self.refresh_token()
60+
self.tv_refresh_token()
5661

5762
@property
5863
def logged_in(self):
5964
self.refresh_token()
6065
return self.users.access_token and not self.users.token_expired
6166

67+
@property
68+
def tv_logged_in(self):
69+
self.tv_refresh_token()
70+
return self.users.tv_access_token and not self.users.tv_token_expired
71+
6272
@property
6373
def language(self):
6474
return self._language.replace('-', '_')
@@ -706,6 +716,59 @@ def refresh_client(self):
706716
self.client = oauth.Client()
707717
memoizer.reset_cache()
708718

719+
@api_request
720+
def tv_refresh_token(self):
721+
if self.users.tv_access_token and self.users.tv_token_expired:
722+
access_token, expiry = self.tv_client.refresh_token(self.users.tv_refresh_token)
723+
self.users.tv_access_token = access_token
724+
self.users.tv_token_expiry = time.time() + int(expiry)
725+
self.users.save()
726+
self.tv_refresh_client()
727+
728+
@api_request
729+
def tv_revoke_token(self):
730+
if self.users.tv_refresh_token:
731+
self.tv_client.revoke_token(self.users.tv_refresh_token)
732+
self.users.tv_access_token = ''
733+
self.users.tv_refresh_token = ''
734+
self.users.tv_token_expiry = -1
735+
self.users.save()
736+
self.tv_refresh_client()
737+
738+
@api_request
739+
def tv_request_codes(self):
740+
return self.tv_client.request_codes()
741+
742+
@api_request
743+
def tv_request_access_token(self, device_code):
744+
data = self.tv_client.request_access_token(device_code)
745+
746+
if 'error' not in data:
747+
access_token = data.get('access_token', '')
748+
refresh_token = data.get('refresh_token', '')
749+
token_expiry = time.time() + int(data.get('expires_in', 3600))
750+
751+
if not access_token and not refresh_token:
752+
token_expiry = -1
753+
754+
self.users.tv_access_token = access_token
755+
self.users.tv_refresh_token = refresh_token
756+
self.users.tv_token_expiry = token_expiry
757+
self.users.save()
758+
self.tv_refresh_client()
759+
return True
760+
761+
if data['error'] == 'authorization_pending':
762+
return False
763+
764+
return data
765+
766+
def tv_refresh_client(self):
767+
self.users.load()
768+
self._api.ACCESS_TOKEN_TV = self.users.tv_access_token
769+
self.tv_client = oauth.Client(str(CREDENTIALS.TV_ID), str(CREDENTIALS.TV_SECRET))
770+
memoizer.reset_cache()
771+
709772
def calculate_next_page_token(self, page):
710773
"""
711774
Copyright (C) 2014-2016 bromix (plugin.video.youtube)

resources/lib/src/api/decorators.py

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def wrapper(*args, **kwargs):
3030
if len(args) > 0 and not func.__name__.endswith('refresh_token'):
3131
try:
3232
args[0].refresh_token()
33+
args[0].tv_refresh_token()
3334
except AttributeError:
3435
pass
3536

resources/lib/src/constants/credentials.py

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
import xbmcvfs # pylint: disable=import-error
1717

18+
from tubed_api import API_KEY_TV
19+
from tubed_api import CLIENT_ID_TV
20+
from tubed_api import CLIENT_SECRET_TV
21+
1822
_KEY = 'QUl6YVN5QUR0T0RKVTB4d3BXdWZfbUE1N3VFdUNwT0FfcjN6WEtv'
1923
_ID = 'OTAxOTQ1MDk2MjU2LWV2MGk5dmFuczd0Z25iYTRtNjZjaTQ2ZGFnc3RlY2Y1'
2024
_SECRET = 'Y2RMSldUdHdrWENod2ZsV1dqYnNwYVNH'
@@ -48,5 +52,10 @@ class CREDENTIALS(Enum):
4852
SECRET = _SECRET
4953
TOKEN = ''
5054

55+
TV_KEY = API_KEY_TV
56+
TV_ID = CLIENT_ID_TV
57+
TV_SECRET = CLIENT_SECRET_TV
58+
TV_TOKEN = ''
59+
5160
def __str__(self):
5261
return b64decode(str(self.value)).decode('utf-8')

resources/lib/src/constants/strings.py

+2
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,6 @@
191191
'Would you like to enable InputStream Adaptive now?': 30255,
192192
'Settings': 30256,
193193
'No entries found': 30257,
194+
'v3 Data API Client': 30258,
195+
'YouTube-TV API Client': 30259,
194196
}

resources/lib/src/dialogs/sign_in.py

+21-7
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ def __init__(self, context, window, **kwargs):
2929
self._context = context
3030
self.window = window
3131

32+
self.tv_client = kwargs.get('tv_client') is True
3233
self.demo = kwargs.get('mode') == 'demo'
3334

34-
self.title = bold(context.i18n('Sign In'))
35+
if not self.tv_client:
36+
client_title = context.i18n('v3 Data API Client')
37+
else:
38+
client_title = context.i18n('YouTube-TV API Client')
39+
40+
self.title = bold(' '.join([context.i18n('Sign In'), '-', client_title]))
3541

3642
super().__init__(self.title)
3743

@@ -62,7 +68,10 @@ def start(self):
6268
if self.demo:
6369
data = SIGN_IN_CODES
6470
else:
65-
data = self.context.api.request_codes()
71+
if not self.tv_client:
72+
data = self.context.api.request_codes()
73+
else:
74+
data = self.context.api.tv_request_codes()
6675

6776
self.device_code = data['device_code']
6877
self.user_code = data['user_code']
@@ -82,8 +91,8 @@ def start(self):
8291
self.connect(pyxbmct.ACTION_NAV_BACK, self.close)
8392
self.connect(ACTION_STOP, self.close)
8493

85-
self.thread = DialogThread(self.context, self.device_code,
86-
self.interval, self.close, self.demo)
94+
self.thread = DialogThread(self.context, self.device_code, self.interval,
95+
self.close, self.demo, self.tv_client)
8796

8897
self.doModal()
8998

@@ -119,7 +128,7 @@ def set_controls(self):
119128

120129
self.client_id = pyxbmct.Label(
121130
self.context.i18n('Client ID: %s') %
122-
bold(str(CREDENTIALS.ID)),
131+
bold(str(CREDENTIALS.ID)) if not self.tv_client else bold(str(CREDENTIALS.TV_ID)),
123132
font='font10',
124133
alignment=2
125134
)
@@ -130,7 +139,7 @@ def set_navigation(self):
130139

131140

132141
class DialogThread(threading.Thread):
133-
def __init__(self, context, device_code, interval, close, demo=False):
142+
def __init__(self, context, device_code, interval, close, demo=False, tv_client=False):
134143
super().__init__()
135144

136145
self._stopped = threading.Event()
@@ -141,6 +150,7 @@ def __init__(self, context, device_code, interval, close, demo=False):
141150
self.interval = interval
142151

143152
self.demo = demo
153+
self.tv_client = tv_client
144154

145155
self.monitor = xbmc.Monitor()
146156

@@ -170,7 +180,11 @@ def run(self):
170180
for _ in range(steps):
171181
# self.update_progress(int(float((100.0 // steps)) * index))
172182

173-
signed_in = self.context.api.request_access_token(self.device_code)
183+
if self.tv_client:
184+
signed_in = self.context.api.tv_request_access_token(self.device_code)
185+
else:
186+
signed_in = self.context.api.request_access_token(self.device_code)
187+
174188
if signed_in:
175189
self.signed_in = True
176190
self.stop()

resources/lib/src/routes/main_menu.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ def invoke(context): # pylint: disable=too-many-branches,too-many-statements
3737
users = None
3838

3939
logged_in = context.api.logged_in
40+
tv_logged_in = context.api.tv_logged_in
41+
4042
fanart = context.addon.getAddonInfo('fanart')
4143

4244
has_channel_mine = False
4345
if logged_in:
4446
has_channel_mine = context.api.channel_by_username('mine') != {}
4547

46-
if not logged_in:
48+
if not logged_in or not tv_logged_in:
4749
if show_main_menu_item('sign.in'):
4850
label = context.i18n('Sign in with Google')
4951
action = Action(

resources/lib/src/routes/sign_in.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,17 @@
1515

1616

1717
def invoke(context):
18-
signed_in = open_dialog(context, SignInDialog)
18+
logged_in = context.api.logged_in
19+
tv_logged_in = context.api.tv_logged_in
1920

20-
if signed_in:
21+
signed_in = False
22+
tv_signed_in = False
23+
24+
if not logged_in:
25+
signed_in = open_dialog(context, SignInDialog)
26+
27+
if not tv_logged_in:
28+
tv_signed_in = open_dialog(context, SignInDialog, tv_client=True)
29+
30+
if signed_in or tv_signed_in:
2131
xbmc.executebuiltin('Container.Refresh')

resources/lib/src/routes/sign_out.py

+1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ def invoke(context):
1717
context.i18n('You are about to sign out, are you sure?')):
1818

1919
context.api.revoke_token()
20+
context.api.tv_revoke_token()
2021

2122
xbmc.executebuiltin('Container.Refresh')

0 commit comments

Comments
 (0)