Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widevine failing on VMP_VALIDATION_FAILED #397

Closed
gd71 opened this issue Mar 15, 2020 · 27 comments
Closed

Widevine failing on VMP_VALIDATION_FAILED #397

gd71 opened this issue Mar 15, 2020 · 27 comments

Comments

@gd71
Copy link

gd71 commented Mar 15, 2020

Hello,
in a configuration where I have to produce a license for a widevine encrypted DRM based stream.
The server is asking for cookies with the licURL post request, giving me error 400

2020-03-15 01:34:19.974 T:2523918544   ERROR: CCurlFile::Open failed with code 400 for https://music.amazon.fr/EU/api/dmls/:
                                            {"__type":"com.amazon.digitalmusiclocator#UnauthorizedException","message":"Request authentication failure : REQUIRED_COOKIES_MISSING (AuthenticationException) request-id: d21589fd-70fa-4064-96f6-184105ca008c"}

Some tokens are provided in the headers, others are in the POST_DATA field of the license_key property but others should also be provided by cookies.
Tried to embed the cookies data into header or post_data with no luck.
Far from being an expert on these topics, google did not help me so much.
header are in the form

    licHeaders = 'User-agent='+userAgent \
                +'&Content-Encoding=amz-1.0'\
                +'&Content-Type=application%2Fjson'\
                +'&cookie='+ urllib.quote_plus(cj_str)\
                +'&X-Amz-Target=com.amazon.digitalmusiclocator.DigitalMusicLocatorServiceExternal.getLicenseForPlaybackV2'\
                +'&csrf-token="'+ addon.getSetting('csrf_Token')+'"'\
                +'&csrf-rnd="'+ addon.getSetting('csrf_rndToken')+'"'\
                +'&csrf-ts="'+ addon.getSetting('csrf_tsToken')+'"'

body in the form

licpBody = '{"DrmType":"WIDEVINE","licenseChallenge":"B{SSM}","customerId":"`XXXXXXX","deviceToken":{"deviceTypeId":"XXXXXX","deviceId":"XXXXXX"},"appInfo":{"musicAgent":"Maestro/1.0 WebCP/1.0.202649.0 (c8d8-6a2f-dmcp-a62a-1594c)"}}'

Curl in debug mode from kodi:

2020-03-15 01:34:19.974 T:2523918544   ERROR: CCurlFile::Open failed with code 400 for https://music.amazon.fr/EU/api/dmls/:
                                            {"__type":"com.amazon.digitalmusiclocator#UnauthorizedException","message":"Request authentication failure : REQUIRED_COOKIES_MISSING (AuthenticationException) request-id: d21589fd-70fa-4064-96f6-184105ca008c"}

with a web browser in debug mode, I can see requests similar but with the cookie which make the difference.
Would love to know if ther is a way to embed the cookie data in the header or post_data field of the license_key property.
Thanks for your attention
Please note that it looks to me nothing illegal there as a valid prime member, my goal is just to be able to listen my music through my loved kodi app :)

@gd71
Copy link
Author

gd71 commented Mar 15, 2020

Looks like I'm not correctly encoding the headers as "Cookie=" entry should do the trick :(

@gd71 gd71 closed this as completed Mar 15, 2020
@gd71
Copy link
Author

gd71 commented Mar 15, 2020

Ok, I was indeed incorrectly quoting my headers (removed the quote_plus call).
but the Cookie content contains pipes characters leading to this error now:

2020-03-15 20:01:49.540 T:2739187920   DEBUG: AddOnLog: InputStream Adaptive: CDMMessage: 1 arrived!
2020-03-15 20:01:49.540 T:2739187920   ERROR: AddOnLog: InputStream Adaptive: 4 '|' separated blocks in licURL expected (req / header / body / response)
2020-03-15 20:01:49.540 T:2739187920   ERROR: AddOnLog: InputStream Adaptive: License update not successful (no keys)
2020-03-15 20:01:49.557 T:2739187920   DEBUG: AddOnLog: InputStream Adaptive: CDMMessage: 4 arrived!

@gd71 gd71 reopened this Mar 15, 2020
@glennguy
Copy link
Contributor

You should indeed be quoting the cookie value. Check the header output of your script vs. the headers in a browser, perhaps try quote instead of quote_plus.

@gd71
Copy link
Author

gd71 commented Mar 16, 2020

Thanks for the tips and shame on me, some token contains '+' and '=' which where converted to space with quote_plus.
Looks like I'm on a step further.
Headers are now correct and authentication looks sucessfull

2020-03-16 20:44:29.329 T:2519724240   ERROR: CCurlFile::Open failed with code 400 for https://music.amazon.fr/EU/api/dmls/:
                                            {"__type":"com.amazon.digitalmusiclocator#BadRequestExceptionV2","message":"Failed to decode widevine license challenge: Illegal base64 character 25 (BadRequestException EC_INVALID_PARAMETER) request-id: ef5f356c-8452-486c-998c-e46dff262d64 music-agent: Maestro/1.0 WebCP/1.0.202649.0 (c8d8-6a2f-dmcp-a62a-1594c)"}

This output should sounds better to you but even by reading the doc, I'm not in a situation to understand what should exactly base64 encoded by me.
Also, I set "B{SSM}" in the body for the "licenseChallenge" parameter of the json.
But on the web browser, there is 4 characters which are always the same for the first request.("licenseChallenge":"CAQ=")
This request answer is a json file containing the "license:" parameter and it looks like this is the value we want.
Following that, exactly the same request is sent but with a quite bigger payload in place of where I put the B{SSM}. and another json with license is provided.
Looks to me that it is the job of inpustream adaptive to perform the second request? I do not have any idea for now on how to fill the part of the second request.
So my questions are:

  • Can you confirm that the second request is handled by the widevine challenge ?
  • How can I know what to set in my request [b/B/R]{SSM} or [b/B/R]{SID} ?
  • How do we know where to put theses [b/B/R]{SSM} and [b/B/R]{SID} ?
  • How do I know if the challenge shall be base64 encoded or not? (probably the answer is implicit if I understand the other questions)

Finally, my apologies for bother you with these questions, looks like there is no bug nor improvment for inpustream.adaptive on this ticket. Tell me if you prefer having such kind of questions in another place.

@gd71
Copy link
Author

gd71 commented Mar 16, 2020

ok,
Looks like it shall be b{SSM}
Now the answer is

2020-03-16 21:43:38.700 T:2524754128   ERROR: CCurlFile::Open failed with code 400 for https://music.amazon.fr/EU/api/dmls/:
                                            {"__type":"com.amazon.digitalmusiclocator#DrmLicenseDeniedException","DrmType":"WIDEVINE","denialReason":"VMP_VALIDATION_FAILED","message":"WIDEVINE license denied (DrmLicenseDeniedException VMP_VALIDATION_FAILED) request-id: ee502894-a416-4df4-99d3-60b6ac7f7324 music-agent: Maestro/1.0 WebCP/1.0.202649.0 (c8d8-6a2f-dmcp-a62a-1594c)"}

in the debug browser, one difference is on the key in parenthesis for the music agent, this change from time to time and I still not understood the logic behind... Will check on the JScripts, but maybe this error sound to you and I shall looks elsewhere...
so close...

@yoshimo
Copy link

yoshimo commented Mar 16, 2020

Sandmann79/xbmc#294, sounds like the requesting executable is checked

@gd71
Copy link
Author

gd71 commented Mar 16, 2020

Wow indeed thanks for pointing that to me. Was Trying to contribute for pitpompej/kodi_plugins#22
I also had a look on what was done by @Sandmann79 in https://github.com/Sandmann79/xbmc especially regarding usage of inpustream.adaptive.
I also added some generic logic for getting the amazon API from (any?) regions (I'm FR).
So close !!! :(
I'm on raspberry PI 4, if I well understood the thread you reference, I shall try on my Nvidia shield device ? (will do anyway but it's on Kodi 19 nightlies and lots of stuff for porting the app :) )
Or is there nothing to do other than closing this issue ?

@gd71 gd71 changed the title Send cookies with license_key licURL Widevine failing on VMP_VALIDATION_FAILED Mar 16, 2020
@gd71
Copy link
Author

gd71 commented Mar 21, 2020

Hi there,
I finally made the porting (roughly) for the addon for Kodi Matrix nightly and tested on my NVidia Shield and it looks like the widevine drm challenge now is successful :

2020-03-21 16:48:37.135 T:13289   DEBUG: AddOnLog: InputStream Adaptive: Key Status (7):
2020-03-21 16:48:37.135 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> LicenseDurationRemaining -> 2591999
2020-03-21 16:48:37.135 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> LicenseType -> Streaming
2020-03-21 16:48:37.135 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> PersistAllowed -> False
2020-03-21 16:48:37.135 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> PlayAllowed -> True
2020-03-21 16:48:37.135 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> PlaybackDurationRemaining -> 9223372036854775807
2020-03-21 16:48:37.136 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> RenewAllowed -> False
2020-03-21 16:48:37.136 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> RenewalServerUrl ->
2020-03-21 16:48:37.136 T:13289   DEBUG: AddOnLog: InputStream Adaptive: License update successful
2020-03-21 16:48:37.137 T:13289   DEBUG: AddOnLog: InputStream Adaptive: Key Status (7):
2020-03-21 16:48:37.137 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> LicenseDurationRemaining -> 2591999
2020-03-21 16:48:37.137 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> LicenseType -> Streaming
2020-03-21 16:48:37.137 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> PersistAllowed -> False
2020-03-21 16:48:37.137 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> PlayAllowed -> True
2020-03-21 16:48:37.137 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> PlaybackDurationRemaining -> 9223372036854775807
2020-03-21 16:48:37.137 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> RenewAllowed -> False
2020-03-21 16:48:37.138 T:13289   DEBUG: AddOnLog: InputStream Adaptive: -> RenewalServerUrl ->
2020-03-21 16:48:37.138 T:13289   DEBUG: AddOnLog: InputStream Adaptive: GetCapabilities: hdcpLimit: 0
2020-03-21 16:48:37.139 T:13289   DEBUG: CAddonSettings[inputstream.adaptive]: loading setting definitions
2020-03-21 16:48:37.141 T:13289   DEBUG: CAddonSettings[inputstream.adaptive]: loading setting values
2020-03-21 16:48:37.142 T:13289   DEBUG: AddOnLog: InputStream Adaptive: GetCapabilities()
2020-03-21 16:48:37.142 T:13289   DEBUG: AddOnLog: InputStream Adaptive: GetStreamIds()
2020-03-21 16:48:37.142 T:13289   DEBUG: AddOnLog: InputStream Adaptive: GetStream(1001)
2020-03-21 16:48:37.142 T:13289   DEBUG: AddOnLog: InputStream Adaptive: GetStream(1001): initalizing crypto session
2020-03-21 16:48:37.142 T:13289   DEBUG: AddOnLog: InputStream Adaptive: GetStream(1002)
2020-03-21 16:48:37.143 T:13289   DEBUG: AddOnLog: InputStream Adaptive: GetStream(1002): initalizing crypto session
2020-03-21 16:48:37.143 T:13289   DEBUG: CDVDDemuxClient::RequestStream(): added/updated stream 1001 with codec_id 86018
2020-03-21 16:48:37.143 T:13289   DEBUG: CDVDDemuxClient::RequestStream(): added/updated stream 1002 with codec_id 86018
2020-03-21 16:48:37.143 T:13289   DEBUG: CDVDAudioCodecAndroidMediaCodec::Open codec(86018), profile(-99), tag(0), extrasize(0)
2020-03-21 16:48:37.143 T:13289  NOTICE: CDVDAudioCodecAndroidMediaCodec: extradata required for aac decoder!
2020-03-21 16:48:37.143 T:13289   ERROR: CDVDAudioCodecFFmpeg::Open() CryptoSessions unsupported!
2020-03-21 16:48:37.143 T:13289   ERROR: Init: Could not create audio codec

Can you confirm ?
Unfortunately, it looks like there is now an issue with the audio codec.
Is this error still related to inputstream.adaptive ? made a quick search but with no luck until now.
Thanks for your help

@glennguy
Copy link
Contributor

Can you attach the manifest? If it's HLS also one of the variant streams

@gd71
Copy link
Author

gd71 commented Mar 22, 2020

item parameters:

    play_item = xbmcgui.ListItem(path=temp_file_path)
    play_item = setPlayItemInfo(play_item)
    play_item.setProperty('inputstreamaddon', 'inputstream.adaptive')
    play_item.setProperty('inputstream.adaptive.manifest_type', 'mpd')
    play_item.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha')
    play_item.setProperty('inputstream.adaptive.license_key', licUrl)
    play_item.setProperty('IsPlayable', 'true')
    play_item.setMimeType('application/dash+xml')
    play_item.setContentLookup(False)

    xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=play_item)

MPD manifest:
Manifest.mpd

test with license_type com.microsoft.playready

2020-03-22 08:38:20.035 T:32623   DEBUG: AddOnLog: InputStream Adaptive: Successful instanciated deviceUniqueIdSize: 0,systemId:  security-level: L1
2020-03-22 08:38:20.035 T:32623   DEBUG: AddOnLog: InputStream Adaptive: Searching PSSH data in FILE
2020-03-22 08:38:20.039 T:32623   DEBUG: CurlFile::ParseAndCorrectUrl() adding custom header option 'connection: keep-alive'
2020-03-22 08:38:20.039 T:32623   DEBUG: CurlFile::Open(0x21df6d2100) https://dfqzuzzcqflbd.cloudfront.net/3fc2ae41-a240191256/952916c7-7f44-3e47-a1b6-9075bf1cc421.mp4?r=b7b7a302-7407-4fac-bf1e-89b40c6c82fe&rs=EU&mt=FR
2020-03-22 08:38:20.039 T:32623    INFO: easy_acquire - Created session to https://dfqzuzzcqflbd.cloudfront.net
2020-03-22 08:38:20.214 T:32623   DEBUG: AddOnLog: InputStream Adaptive: Download https://dfqzuzzcqflbd.cloudfront.net/3fc2ae41-a240191256/952916c7-7f44-3e47-a1b6-9075bf1cc421.mp4?r=b7b7a302-7407-4fac-bf1e-89b40c6c82fe&rs=EU&mt=FR finished, avg speed: 3460211.01byte/s, current speed: 9178.00byte/s
2020-03-22 08:38:20.215 T:32623   DEBUG: AddOnLog: InputStream Adaptive: Initializing stream with KID: C13DBEA90C6C0370044677172FBC709C
2020-03-22 08:38:20.469 T:32638   ERROR: SOCK: Error selecting socket(s)
2020-03-22 08:38:20.469 T:32638   ERROR: ES: Exception caught while listening for socket

Post-data json and license scheme:

{"DrmType":"WIDEVINE","licenseChallenge":"b{SSM}","customerId":"XXXXXXX","deviceToken":{"deviceTypeId":"A16ZV8BU3SN1N3","deviceId":"XXXXXXX"},"appInfo":{"musicAgent":"Maestro/1.0 WebCP/1.0.202649.0 (c8d8-6a2f-dmcp-a62a-1594c)"}}|JBlicense

with "Jlicense" as license scheme, I get

ERROR: AddOnLog: InputStream Adaptive: Unable to find icense in JSON string

@gd71
Copy link
Author

gd71 commented Mar 22, 2020

base64 decoding content of the mspr:pro tag in the manifest give WRM Header

<WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.0.0.0"><DATA><PROTECTINFO><KEYLEN>16</KEYLEN><ALGID>AESCTR</ALGID></PROTECTINFO><KID>qb49wWwMcAMERncXL7xwnA==</KID><CHECKSUM>h+5o/FpoNOU=</CHECKSUM><LA_URL>https://music.amazon.com/dmls/acquireLicense</LA_URL></DATA></WRMHEADER>

but setting license_type to com.microsoft.playready and removing license_key param gives:

2020-03-22 17:14:29.866 T:15640   ERROR: AddOnLog: InputStream Adaptive: Key system request: com.microsoft.playready
2020-03-22 17:14:29.866 T:15640   DEBUG: AddOnLog: InputStream Adaptive: Found decrypter: /data/app/org.xbmc.kodi-jO59hUtDL2N_as7uND3WvQ==/lib/arm64/libssd_wv.so
2020-03-22 17:14:29.866 T:15640   DEBUG: AddOnLog: InputStream Adaptive: Supported URN: urn:uuid:9A04F079-9840-4286-AB92-E65BE0885F95
2020-03-22 17:14:29.866 T:15640   DEBUG: AddOnLog: InputStream Adaptive: Effective URL
2020-03-22 17:14:29.867 T:15640   DEBUG: AddOnLog: InputStream Adaptive: Download /storage/emulated/0/Android/data/org.xbmc.kodi/files/.kodi/userdata/addon_data/plugin.audio.prime_music/temp.mpd finished
2020-03-22 17:14:29.867 T:15640    INFO: AddOnLog: InputStream Adaptive: Successfully parsed .mpd file. #Periods: 1, #Streams in first period: 1, Type: VOD, Download speed: 3465475.0111 Bytes/s
2020-03-22 17:14:29.868 T:15640   DEBUG: CAddonSettings[inputstream.adaptive]: loading setting definitions
2020-03-22 17:14:29.870 T:15640   DEBUG: CAddonSettings[inputstream.adaptive]: loading setting values
2020-03-22 17:14:29.871 T:15640   DEBUG: CAddonSettings[inputstream.adaptive]: loading setting definitions
2020-03-22 17:14:29.873 T:15640   DEBUG: CAddonSettings[inputstream.adaptive]: loading setting values
2020-03-22 17:14:29.873 T:15640   DEBUG: AddOnLog: InputStream Adaptive: Entering encryption section
2020-03-22 17:14:29.873 T:15640   ERROR: AddOnLog: InputStream Adaptive: Invalid license_key
2020-03-22 17:14:29.873 T:15640   DEBUG: AddOnLog: InputStream Adaptive: Session::~Session()
2020-03-22 17:14:29.873 T:15640   DEBUG: AddOnLog: InputStream Adaptive: WVDecrypter destructed

but in this case, the widevine request for getting license is not performed and I can see this request performed twice in chrome.
Keeping the license_key param with playready perform the license request and mp4 is downloaded but error ERROR: ES: Exception caught while listening for socket
Could be that amazon music is mixing the two DRM schemes?
lost in the fog now XD

@spacys
Copy link

spacys commented Mar 23, 2020

I have similar issues with the license challenge and I'm happy to see your progress. You are a step ahead to me.
Afaik amazon is not mixing the DRM schemes, its just depending on the browser capabilities, so widewine should be fine and enough.

@gd71
Copy link
Author

gd71 commented Mar 23, 2020

There are also XHR which I considered to not implement because of the manifest already got and thought linked to the internal HTML5 player to start playing:

{...
streamingStatus: PLAY
}

Shall I?
in this case, I shall also implement pause, stop ...

@glennguy
Copy link
Contributor

I think you shoud stick to widevine, playready isn't supported on most platforms.

Have you tried testing on a platform other than Android?

Also can you upload a full debug log, not just a snippet? There might be an issue we can't see

@gd71
Copy link
Author

gd71 commented Mar 23, 2020

will do for the full debug, need to cleanup a bit my dirty logs before :).
I have 2 platforms, Raspberry PI 4b - KODI 18.5 and Android NVidia shield - KODI 19 Nightly.
Best results are on Android, Raspberry gave me the VMP_VALIDATION_FAILED issue.
But since, I've made some progress with Android, I'll try to maintain both code in parallel.

@spacys
Copy link

spacys commented Mar 24, 2020

I was able to receive the license and to play the songs via inputstream.
There was a need to quote nearly everything. Especially the cookie information has sometimes an '=' at the end and this needs to be saved.
Hopefully this will help you.

licHeaders = 'User-Agent={}&Content-Encoding=amz-1.0&Content-Type=application%2Fjson&Cookie={}'.format(urllib.quote(self.userAgent),urllib.quote(cj_str)) licHeaders +='&X-Amz-Target={}'.format(amzUrl['target']) licHeaders +='&csrf-token={}'.format(urllib.quote(self.csrf_token)) licHeaders +='&csrf-rnd={}'.format(urllib.quote(self.csrf_rnd)) licHeaders +='&csrf-ts={}'.format(urllib.quote(self.csrf_ts))

@gd71
Copy link
Author

gd71 commented Mar 24, 2020

Nice!
unfortunately, this is mostly what I did for the headers...:(
What about the post-data and license keyword used? (parts of the whole licURL) did you have to quote things also into or serialize the json part?
Was not aware of the addon you intend to do, I'm ready for testing on Android and raspberry ;)

@spacys
Copy link

spacys commented Mar 24, 2020

Please note I also removed the "" for the csrf information. It looks similar but it is different, at least compared to the first post. The JSON part is the same like yours, no quotes.
But I have added on more thing...
li.setProperty('inputstream.adaptive.stream_headers', 'user-agent=' + self.userAgent)

@gd71
Copy link
Author

gd71 commented Mar 24, 2020

I had already fixed the quote issue on the headers for csrf info, I'm in the same situation as yours
I guess my issue come from the POST-DATA field or the license field ... or both
Adding stream_headers property didn't change the result

@gd71
Copy link
Author

gd71 commented Mar 24, 2020

Attached the log, I clearly see that the widevine challenge got the license license.
Looks like giving the stream to the audio system is failing.
kodi.log

@spacys
Copy link

spacys commented Mar 24, 2020

You are right, it looks good. I see some differences...I do not have the following defined:

  • Accept-Charset: UTF-8,*;q=0.8
  • X-Requested-With: XMLHttpRequest
  • Accept-Encoding: gzip, deflate
    My licBody looks like:
    licBody = '{"DrmType":"WIDEVINE","licenseChallenge":"b{SSM}","customerId":"'+self.customerId+'","deviceToken":{"deviceTypeId":"'+self.deviceType+'","deviceId":"'+self.deviceId+'"},"appInfo":{"musicAgent":"Maestro/1.0 WebCP/1.0.202649.0 (c8d8-6a2f-dmcp-a62a-1594c)"}}' return '{}|{}|{}|JBlicense'.format(url,licHeaders,licBody)

@gd71
Copy link
Author

gd71 commented Mar 24, 2020

On which platform are you ?
Also did you test on both Leia and Matrix ?
the X-Requested-With is set by me and come from what I saw in chrome debug session
Accept-Charset might be automatically set by Curl, I guess

@spacys
Copy link

spacys commented Mar 24, 2020

I'm on Kodi 18.6 on Ubuntu 18.04. and 19.x, all 64 Bit x86 systems.
I never tested it on an older Kodi version.
My implementation is now released, so you can have a look into it.

@gd71
Copy link
Author

gd71 commented Mar 24, 2020

Ok, will test on my ubuntu box 19.10 my piece of code.
BTW, I found an algorithm regarding the music-agent code into parenthesis, it is a pure random integer numbering to hex str concatenated with '-', JS client side only. Looks like the server could check from time to time if this change... And it is the case in a debug session from chrome. But if it works on your side with these numbers probably mean that not used nor implemented yet.
Will also test your implementation 19.x on Android, thanks for sharing

@gd71
Copy link
Author

gd71 commented Mar 24, 2020

ok, I've got an FR account, so I can't test it now. Didn't yet check your code but quite easy to extend to other countries. Look like you started from the same origin as mine. :)
(suffix of cookies fr, url.'fr', EU/DML...) and that's it

@gd71
Copy link
Author

gd71 commented Mar 24, 2020

Was wrong, you did not start from any origin but inspiration
very nice code !
Still some slight adaptation for python 3 / Kodi 19
Added FR
Works on Android kodi 19 like a charm.
My issue was getting the maestroID, you implemented it, it was my only remaining thing to do (2 comments before).
Will close this issue and see you on your github project

@gd71 gd71 closed this as completed Mar 24, 2020
@spacys
Copy link

spacys commented Mar 25, 2020

Nice to hear and love to help.
I see, I have to extend my code for other countries as well. ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants