Skip to content

Instantly share code, notes, and snippets.

@davidbe
Created June 29, 2024 13:53
Show Gist options
  • Save davidbe/4a09ebc002d4d61cc33f993d5b55f87a to your computer and use it in GitHub Desktop.
Save davidbe/4a09ebc002d4d61cc33f993d5b55f87a to your computer and use it in GitHub Desktop.
Analysis for VtmGo addon for Kodi - 20240629

Analysis for VtmGo addon for Kodi - 20240629

Last week, two issues were raised:

Things have probably changed on VtmGo-side.

This python code worked a few days before issues were raised. It is minimal code:

  • to register a new device
  • getting all available movies

It is based on what happens in de kodi-addon.

This script uses https://github.com/add-ons/plugin.video.vtm.go/blob/master/resources/lib/vtmgo/util.py and thus needs to be in the same directory to try the test-script. (The refresh-request is not directly needed, but it was a test whether it works and is the right code.)

import util
import json
import uuid

API_ENDPOINT = 'https://lfvp-api.dpgmedia.net'
API_ANDROID_ENDPOINT = 'https://lfvp-android-api.dpgmedia.net'

STOREFRONT_MAIN = 'main'
STOREFRONT_MOVIES = 'movies'
STOREFRONT_SHORTIES = 'shorties'
STOREFRONT_KIDS = 'kids'

response = util.http_post('https://login2.vtm.be/device/authorize',
                          form={'client_id': 'vtm-go-androidtv', })
auth_info = json.loads(response.text)
device_code = auth_info.get('device_code')
print("fill in: ")
print(auth_info.get('user_code'))
print("on url: ")
print(auth_info.get('verification_uri'))

input("and press enter...")

response2 = util.http_post('https://login2.vtm.be/token',
                           form={'device_code': device_code,
                                 'client_id': 'vtm-go-androidtv',
                                 'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
                                 })
auth_info2 = json.loads(response2.text)
id_token = auth_info2.get('access_token')
refresh_token = auth_info2.get('refresh_token')


response3 = util.http_post('https://lfvp-api.dpgmedia.net/VTM_GO/tokens',
                           data={'device': {'id': str(uuid.uuid4()),
                                            'name': 'VTM Go Addon on Kodi',
                                            },
                                 'idToken': id_token,
                                 })
access_token = json.loads(response3.text).get('lfvpToken')


response4 = util.http_post('https://lfvp-api.dpgmedia.net/VTM_GO/tokens/refresh',
                           data={'lfvpToken': access_token,
                                 })
access_token = json.loads(response4.text).get('lfvpToken')


class Profile:
    """ Defines a profile under your account. """

    def __init__(self, key=None, product=None, name=None, gender=None, birthdate=None, color=None, color2=None):
        """
        :type key: str
        :type product: str
        :type name: str
        :type gender: str
        :type birthdate: str
        :type color: str
        :type color2: str
        """
        self.key = key
        self.product = product
        self.name = name
        self.gender = gender
        self.birthdate = birthdate
        self.color = color
        self.color2 = color2

    def __repr__(self):
        return "%r" % self.__dict__
response5 = util.http_get(API_ENDPOINT + '/VTM_GO/profiles',
                          token=access_token)
result = json.loads(response5.text)
print(result)
profiles = [
    Profile(
        key=profile.get('id'),
        product=profile.get('product'),
        name=profile.get('name'),
        gender=profile.get('gender'),
        birthdate=profile.get('birthDate'),
        color=profile.get('color', {}).get('start'),
        color2=profile.get('color', {}).get('end'),
    )
    for profile in result.get('profiles')
]
profile = profiles[0].key
product = profiles[0].product


response6 = util.http_get(API_ENDPOINT + '/%s/storefronts/%s' % ('VTM_GO', STOREFRONT_MOVIES),
                            token=access_token,
                            profile=profile)
result6 = json.loads(response6.text)
print(result6)

Running this code gives:

$ python vtmtest.py
fill in:
GSGWVH
on url:
https://login2.vtm.be/androidtv
and press enter...
Traceback (most recent call last):
  File "../testcode/vtmtest.py", line 36, in <module>
    response3 = util.http_post('https://lfvp-api.dpgmedia.net/VTM_GO/tokens',
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "../testcode/util.py", line 77, in http_post
    return _request('POST', url=url, params=params, form=form, data=data, token=token, profile=profile, headers=headers)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "../testcode/util.py", line 185, in _request
    response.raise_for_status()
  File "/usr/lib/python3.12/site-packages/requests/models.py", line 1021, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 426 Client Error: Upgrade Required for url: https://lfvp-api.dpgmedia.net/VTM_GO/tokens

Errors occurs when this post-request is done:

response3 = util.http_post('https://lfvp-api.dpgmedia.net/VTM_GO/tokens',
                           data={'device': {'id': str(uuid.uuid4()),
                                            'name': 'VTM Go Addon on Kodi',
                                            },
                                 'idToken': id_token,
                                 })

Last line returns Upgrade Required for url.

I changed the values in the util.py-file according to this issue-response: add-ons/plugin.video.vtm.go#387 (comment)

SESSION.headers should now be:

SESSION.headers = {
    'User-Agent': 'VTM_GO/17.240626 (be.vmma.vtm.zenderapp; build:19069; Android 34) okhttp/4.12.0',
    'x-app-version': '17',
    'x-persgroep-mobile-app': 'true',
    'x-persgroep-os': 'android',
    'x-persgroep-os-version': '28',
}

and the scripts works!

I changed that on my device in the addon and as mentioned in add-ons/plugin.video.vtm.go#387 (comment) the menu is visible again, but when going into menu-items, nothing is visible.

json responses might have changed and that way parsed in the wrong way.

Debugging while running kodi. When I enter Movies/VTM GO/ Moet je nu zien I see this in debug.log:

024-06-29 15:45:36.188 T:22638   debug <general>: [plugin.video.vtm.go] [urllib3.connectionpool] https://lfvp-api.dpgmedia.net:443 "GET /VTM_GO/storefronts/movies/detail/a8b8e93d-6bb2-480a-8bb9-dc70968c6af4 HTTP/1.1" 200 3502
2024-06-29 15:45:36.189 T:22638    info <general>: Skipped 2 duplicate messages..
2024-06-29 15:45:36.189 T:22638   debug <general>: [plugin.video.vtm.go] [resources.lib.vtmgo.util] Got response (status=200): {"abroad":false,"row":{"id":"a8b8e93d-6bb2-480a-8bb9-dc70968c6af4","metaData":{"provider":"APP","campaignId":null},"title":"Moet je nu zien","rowType":"SWIMLANE_LANDSCAPE","teasers":[{"title":"The Boss Baby 2: Family Business","detailId":"47accde8-94b9-467f-8422-417574f51d2c","imageUrl":"https://images1.persgroep.net/rcs/YkaNPBQlG7Wgf64AXvO_EjpVWoI/diocontent/245107923/_fitwidth/426?appId=038a353bad43ac27fd436dc5419c256b&quality=0.8","overlayImageUrl":null,"comingSoon":null},{"title":"D'Ardennen","detailId":"5b84e08a-6b7a-4da6-a01d-4695d937550c","imageUrl":"https://images1.persgroep.net/rcs/Pt0gKix8lkOQsMOeNQ38hfszYoo/diocontent/233952978/_fitwidth/426?appId=038a353bad43ac27fd436dc5419c256b&quality=0.8","overlayImageUrl":null,"comingSoon":null},{"title":"De behandeling","detailId":"da16c6ac-5323-4c47-8dd7-dc144d9ad16c","imageUrl":"https://images3.persgroep.net/rcs/ySVqPfm7pr1ubuGm84x8XlrPhoM/diocontent/245077373/_fitwidth/426?appId=038a353bad43ac27fd436dc5419c256b&quality=0.8","overlayImageUrl":null,"comingSo
2024-06-29 15:45:36.189 T:22638    info <general>: Skipped 2 duplicate messages..
2024-06-29 15:45:36.189 T:22638   debug <general>: CPythonInvoker(2, .kodi/addons/plugin.video.vtm.go/addon_entry.py): script successfully run

The response contains all the information for the entries. So, we need to analyse the parser part.

@michaelarnauts
Copy link

FYI, I think I limit the response to the first 1024 bytes somewhere in the API code. If you remove that, you should see the full json. It might make it easier to find what's different.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment