Skip to content

Commit

Permalink
Add login
Browse files Browse the repository at this point in the history
Resolves #3
  • Loading branch information
jaylinski committed Feb 11, 2021
1 parent c043d28 commit 3fcef5f
Show file tree
Hide file tree
Showing 13 changed files with 105 additions and 17 deletions.
6 changes: 5 additions & 1 deletion resources/language/resource.language.de_de/strings.po
Expand Up @@ -128,9 +128,13 @@ msgid "Settings"
msgstr "Einstellungen"

msgctxt "#30109"
msgid "Sign in"
msgid "Log in"
msgstr "Anmelden"

msgctxt "#30110"
msgid "Log out"
msgstr "Abmelden"

# GUI - Search
msgctxt "#30201"
msgid "New search"
Expand Down
6 changes: 5 additions & 1 deletion resources/language/resource.language.en_gb/strings.po
Expand Up @@ -128,7 +128,11 @@ msgid "Settings"
msgstr ""

msgctxt "#30109"
msgid "Sign in"
msgid "Log in"
msgstr ""

msgctxt "#30110"
msgid "Log out"
msgstr ""

# GUI - Search
Expand Down
13 changes: 11 additions & 2 deletions resources/lib/vimeo/api.py → resources/lib/api.py
Expand Up @@ -5,15 +5,15 @@
import urllib.parse
import xbmc

from .client import VimeoClient
from .auth import GrantFailed
from .api_collection import ApiCollection
from .utils import webvtt_to_srt
from resources.lib.models.category import Category
from resources.lib.models.channel import Channel
from resources.lib.models.group import Group
from resources.lib.models.user import User
from resources.lib.models.video import Video
from resources.lib.vimeo.auth import GrantFailed
from resources.lib.vimeo.client import VimeoClient


class Api:
Expand All @@ -24,6 +24,7 @@ class Api:
api_sort = None
api_fallback = False
api_fallback_params = ["filter"]
api_oauth_scope = "public,private,interact"

# Extracted from public Vimeo Android App
# This is a special client ID which will return playable URLs
Expand Down Expand Up @@ -100,6 +101,14 @@ def search_template(self):

return "{}"

def oauth_device(self):
return self.api_client.load_device_code(self.api_oauth_scope)

def oauth_device_authorize(self, user_code, device_code):
token, user, scope = self.api_client.device_code_authorize(user_code, device_code)
self.settings.set("api.accesstoken", token)
return user["name"]

def call(self, url):
params = self._get_default_params()
res = self._do_api_request(url, params)
Expand Down
File renamed without changes.
22 changes: 16 additions & 6 deletions resources/lib/kodi/items.py
Expand Up @@ -9,9 +9,10 @@


class Items:
def __init__(self, addon, addon_base, search_history):
def __init__(self, addon, addon_base, settings, search_history):
self.addon = addon
self.addon_base = addon_base
self.settings = settings
self.search_history = search_history

def root(self):
Expand All @@ -37,16 +38,25 @@ def root(self):
url = self.addon_base + PATH_CATEGORIES
items.append((url, list_item, True))

# Log in/out
if self.settings.get("api.accesstoken"):
list_item = xbmcgui.ListItem(label="Profile") # TODO Localize
url = self.addon_base + PATH_PROFILE
items.append((url, list_item, True))

list_item = xbmcgui.ListItem(label=self.addon.getLocalizedString(30110))
url = self.addon_base + PATH_AUTH_LOGOUT
items.append((url, list_item, False))
else:
list_item = xbmcgui.ListItem(label=self.addon.getLocalizedString(30109))
url = self.addon_base + PATH_AUTH_LOGIN
items.append((url, list_item, False))

# Settings
list_item = xbmcgui.ListItem(label=self.addon.getLocalizedString(30108))
url = self.addon_base + "/?action=settings"
items.append((url, list_item, False))

# Sign in TODO
# list_item = xbmcgui.ListItem(label=addon.getLocalizedString(30109))
# url = addon_base + "/action=signin"
# items.append((url, list_item, False))

return items

def search(self):
Expand Down
File renamed without changes.
42 changes: 42 additions & 0 deletions resources/lib/vimeo/auth/device_code.py
@@ -0,0 +1,42 @@
#! /usr/bin/env python
# encoding: utf-8

from __future__ import absolute_import

from .base import AuthenticationMixinBase
from . import GrantFailed


class DeviceCodeMixin(AuthenticationMixinBase):
"""
Implement helpers for the Device Code grant for OAuth2.
Attention! This is not (yet) part of the official vimeo.py library!
"""

def load_device_code(self, scope):
"""Perform the request for device code."""
code, headers, resp = self.call_grant(
"/oauth/device", {
"grant_type": "device_grant",
"scope": scope
})

if not code == 200:
raise GrantFailed()

return resp

def device_code_authorize(self, user_code, device_code):
"""Perform the authorization step after the user entered the device code."""
code, headers, resp = self.call_grant(
"/oauth/device/authorize", {
"user_code": user_code,
"device_code": device_code
})

if not code == 200:
raise GrantFailed()

self.token = resp["access_token"]

return self.token, resp["user"], resp["scope"]
3 changes: 2 additions & 1 deletion resources/lib/vimeo/client.py
Expand Up @@ -8,10 +8,11 @@
import requests
from .auth.client_credentials import ClientCredentialsMixin
from .auth.authorization_code import AuthorizationCodeMixin
from .auth.device_code import DeviceCodeMixin
from .exceptions import APIRateLimitExceededFailure


class VimeoClient(ClientCredentialsMixin, AuthorizationCodeMixin):
class VimeoClient(ClientCredentialsMixin, AuthorizationCodeMixin, DeviceCodeMixin):
"""Client handle for the Vimeo API."""

API_ROOT = "https://api.vimeo.com"
Expand Down
23 changes: 19 additions & 4 deletions resources/plugin.py
Expand Up @@ -10,7 +10,7 @@
import xbmcgui
import xbmcplugin

from resources.lib.vimeo.api import Api, PasswordRequiredException, WrongPasswordException
from resources.lib.api import Api, PasswordRequiredException, WrongPasswordException
from resources.lib.kodi.cache import Cache
from resources.lib.kodi.items import Items
from resources.lib.kodi.search_history import SearchHistory
Expand All @@ -30,7 +30,7 @@
cache = Cache(settings, vfs_cache)
api = Api(settings, xbmc.getLanguage(xbmc.ISO_639_1), vfs, cache)
search_history = SearchHistory(settings, vfs)
listItems = Items(addon, addon_base, search_history)
listItems = Items(addon, addon_base, settings, search_history)


def run():
Expand Down Expand Up @@ -162,10 +162,25 @@ def run():
else:
xbmc.log(addon_id + ": Invalid search action", xbmc.LOGERROR)

elif path == PATH_AUTH_LOGIN:
device_code_response = api.oauth_device()
activate_link = device_code_response["activate_link"]
device_code = device_code_response["device_code"]
user_code = device_code_response["user_code"]
xbmcgui.Dialog().ok("Authorization", "Link " + activate_link + "\nCode " + user_code)

user_name = api.oauth_device_authorize(user_code, device_code)
xbmcgui.Dialog().ok("Success!", "Logged in as " + user_name)
xbmc.executebuiltin("Container.Refresh")

elif path == PATH_AUTH_LOGOUT:
settings.set("api.accesstoken", "")
vfs_cache.destroy()
xbmc.executebuiltin("Container.Refresh")

elif path == PATH_SETTINGS_CACHE_CLEAR:
vfs_cache.destroy()
dialog = xbmcgui.Dialog()
dialog.ok("Vimeo", addon.getLocalizedString(30501))
xbmcgui.Dialog().ok("Vimeo", addon.getLocalizedString(30501))

else:
xbmc.log(addon_id + ": Path not found", xbmc.LOGERROR)
Expand Down
3 changes: 3 additions & 0 deletions resources/routes.py
@@ -1,7 +1,10 @@
PATH_ROOT = "/"
PATH_AUTH_LOGIN = "/auth/login/"
PATH_AUTH_LOGOUT = "/auth/logout/"
PATH_CATEGORIES = "/categories/"
PATH_FEATURED = "/featured/"
PATH_PLAY = "/play/"
PATH_PROFILE = "/profile/"
PATH_SEARCH = "/search/"
PATH_SETTINGS_CACHE_CLEAR = "/settings/cache/clear/"
PATH_TRENDING = "/trending/"
Expand Up @@ -6,8 +6,8 @@
sys.modules["xbmc"] = xbmcMock = MagicMock()
sys.modules["xbmcaddon"] = MagicMock()
sys.modules["xbmcgui"] = MagicMock()
from resources.lib.api import Api, PasswordRequiredException
from resources.lib.kodi.settings import Settings
from resources.lib.vimeo.api import Api, PasswordRequiredException


class ApiTestCase(TestCase):
Expand Down
@@ -1,5 +1,5 @@
from unittest import TestCase
from resources.lib.vimeo.utils import webvtt_to_srt
from resources.lib.utils import webvtt_to_srt


class UtilsTestCase(TestCase):
Expand Down
Empty file.

0 comments on commit 3fcef5f

Please sign in to comment.