From 9f64ed1231cce8250bd7da278a5bf85838b0e0ec Mon Sep 17 00:00:00 2001 From: THEOportal <64831658+THEOportal@users.noreply.github.com> Date: Wed, 23 Sep 2020 11:16:11 +0200 Subject: [PATCH 01/85] Initial commit --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..0b145393 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# samples-drm-integration \ No newline at end of file From 5ecb2d7342f3115731811f122c501617588b4cfe Mon Sep 17 00:00:00 2001 From: Jeroen Veltmans Date: Tue, 13 Oct 2020 09:10:53 +0200 Subject: [PATCH 02/85] Add samples-drm-integration --- .gitignore | 55 + README.md | 10 +- android/.gitignore | 14 + android/README.md | 158 ++ android/app/.gitignore | 1 + android/app/build.gradle | 21 + android/app/src/main/AndroidManifest.xml | 25 + .../MainActivity.java | 20 + .../PlayerActivity.java | 28 + .../SourceListFragment.java | 36 + .../SourceManager.java | 101 + ...eWidevineContentProtectionIntegration.java | 36 + ...neContentProtectionIntegrationFactory.java | 12 + ...mWidevineContentProtectionIntegration.java | 77 + ...neContentProtectionIntegrationFactory.java | 12 + .../drawable-v24/ic_launcher_foreground.xml | 30 + .../res/drawable/ic_launcher_background.xml | 170 ++ .../app/src/main/res/layout/activity_main.xml | 11 + .../src/main/res/layout/activity_player.xml | 16 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3593 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5339 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2636 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 3388 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4926 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7472 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7909 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 11873 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10652 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 16570 bytes android/app/src/main/res/values/colors.xml | 6 + android/app/src/main/res/values/strings.xml | 3 + android/app/src/main/res/values/styles.xml | 10 + .../main/res/xml/network_security_config.xml | 8 + android/build.gradle | 23 + android/gradle.properties | 19 + .../gradle/wrapper/gradle-wrapper.properties | 6 + android/gradlew | 172 ++ android/gradlew.bat | 84 + android/settings.gradle | 2 + .../project.pbxproj | 397 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../AppDelegate.swift | 41 + .../AppIcon.appiconset/Contents.json | 98 + .../Assets.xcassets/Contents.json | 6 + .../Base.lproj/LaunchScreen.storyboard | 25 + .../Base.lproj/Main.storyboard | 24 + ios/ContentProtectionIntegration/Info.plist | 64 + .../SceneDelegate.swift | 52 + .../ViewController.swift | 44 + .../integration/AzureDRMIntegration.swift | 82 + .../integration/UplynkDRMIntegration.swift | 82 + .../integration/VuDRMIntegration.swift | 74 + ios/README.md | 131 + web/.eslintrc.json | 18 + web/README.md | 185 ++ web/package-lock.json | 2168 +++++++++++++++++ web/package.json | 42 + web/rollup.config.js | 16 + web/src/index.ts | 33 + .../axinomdrm/AxinomDrmConfiguration.ts | 30 + ...DrmFairplayContentProtectionIntegration.ts | 45 + ...playContentProtectionIntegrationFactory.ts | 12 + ...rmPlayReadyContentProtectionIntegration.ts | 32 + ...eadyContentProtectionIntegrationFactory.ts | 12 + .../integration/axinomdrm/AxinomDrmUtils.ts | 5 + ...DrmWidevineContentProtectionIntegration.ts | 32 + ...vineContentProtectionIntegrationFactory.ts | 12 + .../azuredrm/AzureDrmConfiguration.ts | 30 + ...DrmFairplayContentProtectionIntegration.ts | 62 + ...playContentProtectionIntegrationFactory.ts | 12 + ...rmPlayReadyContentProtectionIntegration.ts | 32 + ...eadyContentProtectionIntegrationFactory.ts | 12 + web/src/integration/azuredrm/AzureDrmUtils.ts | 5 + ...DrmWidevineContentProtectionIntegration.ts | 32 + ...vineContentProtectionIntegrationFactory.ts | 12 + .../ezdrm/EzdrmDrmConfiguration.ts | 27 + ...drmFairplayContentProtectionIntegration.ts | 46 + ...playContentProtectionIntegrationFactory.ts | 12 + .../vudrm/VudrmDrmConfiguration.ts | 50 + ...drmFairplayContentProtectionIntegration.ts | 58 + ...playContentProtectionIntegrationFactory.ts | 12 + ...rmPlayReadyContentProtectionIntegration.ts | 35 + ...eadyContentProtectionIntegrationFactory.ts | 12 + web/src/integration/vudrm/VudrmUtil.ts | 5 + ...drmWidevineContentProtectionIntegration.ts | 43 + ...vineContentProtectionIntegrationFactory.ts | 12 + web/src/utils/FairplayUtils.ts | 19 + web/test/axinomdrm/fairplay.html | 48 + web/test/axinomdrm/playready.html | 47 + web/test/axinomdrm/widevine.html | 47 + web/test/azuredrm/fairplay.html | 47 + web/test/azuredrm/playready.html | 46 + web/test/azuredrm/widevine.html | 46 + web/test/ezdrm/fairplay.html | 44 + web/test/vudrm/fairplay.html | 47 + web/test/vudrm/playready.html | 46 + web/test/vudrm/widevine.html | 47 + web/tsconfig.json | 69 + 101 files changed, 6014 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 android/.gitignore create mode 100644 android/README.md create mode 100644 android/app/.gitignore create mode 100644 android/app/build.gradle create mode 100644 android/app/src/main/AndroidManifest.xml create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceListFragment.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.java create mode 100644 android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 android/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 android/app/src/main/res/layout/activity_main.xml create mode 100644 android/app/src/main/res/layout/activity_player.xml create mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/values/colors.xml create mode 100644 android/app/src/main/res/values/strings.xml create mode 100644 android/app/src/main/res/values/styles.xml create mode 100644 android/app/src/main/res/xml/network_security_config.xml create mode 100644 android/build.gradle create mode 100644 android/gradle.properties create mode 100644 android/gradle/wrapper/gradle-wrapper.properties create mode 100644 android/gradlew create mode 100644 android/gradlew.bat create mode 100644 android/settings.gradle create mode 100644 ios/ContentProtectionIntegration.xcodeproj/project.pbxproj create mode 100644 ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 ios/ContentProtectionIntegration/AppDelegate.swift create mode 100644 ios/ContentProtectionIntegration/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 ios/ContentProtectionIntegration/Assets.xcassets/Contents.json create mode 100644 ios/ContentProtectionIntegration/Base.lproj/LaunchScreen.storyboard create mode 100644 ios/ContentProtectionIntegration/Base.lproj/Main.storyboard create mode 100644 ios/ContentProtectionIntegration/Info.plist create mode 100644 ios/ContentProtectionIntegration/SceneDelegate.swift create mode 100644 ios/ContentProtectionIntegration/ViewController.swift create mode 100644 ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift create mode 100644 ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift create mode 100644 ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift create mode 100644 ios/README.md create mode 100644 web/.eslintrc.json create mode 100644 web/README.md create mode 100644 web/package-lock.json create mode 100644 web/package.json create mode 100644 web/rollup.config.js create mode 100644 web/src/index.ts create mode 100644 web/src/integration/axinomdrm/AxinomDrmConfiguration.ts create mode 100644 web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts create mode 100644 web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts create mode 100644 web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/axinomdrm/AxinomDrmUtils.ts create mode 100644 web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts create mode 100644 web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/azuredrm/AzureDrmConfiguration.ts create mode 100644 web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts create mode 100644 web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts create mode 100644 web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/azuredrm/AzureDrmUtils.ts create mode 100644 web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts create mode 100644 web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/ezdrm/EzdrmDrmConfiguration.ts create mode 100644 web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts create mode 100644 web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/vudrm/VudrmDrmConfiguration.ts create mode 100644 web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts create mode 100644 web/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts create mode 100644 web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/vudrm/VudrmUtil.ts create mode 100644 web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts create mode 100644 web/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts create mode 100644 web/src/utils/FairplayUtils.ts create mode 100644 web/test/axinomdrm/fairplay.html create mode 100644 web/test/axinomdrm/playready.html create mode 100644 web/test/axinomdrm/widevine.html create mode 100644 web/test/azuredrm/fairplay.html create mode 100644 web/test/azuredrm/playready.html create mode 100644 web/test/azuredrm/widevine.html create mode 100644 web/test/ezdrm/fairplay.html create mode 100644 web/test/vudrm/fairplay.html create mode 100644 web/test/vudrm/playready.html create mode 100644 web/test/vudrm/widevine.html create mode 100644 web/tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..eeb38795 --- /dev/null +++ b/.gitignore @@ -0,0 +1,55 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Maven +target/ +dist/ + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +# THEOplayer build and TypeScript definitions +THEOplayer/ +ios/THEOplayerSDK.framework +xcuserdata/ +android/app/libs/theoplayer.aar diff --git a/README.md b/README.md index 0b145393..feb84b9a 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -# samples-drm-integration \ No newline at end of file +# THEOplayer DRM integrations + +This repository contains a subset of the current integrated DRM integrations of THEOplayer. They serve as an example for integrating +with the THEOplayer DRM API. + +### Table of Contents +- [Getting started on Web](web/README.md) +- [Getting started on Android](android/README.md) +- [Getting started on iOS](ios/README.md) diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 00000000..603b1407 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/android/README.md b/android/README.md new file mode 100644 index 00000000..75c48a06 --- /dev/null +++ b/android/README.md @@ -0,0 +1,158 @@ +## Getting started on Android + +### Creating a new integration + +First create a custom implementation of [ContentProtectionIntegration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/android/latest/com/theoplayer/android/api/contentprotection/ContentProtectionIntegration.html) +in the [com.theoplayer.contentprotectionintegration.integration](/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration) +package. +This object defines handler methods that allow altering license and certificate requests and responses as part of the +DRM flow. +All methods are optional. They can be omitted if the integration does not require additional action, in which case the +default implementation will be used. + +```java +package com.theoplayer.contentprotectionintegration.custom; + +import com.theoplayer.android.api.contentprotection.CertificateRequestCallback; +import com.theoplayer.android.api.contentprotection.CertificateResponseCallback; +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; +import com.theoplayer.android.api.contentprotection.LicenseResponseCallback; +import com.theoplayer.android.api.contentprotection.Request; +import com.theoplayer.android.api.contentprotection.Response; +import com.theoplayer.android.api.source.drm.DRMConfiguration; + +public class CustomContentProtectionIntegration extends ContentProtectionIntegration { + + private final DRMConfiguration contentProtectionConfiguration; + + public CustomContentProtectionIntegration(DRMConfiguration configuration) { + this.contentProtectionConfiguration = configuration; + } + + public void onCertificateRequest(Request request, CertificateRequestCallback callback) { + callback.request(request); + } + + public void onCertificateResponse(Response response, CertificateResponseCallback callback) { + callback.respond(response.getBody()); + } + + public void onLicenseRequest(Request request, LicenseRequestCallback callback) { + // final Object token = this.contentProtectionConfiguration.getIntegrationParameters().get("token"); + // request.getHeaders().put("x-token", token.toString()); + callback.request(request); + } + + public void onLicenseResponse(Response response, LicenseResponseCallback callback) { + callback.respond(response.getBody()); + } +} +``` + +Optional parameters needed for certificate or license requests, such as tokens, can be added to a +[DRMConfiguration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/android/latest/com/theoplayer/android/api/source/drm/DRMConfiguration.html) +object that is passed when creating instances of the `CustomContentProtectionIntegration` class. +In the example, `CustomContentProtectionIntegration` adds a token from the configuration object as part of the headers +during a license request. + +Next, create a [ContentProtectionIntegrationFactory](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/android/latest/com/theoplayer/android/api/contentprotection/ContentProtectionIntegrationFactory.html) +for building CustomContentProtectionIntegration instances. +THEOplayer will use this factory in its DRM flow whenever it needs a ContentProtectionIntegration instance that +matches with the content protected source. How THEOplayer knows which factory to take will be determined in the +`registerContentProtectionIntegration` step next. + +```java +package com.theoplayer.contentprotectionintegration.custom; + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; +import com.theoplayer.android.api.source.drm.DRMConfiguration; + +public class CustomContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + @Override + public ContentProtectionIntegration build(DRMConfiguration configuration) { + return new CustomContentProtectionIntegration(configuration); + } +} +``` + +An instance of `CustomContentProtectionIntegrationFactory` needs to be registered with THEOplayer's global instance in the +[SourceManager](/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java) +by specifying a unique `integrationId`, such as `"CUSTOM"` in this example. + +```java +String CUSTOM_ID = "CUSTOM"; +THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + CUSTOM_ID, + KeySystemId.WIDEVINE, + new CustomContentProtectionIntegrationFactory() +); +``` + +When the player now loads a source with a `customIntegrationId` that matches the `integrationId` +passed during registration, an instance of `CustomContentProtectionIntegration` will be created and used in the DRM flow. + +Also add the source description here, which provides the manifest and license URLs along with any integration parameters. + +```java +public class SourceManager { + + private void initSources(Context context) { + // Custom content protect integration + String CUSTOM_ID = "CUSTOM"; + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + CUSTOM_ID, + KeySystemId.WIDEVINE, + new CustomContentProtectionIntegrationFactory() + ); + sources.put( + "Custom Widevine", + buildWidevineSourceDescription( + CUSTOM_ID, + "", + "", + new HashMap() {{ + // optional integration parameters + // put("token", ""); + }} + ) + ); + + // add other registrations & sources here ... + } + + private SourceDescription buildWidevineSourceDescription( + String integrationId, + String manifestUrl, + String licenseUrl, + HashMap integrationParams) { + return sourceDescription( + typedSource(manifestUrl) + .setNativeRenderingEnabled(true) + .setNativeUiRenderingEnabled(false) + .drm(new DRMConfiguration.Builder() + .customIntegrationId(integrationId) + .integrationParameters(integrationParams) + .widevine(keySystemConfiguration(licenseUrl).build()) + .build()) + .build() + ).build(); + } +} +``` + +Finally, build and run the app on an Android device or Android emulator. + +### Available examples + +- Vualto VuDRM +- Microsoft Azure DRM + +### Testing an integration + +- Add your THEOplayer Android Archive (AAR) into the [/android/app/libs/]() folder and rename it to `theoplayer.aar`. +- Depending on the features included in your THEOplayer build, include the necessary dependencies in `/android/app/build.gradle`. +- Open the `/android` folder in [Android Studio](https://developer.android.com/studio) and build the project. +- Make sure to fill in the necessary fields in `SourceManager` for the content integration that will be tested, such as the manifest url and any integration parameters. +- Attach either a physical Android device or start an Android emulator, and run the project. diff --git a/android/app/.gitignore b/android/app/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/android/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 00000000..16779101 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.1" + + defaultConfig { + applicationId "com.theoplayer.contentprotectionintegration" + minSdkVersion 16 + targetSdkVersion 30 + multiDexEnabled true + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.1' + implementation 'com.google.code.gson:gson:2.8.6' + implementation(name:'theoplayer', ext:'aar') + implementation 'com.android.support:multidex:1.0.3' +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..ac25b369 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.java new file mode 100644 index 00000000..69497e69 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.java @@ -0,0 +1,20 @@ +package com.theoplayer.contentprotectionintegration; + +import android.os.Bundle; + +import androidx.appcompat.app.AppCompatActivity; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + getSupportFragmentManager() + .beginTransaction() + .add(R.id.frame_container, new SourceListFragment(), SourceListFragment.TAG) + .disallowAddToBackStack() + .commit(); + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java new file mode 100644 index 00000000..eb0e8727 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java @@ -0,0 +1,28 @@ +package com.theoplayer.contentprotectionintegration; + +import android.os.Bundle; + +import androidx.appcompat.app.AppCompatActivity; + +import com.theoplayer.android.api.THEOplayerView; +import com.theoplayer.android.api.source.SourceDescription; + +public class PlayerActivity extends AppCompatActivity { + + public final static String EXTRA_SOURCENAME = "sourceName"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_player); + + Bundle extras = getIntent().getExtras(); + if (extras != null) { + String sourceName = extras.getString(EXTRA_SOURCENAME); + THEOplayerView playerView = findViewById(R.id.theoplayer); + SourceDescription sourceDescription = SourceManager.getInstance(this).getSource(sourceName); + playerView.getPlayer().setSource(sourceDescription); + playerView.getPlayer().play(); + } + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceListFragment.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceListFragment.java new file mode 100644 index 00000000..2450f78e --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceListFragment.java @@ -0,0 +1,36 @@ +package com.theoplayer.contentprotectionintegration; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import androidx.annotation.NonNull; +import androidx.fragment.app.ListFragment; + +public class SourceListFragment extends ListFragment { + + public final static String TAG = "SourceList"; + + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (getActivity() != null) { + String[] sourceNames = SourceManager.getInstance(getActivity()).getSourcesNames(); + ArrayAdapter adapter = + new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, sourceNames); + setListAdapter(adapter); + } + } + + @Override + public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) { + if (getListAdapter() == null) { + return; + } + String item = (String) getListAdapter().getItem(position); + Intent intent = new Intent(getActivity(), PlayerActivity.class); + intent.putExtra(PlayerActivity.EXTRA_SOURCENAME, item); + startActivity(intent); + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java new file mode 100644 index 00000000..45db4934 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java @@ -0,0 +1,101 @@ +package com.theoplayer.contentprotectionintegration; + +import android.content.Context; + +import com.theoplayer.android.api.THEOplayerGlobal; +import com.theoplayer.android.api.contentprotection.KeySystemId; +import com.theoplayer.android.api.source.SourceDescription; +import com.theoplayer.android.api.source.drm.DRMConfiguration; +import com.theoplayer.contentprotectionintegration.integration.azuredrm.AzureWidevineContentProtectionIntegrationFactory; +import com.theoplayer.contentprotectionintegration.integration.vudrm.VudrmWidevineContentProtectionIntegrationFactory; + +import java.util.HashMap; + +import static com.theoplayer.android.api.source.SourceDescription.Builder.sourceDescription; +import static com.theoplayer.android.api.source.TypedSource.Builder.typedSource; +import static com.theoplayer.android.api.source.drm.KeySystemConfiguration.Builder.keySystemConfiguration; + +public class SourceManager { + + private static SourceManager instance = null; + + private HashMap sources = new HashMap<>(); + + private SourceManager(Context context) { + initSources(context); + } + + public static SourceManager getInstance(Context context) { + if (SourceManager.instance == null) { + instance = new SourceManager(context); + } + return instance; + } + + public SourceDescription getSource(String name) { + return sources.get(name); + } + + public String[] getSourcesNames() { + return sources.keySet().toArray(new String[0]); + } + + private SourceDescription buildWidevineSourceDescription( + String integrationId, + String manifestUrl, + String licenseUrl, + HashMap integrationParams) { + return sourceDescription( + typedSource(manifestUrl) + .drm(new DRMConfiguration.Builder() + .customIntegrationId(integrationId) + .integrationParameters(integrationParams) + .widevine(keySystemConfiguration(licenseUrl).build()) + .build()) + .build() + ).build(); + } + + private void initSources(Context context) { + // Vualto VUDRM Widevine content protect integration + String VUDRM_ID = "VUDRM"; + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + VUDRM_ID, + KeySystemId.WIDEVINE, + new VudrmWidevineContentProtectionIntegrationFactory() + ); + sources.put( + "Vualto VUDRM Widevine", + buildWidevineSourceDescription( + VUDRM_ID, + "", + "", + new HashMap() {{ + put("token", ""); + put("keyId", ""); + }} + ) + ); + + // Microsoft Azure Widevine content protect integration + String AZURE_ID = "AZURE"; + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + AZURE_ID, + KeySystemId.WIDEVINE, + new AzureWidevineContentProtectionIntegrationFactory() + ); + sources.put( + "Microsoft Azure Widevine", + buildWidevineSourceDescription( + AZURE_ID, + "", + "", + new HashMap() {{ + put("token", ""); + }} + ) + ); + + // add other registrations & sources here ... + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.java new file mode 100644 index 00000000..224d789c --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.java @@ -0,0 +1,36 @@ +package com.theoplayer.contentprotectionintegration.integration.azuredrm; + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; +import com.theoplayer.android.api.contentprotection.Request; +import com.theoplayer.android.api.source.drm.DRMConfiguration; + +public class AzureWidevineContentProtectionIntegration extends ContentProtectionIntegration { + + private final DRMConfiguration contentProtectionConfiguration; + + public AzureWidevineContentProtectionIntegration(DRMConfiguration configuration) { + this.contentProtectionConfiguration = configuration; + } + + public void onLicenseRequest(final Request request, LicenseRequestCallback callback) { + Object token = contentProtectionConfiguration.getIntegrationParameters().get("token"); + if (token == null) { + callback.error(new NullPointerException("The Azure drm token can not be null")); + return; + } + String licenseUrl = null; + if (contentProtectionConfiguration.getWidevine() != null) { + licenseUrl = contentProtectionConfiguration.getWidevine().getLicenseAcquisitionURL(); + } + if (licenseUrl == null) { + callback.error(new NullPointerException("The Azure licenseAcquisitionURL can not be null")); + return; + } + request.setUrl(licenseUrl); + request.getHeaders().put( + "Authorization", + "Bearer " + token.toString()); + callback.request(request); + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.java new file mode 100644 index 00000000..a270afbb --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.java @@ -0,0 +1,12 @@ +package com.theoplayer.contentprotectionintegration.integration.azuredrm; + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; +import com.theoplayer.android.api.source.drm.DRMConfiguration; + +public class AzureWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + @Override + public ContentProtectionIntegration build(DRMConfiguration configuration) { + return new AzureWidevineContentProtectionIntegration(configuration); + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java new file mode 100644 index 00000000..82f050b9 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java @@ -0,0 +1,77 @@ +package com.theoplayer.contentprotectionintegration.integration.vudrm; + +import com.theoplayer.android.api.contentprotection.CertificateRequestCallback; +import com.theoplayer.android.api.contentprotection.CertificateResponseCallback; +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; +import com.theoplayer.android.api.contentprotection.Request; +import com.theoplayer.android.api.contentprotection.Response; +import com.theoplayer.android.api.source.drm.DRMConfiguration; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class VudrmWidevineContentProtectionIntegration extends ContentProtectionIntegration { + + static final String DEFAULT_LICENSE_URL = "https://widevine-proxy.drm.technology/proxy"; + + private final DRMConfiguration contentProtectionConfiguration; + + public VudrmWidevineContentProtectionIntegration(DRMConfiguration configuration) { + this.contentProtectionConfiguration = configuration; + } + + private Request wrapRequest(Request request) { + if (request.getBody() == null) { + throw new NullPointerException("The request body can not be null"); + } + final Object token = this.contentProtectionConfiguration.getIntegrationParameters().get("token"); + if (token == null) { + throw new NullPointerException("The Widevine vuDRM token can not be null"); + } + + String licenseUrl = DEFAULT_LICENSE_URL; + if (contentProtectionConfiguration.getWidevine() != null) { + licenseUrl = contentProtectionConfiguration.getWidevine().getLicenseAcquisitionURL(); + } + request.setUrl(licenseUrl); + request.getHeaders().put("Content-Type", "text/plain"); + + final Object kid = contentProtectionConfiguration.getIntegrationParameters().get("keyId"); + JSONObject jsonBody = new JSONObject(); + try { + jsonBody.put("token", token); + jsonBody.put("drm_info", toUint8JsonArray(request.getBody())); + jsonBody.put("kid", kid); + } catch (JSONException e) { + e.printStackTrace(); + } + request.setBody(jsonBody.toString().getBytes()); + return request; + } + + public void onCertificateRequest(Request request, final CertificateRequestCallback callback) { + try { + callback.request(wrapRequest(request)); + } catch (Throwable error) { + callback.error(error); + } + } + + public void onLicenseRequest(final Request request, LicenseRequestCallback callback) { + try { + callback.request(wrapRequest(request)); + } catch (Throwable error) { + callback.error(error); + } + } + + private JSONArray toUint8JsonArray(final byte [] bytes) { + JSONArray jsonArray = new JSONArray(); + for (byte aByte : bytes) { + jsonArray.put(aByte & 0xff); + } + return jsonArray; + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.java new file mode 100644 index 00000000..d12475ec --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.java @@ -0,0 +1,12 @@ +package com.theoplayer.contentprotectionintegration.integration.vudrm; + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; +import com.theoplayer.android.api.source.drm.DRMConfiguration; + +public class VudrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + @Override + public ContentProtectionIntegration build(DRMConfiguration configuration) { + return new VudrmWidevineContentProtectionIntegration(configuration); + } +} diff --git a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..2b068d11 --- /dev/null +++ b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..10437a11 --- /dev/null +++ b/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,11 @@ + + + + diff --git a/android/app/src/main/res/layout/activity_player.xml b/android/app/src/main/res/layout/activity_player.xml new file mode 100644 index 00000000..3634111d --- /dev/null +++ b/android/app/src/main/res/layout/activity_player.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a571e60098c92c2baca8a5df62f2929cbff01b52 GIT binary patch literal 3593 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 P00000NkvXXu0mjfP=x?Y literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..61da551c5594a1f9d26193983d2cd69189014603 GIT binary patch literal 5339 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..b216f2d313cc673d8b8c4da591c174ebed52795c GIT binary patch literal 11873 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..4faecfa8 --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #6200EE + #3700B3 + #03DAC5 + \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..caac14e4 --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + ContentProtectionIntegration + \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..fac92916 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 00000000..bd229b92 --- /dev/null +++ b/android/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 00000000..d72153a7 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,23 @@ +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath "com.android.tools.build:gradle:4.0.1" + } +} + +allprojects { + repositories { + google() + jcenter() + flatDir { + dirs 'libs' + } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000..c52ac9b7 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,19 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..221b73f1 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Sep 07 22:14:00 CEST 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/android/gradlew b/android/gradlew new file mode 100644 index 00000000..cccdd3d5 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 00000000..f9553162 --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 00000000..de3e0024 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,2 @@ +include ':app' +rootProject.name = "ContentProtectionIntegration" \ No newline at end of file diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj new file mode 100644 index 00000000..e45d580f --- /dev/null +++ b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj @@ -0,0 +1,397 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */; }; + D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */; }; + D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */; }; + E279FE3A25139E4700EC0EFA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3925139E4700EC0EFA /* AppDelegate.swift */; }; + E279FE3C25139E4700EC0EFA /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */; }; + E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3D25139E4700EC0EFA /* ViewController.swift */; }; + E279FE4125139E4700EC0EFA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE3F25139E4700EC0EFA /* Main.storyboard */; }; + E279FE4325139E4900EC0EFA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4225139E4900EC0EFA /* Assets.xcassets */; }; + E279FE4625139E4900EC0EFA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */; }; + E279FE4F25139EBA00EC0EFA /* THEOplayerSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */; }; + E279FE5025139EBA00EC0EFA /* THEOplayerSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + E279FE5125139EBA00EC0EFA /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + E279FE5025139EBA00EC0EFA /* THEOplayerSDK.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VuDRMIntegration.swift; sourceTree = ""; }; + D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UplynkDRMIntegration.swift; sourceTree = ""; }; + D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDRMIntegration.swift; sourceTree = ""; }; + E279FE3625139E4700EC0EFA /* ContentProtectionIntegration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ContentProtectionIntegration.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E279FE3925139E4700EC0EFA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + E279FE3D25139E4700EC0EFA /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + E279FE4025139E4700EC0EFA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + E279FE4225139E4900EC0EFA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + E279FE4525139E4900EC0EFA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + E279FE4725139E4900EC0EFA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = THEOplayerSDK.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E279FE3325139E4700EC0EFA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E279FE4F25139EBA00EC0EFA /* THEOplayerSDK.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + E279FE2D25139E4700EC0EFA = { + isa = PBXGroup; + children = ( + E279FE3825139E4700EC0EFA /* ContentProtectionIntegration */, + E279FE3725139E4700EC0EFA /* Products */, + E279FE4D25139EBA00EC0EFA /* Frameworks */, + ); + sourceTree = ""; + }; + E279FE3725139E4700EC0EFA /* Products */ = { + isa = PBXGroup; + children = ( + E279FE3625139E4700EC0EFA /* ContentProtectionIntegration.app */, + ); + name = Products; + sourceTree = ""; + }; + E279FE3825139E4700EC0EFA /* ContentProtectionIntegration */ = { + isa = PBXGroup; + children = ( + E279FE5225139F2000EC0EFA /* integration */, + E279FE3925139E4700EC0EFA /* AppDelegate.swift */, + E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */, + E279FE3D25139E4700EC0EFA /* ViewController.swift */, + E279FE3F25139E4700EC0EFA /* Main.storyboard */, + E279FE4225139E4900EC0EFA /* Assets.xcassets */, + E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */, + E279FE4725139E4900EC0EFA /* Info.plist */, + ); + path = ContentProtectionIntegration; + sourceTree = ""; + }; + E279FE4D25139EBA00EC0EFA /* Frameworks */ = { + isa = PBXGroup; + children = ( + E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + E279FE5225139F2000EC0EFA /* integration */ = { + isa = PBXGroup; + children = ( + D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */, + D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */, + D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */, + ); + path = integration; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + E279FE3525139E4700EC0EFA /* ContentProtectionIntegration */ = { + isa = PBXNativeTarget; + buildConfigurationList = E279FE4A25139E4900EC0EFA /* Build configuration list for PBXNativeTarget "ContentProtectionIntegration" */; + buildPhases = ( + E279FE3225139E4700EC0EFA /* Sources */, + E279FE3325139E4700EC0EFA /* Frameworks */, + E279FE3425139E4700EC0EFA /* Resources */, + E279FE5125139EBA00EC0EFA /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ContentProtectionIntegration; + productName = ContentProtectionIntegration; + productReference = E279FE3625139E4700EC0EFA /* ContentProtectionIntegration.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E279FE2E25139E4700EC0EFA /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1170; + LastUpgradeCheck = 1170; + ORGANIZATIONNAME = THEOplayer; + TargetAttributes = { + E279FE3525139E4700EC0EFA = { + CreatedOnToolsVersion = 11.7; + }; + }; + }; + buildConfigurationList = E279FE3125139E4700EC0EFA /* Build configuration list for PBXProject "ContentProtectionIntegration" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = E279FE2D25139E4700EC0EFA; + productRefGroup = E279FE3725139E4700EC0EFA /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E279FE3525139E4700EC0EFA /* ContentProtectionIntegration */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E279FE3425139E4700EC0EFA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E279FE4625139E4900EC0EFA /* LaunchScreen.storyboard in Resources */, + E279FE4325139E4900EC0EFA /* Assets.xcassets in Resources */, + E279FE4125139E4700EC0EFA /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E279FE3225139E4700EC0EFA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */, + E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */, + D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */, + E279FE3A25139E4700EC0EFA /* AppDelegate.swift in Sources */, + D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */, + E279FE3C25139E4700EC0EFA /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + E279FE3F25139E4700EC0EFA /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + E279FE4025139E4700EC0EFA /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + E279FE4525139E4900EC0EFA /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + E279FE4825139E4900EC0EFA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.7; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + E279FE4925139E4900EC0EFA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.7; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + E279FE4B25139E4900EC0EFA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + INFOPLIST_FILE = ContentProtectionIntegration/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.theoplayer.ContentProtectionIntegration; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + E279FE4C25139E4900EC0EFA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + INFOPLIST_FILE = ContentProtectionIntegration/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.theoplayer.ContentProtectionIntegration; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E279FE3125139E4700EC0EFA /* Build configuration list for PBXProject "ContentProtectionIntegration" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E279FE4825139E4900EC0EFA /* Debug */, + E279FE4925139E4900EC0EFA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E279FE4A25139E4900EC0EFA /* Build configuration list for PBXNativeTarget "ContentProtectionIntegration" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E279FE4B25139E4900EC0EFA /* Debug */, + E279FE4C25139E4900EC0EFA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = E279FE2E25139E4700EC0EFA /* Project object */; +} diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..185f3510 --- /dev/null +++ b/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/ContentProtectionIntegration/AppDelegate.swift b/ios/ContentProtectionIntegration/AppDelegate.swift new file mode 100644 index 00000000..097dd8ca --- /dev/null +++ b/ios/ContentProtectionIntegration/AppDelegate.swift @@ -0,0 +1,41 @@ +// +// AppDelegate.swift +// ContentProtectionIntegration +// +// Copyright © 2020 THEOplayer. All rights reserved. +// + +import UIKit +import THEOplayerSDK + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + + THEOplayer.registerContentProtectionIntegration(integrationId: VuDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: VuDRMIntegrationFactory()) + + THEOplayer.registerContentProtectionIntegration(integrationId: UplynkDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: UplynkDRMIntegrationFactory()) + + THEOplayer.registerContentProtectionIntegration(integrationId: AzureDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: AzureDRMIntegrationFactory()) + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/ios/ContentProtectionIntegration/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/ContentProtectionIntegration/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..9221b9bb --- /dev/null +++ b/ios/ContentProtectionIntegration/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/ContentProtectionIntegration/Assets.xcassets/Contents.json b/ios/ContentProtectionIntegration/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/ios/ContentProtectionIntegration/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/ContentProtectionIntegration/Base.lproj/LaunchScreen.storyboard b/ios/ContentProtectionIntegration/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..865e9329 --- /dev/null +++ b/ios/ContentProtectionIntegration/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/ContentProtectionIntegration/Base.lproj/Main.storyboard b/ios/ContentProtectionIntegration/Base.lproj/Main.storyboard new file mode 100644 index 00000000..25a76385 --- /dev/null +++ b/ios/ContentProtectionIntegration/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/ContentProtectionIntegration/Info.plist b/ios/ContentProtectionIntegration/Info.plist new file mode 100644 index 00000000..2a3483c0 --- /dev/null +++ b/ios/ContentProtectionIntegration/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ios/ContentProtectionIntegration/SceneDelegate.swift b/ios/ContentProtectionIntegration/SceneDelegate.swift new file mode 100644 index 00000000..a3e7038f --- /dev/null +++ b/ios/ContentProtectionIntegration/SceneDelegate.swift @@ -0,0 +1,52 @@ +// +// SceneDelegate.swift +// ContentProtectionIntegration +// +// Copyright © 2020 THEOplayer. All rights reserved. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/ios/ContentProtectionIntegration/ViewController.swift b/ios/ContentProtectionIntegration/ViewController.swift new file mode 100644 index 00000000..6a09efff --- /dev/null +++ b/ios/ContentProtectionIntegration/ViewController.swift @@ -0,0 +1,44 @@ +// +// ViewController.swift +// ContentProtectionIntegration +// +// Copyright © 2020 THEOplayer. All rights reserved. +// + +import UIKit +import THEOplayerSDK + +class ViewController: UIViewController { + var theoplayer: THEOplayer! + + override func viewDidLoad() { + super.viewDidLoad() + setupTheoPlayer() + self.theoplayer.source = sampleSource + } + + func setupTheoPlayer() { + var frame: CGRect = UIScreen.main.bounds + frame.origin.y = 0 + frame.size.height = frame.size.width * 9 / 16 + + self.theoplayer = THEOplayer() + self.theoplayer.frame = frame + self.theoplayer.addAsSubview(of: self.view) + } + + var sampleSource: SourceDescription { + return SourceDescription( + source: TypedSource( + src: "", + type: "application/x-mpegurl", + drm: FairPlayDRMConfiguration( + customIntegrationId: UplynkDRMIntegration.integrationID, + licenseAcquisitionURL: "", + certificateURL: "", + integrationParameters: [:] + ) + ) + ) + } +} diff --git a/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift new file mode 100644 index 00000000..81916761 --- /dev/null +++ b/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift @@ -0,0 +1,82 @@ +// +// AzureDRMIntegration.swift +// ContentProtectionIntegration +// +// Copyright © 2020 THEOplayer. All rights reserved. +// + +import Foundation +import THEOplayerSDK + +class AzureDRMIntegration: ContentProtectionIntegration { + static let integrationID = "customAzureDRM" + var configuration: DRMConfiguration + + var contentId: String? + + init(configuration: DRMConfiguration) { + self.configuration = configuration + } + + func extractFairplayContentId(skdUrl: String) -> String { + let components = skdUrl.components(separatedBy: "?") + let skd = components.last! + self.contentId = skd + return skd + } + + func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { + request.headers = [ + "Authorization": "Bearer \(self.getTokenFromDrmConfiguration())", + "Content-Type": "application/x-www-form-urlencoded" + ] + callback.request(request: request) + } + + func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { + callback.respond(certificate: response.body) + } + + func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { + guard let contentId = self.contentId else { + fatalError("contentID was nil.") + } + request.headers = [ + "Authorization": "Bearer \(self.getTokenFromDrmConfiguration())", + "Content-Type": "application/x-www-form-urlencoded" + ] + if let body64 = request.body?.base64EncodedString() { + let body = "spc=\(body64)&assetId=\(contentId)" + request.body = body.data(using: .utf8)! + callback.request(request: request) + } else { + fatalError("RequestBody was nil.") + } + } + + func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { + guard var licenseBody = String(data: response.body, encoding: .utf8) else { + fatalError("Could not create a string from the reponseBody provided.") + } + licenseBody = licenseBody.replacingOccurrences(of: "", with: "") + licenseBody = licenseBody.replacingOccurrences(of: "", with: "") + if let data = Data(base64Encoded: licenseBody) { + callback.respond(license: data) + } else { + fatalError("Could not create a Data Object from the responseBody provided.") + } + } + + private func getTokenFromDrmConfiguration() -> String { + guard let token = self.configuration.integrationParameters?["token"] as? String else { + fatalError("Could not find the token in the integrationParameters.") + } + return token + } +} + +class AzureDRMIntegrationFactory: ContentProtectionIntegrationFactory { + func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { + return AzureDRMIntegration(configuration: configuration) + } +} diff --git a/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift new file mode 100644 index 00000000..261dbe23 --- /dev/null +++ b/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift @@ -0,0 +1,82 @@ +// +// UplynkDRMIntegration.swift +// ContentProtectionIntegration +// +// Copyright © 2020 THEOplayer. All rights reserved. +// + +import Foundation +import THEOplayerSDK + +class UplynkDRMIntegration: ContentProtectionIntegration { + static let integrationID = "customUplynkDRM" + let UPLYNK_CONTENT_ID_PARAMETER_NAME = "b"; + var skdUrl: String? + + var configuration: DRMConfiguration + init(configuration: DRMConfiguration) { + self.configuration = configuration + } + + func extractFairplayContentId(skdUrl: String) -> String { + self.skdUrl = skdUrl + guard let urlComponents = URLComponents(string: skdUrl), + let queryItems = urlComponents.queryItems, + let queryItemSkd = queryItems.first(where: { $0.name == UPLYNK_CONTENT_ID_PARAMETER_NAME }), + let skd = queryItemSkd.value + else { + fatalError("Could Not parse the skd") + } + return skd + } + + func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { + callback.request(request: request) + } + + func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { + callback.respond(certificate: response.body) + } + + func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { + guard let skdUrl = self.skdUrl else { + fatalError("skdUrl was nil.") + } + let laURL = skdUrl.replacingOccurrences(of: "skd://", with: "https://") + request.url = laURL + var dict = [String: String]() + if let spc = request.body?.base64EncodedString() { + dict.updateValue(spc, forKey: "spc") + } + do { + request.body = try JSONEncoder().encode(dict) + callback.request(request: request) + } catch let error { + fatalError(error.localizedDescription) + } + } + + func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { + do { + let dto = try JSONDecoder().decode(UplynkDRMLicenseResponse.self, from: response.body) + guard let responseBody = Data(base64Encoded: dto.ckc) else { + fatalError("Could not Decode base64Encoded ckc") + } + response.body = responseBody + callback.respond(license: response.body) + } catch let err { + print(err) + callback.error(error: err) + } + } + + private struct UplynkDRMLicenseResponse: Codable { + var ckc: String + } +} + +class UplynkDRMIntegrationFactory: ContentProtectionIntegrationFactory { + func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { + return UplynkDRMIntegration(configuration: configuration) + } +} diff --git a/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift new file mode 100644 index 00000000..d1128208 --- /dev/null +++ b/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift @@ -0,0 +1,74 @@ +// +// VuDRMIntegration.swift +// ContentProtectionIntegration +// +// Copyright © 2020 THEOplayer. All rights reserved. +// + +import Foundation +import THEOplayerSDK + + +class VuDRMIntegration: ContentProtectionIntegration { + static let integrationID = "customVuDRM" + var contentID: String? + var configuration: DRMConfiguration + + init(configuration: DRMConfiguration) { + self.configuration = configuration + } + + func extractFairplayContentId(skdUrl: String) -> String { + let arr = skdUrl.components(separatedBy: "/") + let skd = arr[arr.count - 1] + self.contentID = skd + return skd + } + + func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { + request.headers.updateValue(self.getTokenFromDrmConfiguration(), forKey: "x-vudrm-token") + request.headers.updateValue("application/json", forKey: "Content-Type") + callback.request(request: request) + } + + func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { + callback.respond(certificate: response.body) + } + + func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { + guard let contentID = self.contentID else { + fatalError("contentID was nil.") + } + request.headers.updateValue("application/json", forKey: "content-type") + + var dict = [String: String]() + dict.updateValue(self.getTokenFromDrmConfiguration(), forKey: "token") + dict.updateValue(contentID, forKey: "contentId") + if let payload = request.body?.base64EncodedString() { + dict.updateValue(payload, forKey: "payload") + } + do { + request.body = try JSONEncoder().encode(dict) + callback.request(request: request) + } catch let error { + fatalError(error.localizedDescription) + } + } + + func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { + callback.respond(license: response.body) + } + + private func getTokenFromDrmConfiguration() -> String { + guard let token = self.configuration.integrationParameters?["token"] as? String else { + fatalError("Could not find the token in the integrationParameters") + } + return token + } +} + +class VuDRMIntegrationFactory: ContentProtectionIntegrationFactory { + func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { + return VuDRMIntegration(configuration: configuration) + } +} diff --git a/ios/README.md b/ios/README.md new file mode 100644 index 00000000..1cd0ba2a --- /dev/null +++ b/ios/README.md @@ -0,0 +1,131 @@ +## Getting started on iOS + +### Creating a new integration + +First create a custom implementation of [ContentProtectionIntegration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/ios/latest/External%20Content%20Protection%20integration%20API.html#/c:@M@THEOplayerSDK@objc(pl)ContentProtectionIntegration) +under `ios/ContentProtectionIntegration/integration`. +This object defines handler methods that allow altering license and certificate requests and responses as part of the +DRM flow. +All methods are optional. They can be omitted if the integration does not require additional action, in which case the +default implementation will be used. + +```swift +import Foundation +import THEOplayerSDK + +class MyCustomIntegration: ContentProtectionIntegration { + static let integrationID = "myCustomDRM" + + let configuration: DRMConfiguration + + init(configuration: DRMConfiguration) { + self.configuration = configuration + } + + func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { + callback.request(request: request) + } + + func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { + callback.respond(certificate: response.body) + } + + func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { + // request.headers = [ + // "x-token": self.getTokenFromDrmConfiguration(), + // ] + callback.request(request: request) + } + + func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { + callback.respond(license: response.body) + } + + func extractFairplayContentId(skdUrl: String) -> String { + return "" + } + + private func getTokenFromDrmConfiguration() -> String { + guard let token = self.configuration.integrationParameters?["token"] as? String else { + fatalError("Could not find the token in the integrationParameters.") + } + return token + } +} +``` + +Optional parameters needed for certificate or license requests, such as tokens, can be added to a +[DRMConfiguration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/ios/latest/Protocols/DRMConfiguration.html) +object that is passed when creating instances of the `MyCustomIntegration` class. +In the example, `MyCustomIntegration` adds a token from the configuration object as part of the headers +during a license request. + +Next, create a [ContentProtectionIntegrationFactory](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/ios/latest/External%20Content%20Protection%20integration%20API.html#/s:13THEOplayerSDK35ContentProtectionIntegrationFactoryP) for building MyCustomIntegration instances. +THEOplayer will use this factory in its DRM flow whenever it needs a ContentProtectionIntegration instance that +matches with the content protected source. How THEOplayer knows which factory to take will be determined in the +`registerContentProtectionIntegration` step next. + +```swift +class MyCustomIntegrationFactory: ContentProtectionIntegrationFactory { + func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { + return MyCustomIntegration(configuration: configuration) + } +} +``` + +An instance of `MyCustomIntegrationFactory` needs to be registered with THEOplayer's global instance in +[AppDelegate](/ios/ContentProtectionIntegration/AppDelegate.swift) +by specifying a unique `integrationId`, such as `"myCustomDRM"` in this example. + +```swift +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + THEOplayer.registerContentProtectionIntegration(integrationId: MyCustomIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: MyCustomIntegrationFactory()) + return true + } +} +``` + +When the player now loads a source with a `customIntegrationId` that matches the `integrationId` +passed during registration, an instance of `MyCustomIntegration` will be created and used in the DRM flow. + +Also, fill the source description in [ViewController](/ios/ContentProtectionIntegration/ViewController.swift), +which provides the manifest, certificate and license URLs along with any integration parameters. + +*Note: The Dictionary ```integrationParameters``` only supports Primitive-types and Codable values. all other types will ignored* +```swift +var sampleSource: SourceDescription { + return SourceDescription( + source: TypedSource( + src: "", + type: "application/x-mpegurl", + drm: FairPlayDRMConfiguration( + customIntegrationId: MyCustomIntegration.integrationID, + licenseAcquisitionURL: "", + certificateURL: "", + integrationParameters: [ + // optional integration parameters + // "token": "" + ] + ) + ) + ) +} +``` +Finally, build and run the app on an iOS device. + +### Available examples + +- Vualto VuDRM +- Microsoft Azure DRM +- Verizon Uplynk DRM + +### Testing an integration + +- Add your iOS THEOplayerSDK framework into the [/ios]() folder. +- Open the [project](/ios/ContentProtectionIntegration.xcodeproj) and + [add the framework as a dependency](https://docs.portal.theoplayer.com/getting-started/01-sdks/03-ios/00-getting-started.md#configure-theoplayer-sdk-framework) + to your project. +- Make sure to fill in the necessary fields `ViewController` for the content integration that will be tested, such as the manifest url and any integration parameters. +- Attach an iOS device, and finally build and run the project. diff --git a/web/.eslintrc.json b/web/.eslintrc.json new file mode 100644 index 00000000..46894b75 --- /dev/null +++ b/web/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": {} +} \ No newline at end of file diff --git a/web/README.md b/web/README.md new file mode 100644 index 00000000..52713e6e --- /dev/null +++ b/web/README.md @@ -0,0 +1,185 @@ +## Getting started on Web + +### Creating a new integration + +First create a custom implementation of [ContentProtectionIntegration](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.contentprotectionintegration.md) +under `src/integration/custom`. This object defines handler methods that allow altering license and certificate requests and responses as part of the +DRM flow. +All methods are optional. They can be omitted if the integration does not require additional action, in which case the +default implementation will be used. + +```ts +import { + ContentProtectionIntegration, + CertificateRequest, + MaybeAsync, + BufferSource, + CertificateResponse, + LicenseRequest, + LicenseResponse +} from 'THEOplayer'; +import { CustomDRMConfiguration } from './CustomDRMConfiguration'; + +export class CustomContentProtectionIntegration implements ContentProtectionIntegration { + constructor(private readonly contentProtectionConfiguration: CustomDRMConfiguration) { + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + throw new Error('not implemented yet'); + } + + onCertificateResponse(response: CertificateResponse): MaybeAsync { + throw new Error('not implemented yet'); + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + // const token = this.contentProtectionConfiguration.integrationParameters.token; + // request.headers = { + // ...request.headers, + // 'x-token': token + // }; + // return request; + throw new Error('not implemented yet'); + } + + onLicenseResponse(response: LicenseResponse): MaybeAsync { + throw new Error('not implemented yet'); + } + + extractFairplayContentId?(skdUrl: string): string { + throw new Error('not implemented yet'); + } +} +``` + +Optional parameters needed for certificate or license requests, such as tokens, can be added to a [DRMConfiguration](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.drmconfiguration.md/#drmconfiguration-interface) +object that is passed when creating instances of the `CustomContentProtectionIntegration` class. + +```ts +import { DRMConfiguration } from 'THEOplayer'; + +export interface CustomDRMConfiguration extends DRMConfiguration { + integrationParameters: { + token: string; + // any other parameters + }; +} +``` + +In the example, `CustomContentProtectionIntegration` adds a token from the configuration object as part of the headers +during a license request. + +Next, create a [ContentProtectionIntegrationFactory](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.contentprotectionintegrationfactory.md) +for building `CustomContentProtectionIntegration` instances. +THEOplayer will use this factory in its DRM flow whenever it needs a ContentProtectionIntegration instance that +matches with the content protected source. How THEOplayer knows which factory to take will be determined in the +`registerContentProtectionIntegration` step later on. + +```ts +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory, + DRMConfiguration +} from 'THEOplayer'; +import { CustomContentProtectionIntegration } from './CustomContentProtectionIntegration'; + +export class CustomContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: CustomDRMConfiguration): ContentProtectionIntegration { + return new CustomContentProtectionIntegration(configuration); + } +} +``` + +Before the factory can be used externally, it needs to be exported in the bundle's entry point `src/index.ts`. + +```ts +import { CustomContentProtectionIntegrationFactory } from './integration/custom/CustomContentProtectionIntegrationFactory'; + +export { + // ... + CustomContentProtectionIntegrationFactory +}; +``` + +The final step, after updating the integrations library with `npm build`, is creating a web page under `test/custom`. + +An instance of `CustomContentProtectionIntegrationFactory` needs to be +[registered](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.registercontentprotectionintegration.md/#registercontentprotectionintegration-function) +with THEOplayer by specifying a unique `integrationId`, such as `'custom_wv'` in this example. + +```ts +THEOplayer.registerContentProtectionIntegration( + 'custom_wv', + 'widevine', + new ContentProtectionIntegrations.CustomContentProtectionIntegrationFactory() +); +``` +The object `ContentProtectionIntegrations` is provided by the library `dist/bundle.js` and gives access to all exports from `src/index.ts`. + +When the player now loads a source with an `integration` parameter that matches the `integrationId` +passed during registration, an instance of `CustomContentProtectionIntegration` will be created and used in the DRM flow. + +```html + + + + + Custom Widevine Test + + + + + +
+ + + +``` + +### Available examples + +- Vualto VuDRM +- EZDRM (only for Fairplay, as Widevine and PlayReady can use the default implementation) +- Microsoft Azure DRM +- Axinom DRM + +### Testing an integration + +- Include a THEOplayer build in the root folder under `THEOplayer/`. It should contain the THEOplayer javascript +library `THEOplayer.js`, the declaration file `THEOplayer.d.ts` with all exported TypeScript types, and `ui.css`. +- Run `npm install && npm build` in the root folder to create the integrations library `bundle.js` under `dist/`. +- Start http-server in the root folder by running `npm run server`. +- Go to `localhost:8080/test/[integration you want to test]`. diff --git a/web/package-lock.json b/web/package-lock.json new file mode 100644 index 00000000..399518fa --- /dev/null +++ b/web/package-lock.json @@ -0,0 +1,2168 @@ +{ + "name": "drm-api-plugins", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", + "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@rollup/plugin-commonjs": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz", + "integrity": "sha512-8uAdikHqVyrT32w1zB9VhW6uGwGjhKgnDNP4pQJsjdnyF4FgCj6/bmv24c7v2CuKhq32CcyCwRzMPEElaKkn0w==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + } + }, + "@rollup/plugin-node-resolve": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz", + "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.17.0" + } + }, + "@rollup/plugin-typescript": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-5.0.2.tgz", + "integrity": "sha512-CkS028Itwjqm1uLbFVfpJgtVtnNvZ+og/m6UlNRR5wOOnNTWPcVQzOu5xGdEX+WWJxdvWIqUq2uR/RBt2ZipWg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.1", + "resolve": "^1.14.1" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "dependencies": { + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + } + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/lodash": { + "version": "4.14.161", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", + "integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA==", + "dev": true + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/node": { + "version": "14.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz", + "integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww==", + "dev": true + }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz", + "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.0.1", + "@typescript-eslint/scope-manager": "4.0.1", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz", + "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.0.1", + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/typescript-estree": "4.0.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz", + "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.0.1", + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/typescript-estree": "4.0.1", + "debug": "^4.1.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz", + "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/visitor-keys": "4.0.1" + } + }, + "@typescript-eslint/types": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz", + "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz", + "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/visitor-keys": "4.0.1", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz", + "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.0.1", + "eslint-visitor-keys": "^2.0.0" + } + }, + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "conditional-type-checks": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/conditional-type-checks/-/conditional-type-checks-1.0.5.tgz", + "integrity": "sha512-DkfkvmjXVe4ye4llJ1JADtO3dNvqqcQM08cA9BhNt9Oe8pyRW8X1CZyBg9Qst05bDV9BJM01KLmnFh78NcJgNg==" + }, + "confusing-browser-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dev": true, + "requires": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", + "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.1.3", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + } + } + }, + "eslint-config-airbnb-base": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", + "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.9", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", + "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + }, + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", + "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-server": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", + "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", + "dev": true, + "requires": { + "basic-auth": "^1.0.3", + "colors": "^1.4.0", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.18.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.25", + "secure-compare": "3.0.1", + "union": "~0.5.0" + } + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", + "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "has": "^1.0.3" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "dependencies": { + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + } + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.26.9", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.9.tgz", + "integrity": "sha512-XIiWYLayLqV+oY4S2Lub/shJq4uk/QQLwWToYCL4LjZbYHbFK3czea4UDVRUJu+zNmKmxq5Zb/OG7c5HSvH2TQ==", + "dev": true, + "requires": { + "fsevents": "~2.1.2" + } + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-node": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "tslib": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", + "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typescript": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", + "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", + "dev": true + }, + "union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "requires": { + "qs": "^6.4.0" + } + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 00000000..748cb039 --- /dev/null +++ b/web/package.json @@ -0,0 +1,42 @@ +{ + "name": "drm-api-plugins", + "version": "1.0.0", + "description": "**Edit a file, create a new file, and clone from Bitbucket in under 2 minutes**", + "main": "index.js", + "scripts": { + "server": "http-server", + "start": "ts-node src/index.ts", + "build": "rollup -c ./rollup.config.js", + "eslint": "eslint 'src/**/*.ts'" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@bitbucket.org/r8szq0vy/drm-api-plugin.git" + }, + "author": "", + "license": "ISC", + "homepage": "https://bitbucket.org/r8szq0vy/drm-api-plugin#readme", + "devDependencies": { + "@rollup/plugin-commonjs": "^15.0.0", + "@rollup/plugin-node-resolve": "^9.0.0", + "@rollup/plugin-typescript": "^5.0.2", + "@types/lodash": "^4.14.161", + "@types/node": "^14.6.3", + "@typescript-eslint/eslint-plugin": "^4.0.1", + "@typescript-eslint/parser": "^4.0.1", + "eslint": "^7.8.1", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-plugin-import": "^2.22.0", + "http-server": "^0.12.3", + "rollup": "^2.26.9", + "ts-node": "^9.0.0", + "tslib": "^2.0.1", + "typescript": "^4.0.2" + }, + "dependencies": { + "@types/long": "^4.0.1", + "conditional-type-checks": "^1.0.5", + "lodash": "^4.17.20", + "long": "^4.0.0" + } +} diff --git a/web/rollup.config.js b/web/rollup.config.js new file mode 100644 index 00000000..5f0678dd --- /dev/null +++ b/web/rollup.config.js @@ -0,0 +1,16 @@ +import commonJs from "@rollup/plugin-commonjs"; +import resolve from "@rollup/plugin-node-resolve"; +import typescript from "@rollup/plugin-typescript"; + +export default { + input: "src/index.ts", + output: { + file: "dist/bundle.js", + format: "iife", + exports: "auto", + name: "ContentProtectionIntegrations", + globals: { THEOplayer: 'THEOplayer' } + }, + external: ['THEOplayer'], + plugins: [resolve(), commonJs({ extensions: [".js", ".ts"] }), typescript()], +}; diff --git a/web/src/index.ts b/web/src/index.ts new file mode 100644 index 00000000..42ec6f34 --- /dev/null +++ b/web/src/index.ts @@ -0,0 +1,33 @@ +import { VudrmWidevineContentProtectionIntegrationFactory } from + './integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory'; +import { VudrmPlayReadyContentProtectionIntegrationFactory } from + './integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory'; +import { VudrmFairplayContentProtectionIntegrationFactory } from + './integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory'; +import { EzdrmFairplayContentProtectionIntegrationFactory } from + './integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory'; +import { AzureDrmWidevineContentProtectionIntegrationFactory } from + './integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory'; +import { AzureDrmPlayReadyContentProtectionIntegrationFactory } from + './integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory'; +import { AzureDrmFairplayContentProtectionIntegrationFactory } from + './integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory'; +import { AxinomDrmWidevineContentProtectionIntegrationFactory } from + './integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory'; +import { AxinomDrmPlayReadyContentProtectionIntegrationFactory } from + './integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory'; +import { AxinomDrmFairplayContentProtectionIntegrationFactory } from + './integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory'; + +export { + AxinomDrmWidevineContentProtectionIntegrationFactory, + AxinomDrmPlayReadyContentProtectionIntegrationFactory, + AxinomDrmFairplayContentProtectionIntegrationFactory, + VudrmWidevineContentProtectionIntegrationFactory, + VudrmPlayReadyContentProtectionIntegrationFactory, + VudrmFairplayContentProtectionIntegrationFactory, + EzdrmFairplayContentProtectionIntegrationFactory, + AzureDrmWidevineContentProtectionIntegrationFactory, + AzureDrmPlayReadyContentProtectionIntegrationFactory, + AzureDrmFairplayContentProtectionIntegrationFactory +}; diff --git a/web/src/integration/axinomdrm/AxinomDrmConfiguration.ts b/web/src/integration/axinomdrm/AxinomDrmConfiguration.ts new file mode 100644 index 00000000..db07326b --- /dev/null +++ b/web/src/integration/axinomdrm/AxinomDrmConfiguration.ts @@ -0,0 +1,30 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Axinom integration. + */ +export type AxinomIntegrationId = 'axinom'; + +/** + * Describes the configuration of the Axinom DRM integration. + */ +export interface AxinomDrmConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: AxinomIntegrationId; + + /** + * An object of key/value pairs which can be used to pass in specific parameters related to a source into a + * ContentProtectionIntegration. + */ + integrationParameters: { + /** + * The Axinom Authorization Token. + * + *
- Token that will be added to the headers of the license request. + */ + token: string; + } +} diff --git a/web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts b/web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts new file mode 100644 index 00000000..759dbd6d --- /dev/null +++ b/web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts @@ -0,0 +1,45 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource, + CertificateRequest +} from 'THEOplayer'; +import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; +import { isAxinomDrmDRMConfiguration } from "./AxinomDrmUtils"; + +export class AxinomDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: AxinomDrmConfiguration; + + constructor(configuration: AxinomDrmConfiguration) { + if (!isAxinomDrmDRMConfiguration(configuration)) { + throw new Error('The Axinom token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.certificateURL) { + throw new Error('The Axinom certificate url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; + request.headers = { + ...request.headers, + 'X-AxDRM-Message': this.contentProtectionConfiguration.integrationParameters.token + }; + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { + throw new Error('The Axinom Fairplay license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + 'X-AxDRM-Message': this.contentProtectionConfiguration.integrationParameters.token + }; + return request; + } +} diff --git a/web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts b/web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..024e162b --- /dev/null +++ b/web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { AxinomDrmConfiguration } from "./AxinomDrmConfiguration"; +import { AxinomDrmFairplayContentProtectionIntegration } from "./AxinomDrmFairplayContentProtectionIntegration"; + +export class AxinomDrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: AxinomDrmConfiguration): ContentProtectionIntegration { + return new AxinomDrmFairplayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts new file mode 100644 index 00000000..5cebbd25 --- /dev/null +++ b/web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts @@ -0,0 +1,32 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; +import { isAxinomDrmDRMConfiguration } from "./AxinomDrmUtils"; + +export class AxinomDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: AxinomDrmConfiguration; + + constructor(configuration: AxinomDrmConfiguration) { + if (!isAxinomDrmDRMConfiguration(configuration)) { + throw new Error('The Axinom token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.playready?.licenseAcquisitionURL) { + throw new Error('The PlayReady Axinom license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.playready?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + 'X-AxDRM-Message': this.contentProtectionConfiguration.integrationParameters.token + }; + return request; + } +} diff --git a/web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts b/web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..c293bc67 --- /dev/null +++ b/web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { AxinomDrmConfiguration } from "./AxinomDrmConfiguration"; +import { AxinomDrmPlayReadyContentProtectionIntegration } from "./AxinomDrmPlayReadyContentProtectionIntegration"; + +export class AxinomDrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: AxinomDrmConfiguration): ContentProtectionIntegration { + return new AxinomDrmPlayReadyContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/axinomdrm/AxinomDrmUtils.ts b/web/src/integration/axinomdrm/AxinomDrmUtils.ts new file mode 100644 index 00000000..feb8c58b --- /dev/null +++ b/web/src/integration/axinomdrm/AxinomDrmUtils.ts @@ -0,0 +1,5 @@ +import { AxinomDrmConfiguration } from "./AxinomDrmConfiguration"; + +export function isAxinomDrmDRMConfiguration(configuration: AxinomDrmConfiguration): boolean { + return configuration.integrationParameters.token !== undefined; +} diff --git a/web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts b/web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts new file mode 100644 index 00000000..1c635f01 --- /dev/null +++ b/web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts @@ -0,0 +1,32 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; +import { isAxinomDrmDRMConfiguration } from "./AxinomDrmUtils"; + +export class AxinomDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: AxinomDrmConfiguration; + + constructor(configuration: AxinomDrmConfiguration) { + if (!isAxinomDrmDRMConfiguration(configuration)) { + throw new Error('The Axinom token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { + throw new Error('The Widevine Axinom license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + 'X-AxDRM-Message': this.contentProtectionConfiguration.integrationParameters.token + }; + return request; + } +} diff --git a/web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..2e5a6b0c --- /dev/null +++ b/web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { AxinomDrmConfiguration } from "./AxinomDrmConfiguration"; +import { AxinomDrmWidevineContentProtectionIntegration } from "./AxinomDrmWidevineContentProtectionIntegration"; + +export class AxinomDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: AxinomDrmConfiguration): ContentProtectionIntegration { + return new AxinomDrmWidevineContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/azuredrm/AzureDrmConfiguration.ts b/web/src/integration/azuredrm/AzureDrmConfiguration.ts new file mode 100644 index 00000000..cb1fcd56 --- /dev/null +++ b/web/src/integration/azuredrm/AzureDrmConfiguration.ts @@ -0,0 +1,30 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Azure Media Services integration. + */ +export type AzureIntegrationID = 'azure'; + +/** + * Describes the configuration of the Azure Media Services DRM integration. + */ +export interface AzureDrmConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: AzureIntegrationID; + + /** + * An object of key/value pairs which can be used to pass in specific parameters related to a source into a + * ContentProtectionIntegration. + */ + integrationParameters: { + /** + * The Azure Media Services Authorization Token. + * + *
- This token will be used for the license request. + */ + token: string; + } +} diff --git a/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts b/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts new file mode 100644 index 00000000..a9890e9a --- /dev/null +++ b/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts @@ -0,0 +1,62 @@ +import { + BufferSource, + CertificateRequest, + ContentProtectionIntegration, + LicenseRequest, + LicenseResponse, + MaybeAsync, + utils +} from 'THEOplayer'; +import { AzureDrmConfiguration } from './AzureDrmConfiguration'; +import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; +import { extractContentId, unwrapCkc } from '../../utils/FairplayUtils'; + +export class AzureDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: AzureDrmConfiguration; + private contentId: string | undefined = undefined; + + constructor(configuration: AzureDrmConfiguration) { + if (!isAzureDrmDRMConfiguration(configuration)) { + throw new Error('The FairPlay AzureDRM token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.certificateURL) { + throw new Error('The FairPlay AzureDRM certificate url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; + request.headers = { + ...request.headers, + Authorization: `Bearer ${this.contentProtectionConfiguration.integrationParameters.token}` + }; + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { + throw new Error('The FairPlay AzureDRM license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + Authorization: `Bearer ${this.contentProtectionConfiguration.integrationParameters.token}` + }; + if (!this.contentId) { + throw new Error('The FairPlay AzureDRM content ID has not been correctly configured.'); + } + const licenseParameters = `spc=${encodeURIComponent(utils.base64.encode(new Uint8Array(request.body!)))}&assetId=${encodeURIComponent(this.contentId)}`; + request.body = new TextEncoder().encode(licenseParameters); + return request; + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + return unwrapCkc(response.body); + } + + extractFairplayContentId(skdUrl: string): string { + this.contentId = extractContentId(skdUrl); + return this.contentId; + } +} diff --git a/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts b/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..46360907 --- /dev/null +++ b/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { AzureDrmConfiguration } from './AzureDrmConfiguration'; +import { AzureDrmFairplayContentProtectionIntegration } from './AzureDrmFairplayContentProtectionIntegration'; + +export class AzureDrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: AzureDrmConfiguration): ContentProtectionIntegration { + return new AzureDrmFairplayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts new file mode 100644 index 00000000..d51215ab --- /dev/null +++ b/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts @@ -0,0 +1,32 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { AzureDrmConfiguration } from './AzureDrmConfiguration'; +import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; + +export class AzureDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: AzureDrmConfiguration; + + constructor(configuration: AzureDrmConfiguration) { + if(!isAzureDrmDRMConfiguration(configuration)){ + throw new Error('The PlayReady AzureDRM token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.playready?.licenseAcquisitionURL) { + throw new Error('The PlayReady AzureDRM license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.playready?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + Authorization: `Bearer ${this.contentProtectionConfiguration.integrationParameters.token}` + }; + return request; + } +} diff --git a/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts b/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..b2c75c32 --- /dev/null +++ b/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { AzureDrmConfiguration } from './AzureDrmConfiguration'; +import { AzureDrmPlayReadyContentProtectionIntegration } from './AzureDrmPlayReadyContentProtectionIntegration'; + +export class AzureDrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: AzureDrmConfiguration): ContentProtectionIntegration { + return new AzureDrmPlayReadyContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/azuredrm/AzureDrmUtils.ts b/web/src/integration/azuredrm/AzureDrmUtils.ts new file mode 100644 index 00000000..af4a3c42 --- /dev/null +++ b/web/src/integration/azuredrm/AzureDrmUtils.ts @@ -0,0 +1,5 @@ +import { AzureDrmConfiguration } from './AzureDrmConfiguration'; + +export function isAzureDrmDRMConfiguration(configuration: AzureDrmConfiguration): boolean { + return configuration.integrationParameters.token !== undefined; +} \ No newline at end of file diff --git a/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts b/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts new file mode 100644 index 00000000..4864c000 --- /dev/null +++ b/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts @@ -0,0 +1,32 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { AzureDrmConfiguration } from './AzureDrmConfiguration'; +import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; + +export class AzureDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: AzureDrmConfiguration; + + constructor(configuration: AzureDrmConfiguration) { + if(!isAzureDrmDRMConfiguration(configuration)){ + throw new Error('The Widevine AzureDRM token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { + throw new Error('The Widevine AzureDRM license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + Authorization: `Bearer ${this.contentProtectionConfiguration.integrationParameters.token}` + }; + return request; + } +} diff --git a/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..3b7163de --- /dev/null +++ b/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { AzureDrmConfiguration } from './AzureDrmConfiguration'; +import { AzureDrmWidevineContentProtectionIntegration } from './AzureDrmWidevineContentProtectionIntegration'; + +export class AzureDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: AzureDrmConfiguration): ContentProtectionIntegration { + return new AzureDrmWidevineContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/ezdrm/EzdrmDrmConfiguration.ts b/web/src/integration/ezdrm/EzdrmDrmConfiguration.ts new file mode 100644 index 00000000..0690891c --- /dev/null +++ b/web/src/integration/ezdrm/EzdrmDrmConfiguration.ts @@ -0,0 +1,27 @@ +import { DRMConfiguration } from "THEOplayer"; + +/** + * The identifier of the Ezdrm integration. + */ +export type EzdrmIntegrationID = 'ezdrm'; + +/** + * Describes the configuration of the Ezdrm DRM integration. + * + * ``` + * const drmConfiguration = { + * integration : 'ezdrm', + * fairplay: { + * certificateURL: 'yourEzdrmCertificateUrl', + * licenseAcquisitionURL: 'yourEzdrmLicenseAcquisitionURL' + * } + * } + * ``` + */ +export interface EzdrmDrmConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: EzdrmIntegrationID; +} diff --git a/web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts b/web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts new file mode 100644 index 00000000..59ed66e1 --- /dev/null +++ b/web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts @@ -0,0 +1,46 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource, CertificateRequest +} from 'THEOplayer'; +import { EzdrmDrmConfiguration } from './EzdrmDrmConfiguration'; +import { extractContentId } from "../../utils/FairplayUtils"; + +export class EzdrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { + + static readonly DEFAULT_CERTIFICATE_URL = 'insert default certificate url here'; + static readonly DEFAULT_LICENSE_URL = 'insert default license url here'; + + private readonly contentProtectionConfiguration: EzdrmDrmConfiguration; + private contentId: string | undefined = undefined; + + constructor(configuration: EzdrmDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + request.url = this.contentProtectionConfiguration.fairplay?.certificateURL ?? + EzdrmFairplayContentProtectionIntegration.DEFAULT_CERTIFICATE_URL; + request.headers = { + ...request.headers, + 'Content-Type': 'application/octet-stream', + }; + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? + EzdrmFairplayContentProtectionIntegration.DEFAULT_LICENSE_URL; + request.headers = { + ...request.headers, + 'Content-Type': 'application/octet-stream', + }; + return request; + } + + extractFairplayContentId(skdUrl: string): string { + this.contentId = extractContentId(skdUrl); + return this.contentId; + } +} diff --git a/web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts b/web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..cf196cfc --- /dev/null +++ b/web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { EzdrmDrmConfiguration } from './EzdrmDrmConfiguration'; +import { EzdrmFairplayContentProtectionIntegration } from "./EzdrmFairplayContentProtectionIntegration"; + +export class EzdrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: EzdrmDrmConfiguration): ContentProtectionIntegration { + return new EzdrmFairplayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/vudrm/VudrmDrmConfiguration.ts b/web/src/integration/vudrm/VudrmDrmConfiguration.ts new file mode 100644 index 00000000..ada1ef51 --- /dev/null +++ b/web/src/integration/vudrm/VudrmDrmConfiguration.ts @@ -0,0 +1,50 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Vudrm integration. + */ +export type VudrmIntegrationID = 'vudrm'; + +/** + * Describes the configuration of the Vudrm DRM integration. + * + * ``` + * var drmConfiguration = { + * integration : 'vudrm', + * playready: { + * licenseAcquisitionURL: 'yourVudrmPlayReadyLicenseAcquisitionURL' + * }, + * widevine: { + * licenseAcquisitionURL: 'yourVudrmWidevineLicenseAcquisitionURL' + * }, + * integrationParameters: { + * token: 'PEtleU9T...blhNTD4=', + * keyId: ''; + * } + * } + * ``` + */ +export interface VudrmDrmConfiguration extends DRMConfiguration { + /** + * The identifier of the DRM integration. + */ + integration: VudrmIntegrationID; + + /** + * An object of key/value pairs which can be used to pass in specific parameters related to a source into a + * ContentProtectionIntegration + */ + integrationParameters: { + /** + * The authentication token. + */ + token: string; + + /** + * The key id. + * + *
- Only mandatory for Widevine. + */ + keyId?: string; + }; +} diff --git a/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts b/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts new file mode 100644 index 00000000..e6bb8477 --- /dev/null +++ b/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts @@ -0,0 +1,58 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource, + CertificateRequest, utils +} from 'THEOplayer'; +import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; +import { isVudrmDRMConfiguration } from './VudrmUtil'; +import { extractContentId } from '../../utils/FairplayUtils'; + +export class VudrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { + + static readonly DEFAULT_CERTIFICATE_URL = 'https://fairplay-license.drm.technology/certificate'; + static readonly DEFAULT_LICENSE_URL = 'https://fairplay-license.drm.technology/license'; + + private readonly contentProtectionConfiguration: VudrmDrmConfiguration; + private contentId: string | undefined = undefined; + + constructor(configuration: VudrmDrmConfiguration) { + if (!isVudrmDRMConfiguration(configuration)) { + throw new Error('The FairPlay vuDRM token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + request.url = this.contentProtectionConfiguration.fairplay?.certificateURL ?? + VudrmFairplayContentProtectionIntegration.DEFAULT_CERTIFICATE_URL; + request.headers = { + ...request.headers, + 'Content-Type': 'application/json', + 'x-vudrm-token': this.contentProtectionConfiguration.integrationParameters.token + }; + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? + VudrmFairplayContentProtectionIntegration.DEFAULT_LICENSE_URL; + const licenseParameters = { + token: this.contentProtectionConfiguration.integrationParameters.token, + contentId: this.contentId, + payload: utils.base64.encode(new Uint8Array(request.body!)) + }; + request.headers = { + 'Content-Type': 'application/json', + 'x-vudrm-token': this.contentProtectionConfiguration.integrationParameters.token + } + request.body = new TextEncoder().encode((JSON.stringify(licenseParameters))); + return request; + } + + extractFairplayContentId(skdUrl: string): string { + this.contentId = extractContentId(skdUrl); + return this.contentId; + } +} diff --git a/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts b/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..f500eedc --- /dev/null +++ b/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; +import { VudrmFairplayContentProtectionIntegration } from "./VudrmFairplayContentProtectionIntegration"; + +export class VudrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: VudrmDrmConfiguration): ContentProtectionIntegration { + return new VudrmFairplayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts new file mode 100644 index 00000000..a73c9fe1 --- /dev/null +++ b/web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts @@ -0,0 +1,35 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { isVudrmDRMConfiguration } from './VudrmUtil'; +import { VudrmDrmConfiguration } from "./VudrmDrmConfiguration"; + +export class VudrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { + + static DEFAULT_LICENSE_URL = 'https://playready-license.drm.technology/rightsmanager.asmx'; + + private readonly contentProtectionConfiguration: VudrmDrmConfiguration; + + constructor(drmConfiguration: VudrmDrmConfiguration) { + if (!isVudrmDRMConfiguration(drmConfiguration)) { + throw new Error('The PlayReady vuDRM token has not been correctly configured.'); + } + this.contentProtectionConfiguration = drmConfiguration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + const url = new URL(this.contentProtectionConfiguration.playready?.licenseAcquisitionURL ?? + VudrmPlayReadyContentProtectionIntegration.DEFAULT_LICENSE_URL); + if (this.contentProtectionConfiguration.playready?.queryParameters) { + for (const key of Object.keys(this.contentProtectionConfiguration.playready.queryParameters)) { + url.searchParams.set(key, this.contentProtectionConfiguration.playready.queryParameters[key]); + } + } + url.searchParams.set('token', this.contentProtectionConfiguration.integrationParameters.token); + request.url = url.toString(); + return request; + } +} diff --git a/web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts b/web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..6d521cb5 --- /dev/null +++ b/web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import {VudrmPlayReadyContentProtectionIntegration} from './VudrmPlayReadyContentProtectionIntegration'; +import { VudrmDrmConfiguration } from "./VudrmDrmConfiguration"; + +export class VudrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: VudrmDrmConfiguration): ContentProtectionIntegration { + return new VudrmPlayReadyContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/vudrm/VudrmUtil.ts b/web/src/integration/vudrm/VudrmUtil.ts new file mode 100644 index 00000000..15cd0098 --- /dev/null +++ b/web/src/integration/vudrm/VudrmUtil.ts @@ -0,0 +1,5 @@ +import { VudrmDrmConfiguration } from "./VudrmDrmConfiguration"; + +export function isVudrmDRMConfiguration(configuration: VudrmDrmConfiguration): boolean { + return configuration.integrationParameters.token !== undefined; +} diff --git a/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts b/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts new file mode 100644 index 00000000..bee39656 --- /dev/null +++ b/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts @@ -0,0 +1,43 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource, CertificateRequest +} from 'THEOplayer'; +import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; +import { isVudrmDRMConfiguration } from './VudrmUtil'; + +export class VudrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { + + static readonly DEFAULT_LICENSE_URL = 'https://widevine-proxy.drm.technology/proxy'; + + private readonly contentProtectionConfiguration: VudrmDrmConfiguration; + + constructor(configuration: VudrmDrmConfiguration) { + if (!isVudrmDRMConfiguration(configuration)) { + throw new Error('The Widevine vuDRM token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + private wrapRequestBody(body: Uint8Array) { + const token = this.contentProtectionConfiguration.integrationParameters.token; + const drmInfo = Array.from(new Uint8Array(body)); + const kid = this.contentProtectionConfiguration.integrationParameters.keyId; + return new TextEncoder().encode((JSON.stringify({ token, drm_info: drmInfo, kid }))); + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL ?? + VudrmWidevineContentProtectionIntegration.DEFAULT_LICENSE_URL; + request.body = this.wrapRequestBody(request.body!); + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL ?? + VudrmWidevineContentProtectionIntegration.DEFAULT_LICENSE_URL; + request.body = this.wrapRequestBody(request.body!); + return request; + } +} diff --git a/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..4d720978 --- /dev/null +++ b/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { VudrmWidevineContentProtectionIntegration } from './VudrmWidevineContentProtectionIntegration'; +import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; + +export class VudrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: VudrmDrmConfiguration): ContentProtectionIntegration { + return new VudrmWidevineContentProtectionIntegration(configuration); + } +} diff --git a/web/src/utils/FairplayUtils.ts b/web/src/utils/FairplayUtils.ts new file mode 100644 index 00000000..d0f9d9c3 --- /dev/null +++ b/web/src/utils/FairplayUtils.ts @@ -0,0 +1,19 @@ +import { utils } from "THEOplayer"; + +export function extractContentId(skdUrl: string): string { + const questionMarkIndex = skdUrl.indexOf('?'); + if (questionMarkIndex >= 0) { + return skdUrl.substr(questionMarkIndex + 1); + } else { + const chunks = skdUrl.split('/'); + return chunks[chunks.length - 1]; + } +} + +export function unwrapCkc(data: Uint8Array): Uint8Array { + let license = new TextDecoder().decode(data).trim(); + if ('' === license.substr(0, 5) && '' === license.substr(-6)) { + license = license.slice(5, -6); + } + return utils.base64.decode(license); +} diff --git a/web/test/axinomdrm/fairplay.html b/web/test/axinomdrm/fairplay.html new file mode 100644 index 00000000..56fa021e --- /dev/null +++ b/web/test/axinomdrm/fairplay.html @@ -0,0 +1,48 @@ + + + + + Axinom Fairplay Test + + + + + +
+ + + diff --git a/web/test/axinomdrm/playready.html b/web/test/axinomdrm/playready.html new file mode 100644 index 00000000..d849d6de --- /dev/null +++ b/web/test/axinomdrm/playready.html @@ -0,0 +1,47 @@ + + + + + Axinom PlayReady Test + + + + + +
+ + + diff --git a/web/test/axinomdrm/widevine.html b/web/test/axinomdrm/widevine.html new file mode 100644 index 00000000..7ab72a4c --- /dev/null +++ b/web/test/axinomdrm/widevine.html @@ -0,0 +1,47 @@ + + + + + Axinom Widevine Test + + + + + +
+ + + diff --git a/web/test/azuredrm/fairplay.html b/web/test/azuredrm/fairplay.html new file mode 100644 index 00000000..4d3a8c7b --- /dev/null +++ b/web/test/azuredrm/fairplay.html @@ -0,0 +1,47 @@ + + + + + Azure drm FairPlay Test + + + + + +
+ + + diff --git a/web/test/azuredrm/playready.html b/web/test/azuredrm/playready.html new file mode 100644 index 00000000..31517105 --- /dev/null +++ b/web/test/azuredrm/playready.html @@ -0,0 +1,46 @@ + + + + + Azure drm PlayReady Test + + + + + +
+ + + diff --git a/web/test/azuredrm/widevine.html b/web/test/azuredrm/widevine.html new file mode 100644 index 00000000..ca0bb2e2 --- /dev/null +++ b/web/test/azuredrm/widevine.html @@ -0,0 +1,46 @@ + + + + + Azure drm Widevine Test + + + + + +
+ + + diff --git a/web/test/ezdrm/fairplay.html b/web/test/ezdrm/fairplay.html new file mode 100644 index 00000000..48ebc749 --- /dev/null +++ b/web/test/ezdrm/fairplay.html @@ -0,0 +1,44 @@ + + + + + Ezdrm Fairplay Test + + + + + +
+ + + diff --git a/web/test/vudrm/fairplay.html b/web/test/vudrm/fairplay.html new file mode 100644 index 00000000..436baba2 --- /dev/null +++ b/web/test/vudrm/fairplay.html @@ -0,0 +1,47 @@ + + + + + Vudrm Fairplay Test + + + + + +
+ + + diff --git a/web/test/vudrm/playready.html b/web/test/vudrm/playready.html new file mode 100644 index 00000000..c79dda4e --- /dev/null +++ b/web/test/vudrm/playready.html @@ -0,0 +1,46 @@ + + + + + Vudrm PlayReady Test + + + + + +
+ + + diff --git a/web/test/vudrm/widevine.html b/web/test/vudrm/widevine.html new file mode 100644 index 00000000..a4d65d0e --- /dev/null +++ b/web/test/vudrm/widevine.html @@ -0,0 +1,47 @@ + + + + + Vudrm Widevine Test + + + + + +
+ + + diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 00000000..c0f4632a --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,69 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + "paths": {"THEOplayer": ["./THEOplayer/THEOplayer"]}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} From 7fbe085372a393359b9baee4f1ab3dfa893ee427 Mon Sep 17 00:00:00 2001 From: Mohamed Abida Date: Mon, 11 Jan 2021 10:52:22 +0100 Subject: [PATCH 03/85] add `EzdrmDRMIntegration`, an external Content Protection Integration for Ezdrm --- .../project.pbxproj | 4 ++ .../AppDelegate.swift | 2 + .../integration/EzdrmDRMIntegration.swift | 57 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj index e45d580f..6eba54c6 100644 --- a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj +++ b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */; }; D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */; }; D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */; }; + D99BC03525A4679200AE24B0 /* EzdrmDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */; }; E279FE3A25139E4700EC0EFA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3925139E4700EC0EFA /* AppDelegate.swift */; }; E279FE3C25139E4700EC0EFA /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */; }; E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3D25139E4700EC0EFA /* ViewController.swift */; }; @@ -38,6 +39,7 @@ D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VuDRMIntegration.swift; sourceTree = ""; }; D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UplynkDRMIntegration.swift; sourceTree = ""; }; D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDRMIntegration.swift; sourceTree = ""; }; + D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EzdrmDRMIntegration.swift; sourceTree = ""; }; E279FE3625139E4700EC0EFA /* ContentProtectionIntegration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ContentProtectionIntegration.app; sourceTree = BUILT_PRODUCTS_DIR; }; E279FE3925139E4700EC0EFA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -107,6 +109,7 @@ D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */, D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */, D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */, + D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */, ); path = integration; sourceTree = ""; @@ -183,6 +186,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D99BC03525A4679200AE24B0 /* EzdrmDRMIntegration.swift in Sources */, D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */, E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */, D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */, diff --git a/ios/ContentProtectionIntegration/AppDelegate.swift b/ios/ContentProtectionIntegration/AppDelegate.swift index 097dd8ca..cbb5788e 100644 --- a/ios/ContentProtectionIntegration/AppDelegate.swift +++ b/ios/ContentProtectionIntegration/AppDelegate.swift @@ -19,6 +19,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { THEOplayer.registerContentProtectionIntegration(integrationId: UplynkDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: UplynkDRMIntegrationFactory()) THEOplayer.registerContentProtectionIntegration(integrationId: AzureDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: AzureDRMIntegrationFactory()) + + THEOplayer.registerContentProtectionIntegration(integrationId: EzdrmDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: EzdrmDRMIntegrationFactory()) return true } diff --git a/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift new file mode 100644 index 00000000..0190dca8 --- /dev/null +++ b/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift @@ -0,0 +1,57 @@ +// +// EzdrmDRMIntegration.swift +// ContentProtectionIntegration +// +// Copyright © 2021 THEOplayer. All rights reserved. +// + +import Foundation +import THEOplayerSDK + +class EzdrmDRMIntegration: ContentProtectionIntegration { + static let integrationID = "EzdrmDRMIntegration" + + func extractFairplayContentId(skdUrl: String) -> String { + let arr = skdUrl.components(separatedBy: ";") + let skd = arr[arr.count - 1] + return skd + } + + func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { + callback.request(request: request) + } + + func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { + callback.respond(certificate: response.body) + } + + func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { + // Setting the `request.url` to a valid dummy URL is necessary to bypass a known limitation. + // Please note: As of THEOplayerSDK v2.81.0, you could just use the method `LicenseRequestCallback.respond(:data)` inside `onLicenseRequest` without the need to use `onLicenseResponse`. + request.url = "https://httpstatuses.com/200" + callback.request(request: request) + } + + func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { + guard let serviceUrl = URL(string: response.request.url) else { + fatalError("'\(response.request.url)' is not a valid URL") + } + var request = URLRequest(url: serviceUrl) + request.httpMethod = "POST" + request.httpBody = response.request.body + request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type") + URLSession.shared.dataTask(with: request) { (data, response, error) in + if let data = data { + callback.respond(license: data) + } else { + callback.error(error: error!) + } + }.resume() + } +} + +class EzdrmDRMIntegrationFactory: ContentProtectionIntegrationFactory { + func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { + return EzdrmDRMIntegration() + } +} From 84a7f2ac470c5c4e08303b3fd52bb8a333533118 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Mon, 11 Jan 2021 14:08:29 +0100 Subject: [PATCH 04/85] Add activity lifecycle methods --- .../PlayerActivity.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java index eb0e8727..06d3a3be 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java @@ -11,6 +11,8 @@ public class PlayerActivity extends AppCompatActivity { public final static String EXTRA_SOURCENAME = "sourceName"; + private THEOplayerView playerView; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -19,10 +21,34 @@ protected void onCreate(Bundle savedInstanceState) { Bundle extras = getIntent().getExtras(); if (extras != null) { String sourceName = extras.getString(EXTRA_SOURCENAME); - THEOplayerView playerView = findViewById(R.id.theoplayer); + playerView = findViewById(R.id.theoplayer); SourceDescription sourceDescription = SourceManager.getInstance(this).getSource(sourceName); playerView.getPlayer().setSource(sourceDescription); playerView.getPlayer().play(); } } + + @Override + protected void onPause() { + super.onPause(); + if (playerView != null) { + playerView.onPause(); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (playerView != null) { + playerView.onResume(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (playerView != null) { + playerView.onDestroy(); + } + } } From a94bd8ea62f2d23ecb6fc9b4b86131637b477824 Mon Sep 17 00:00:00 2001 From: Mohamed Abida <> Date: Fri, 5 Feb 2021 09:25:35 +0100 Subject: [PATCH 05/85] Update EzdrmDRMIntegration for THEOplayer v2.81.0 --- .../integration/EzdrmDRMIntegration.swift | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift index 0190dca8..ca827fe9 100644 --- a/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift +++ b/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift @@ -26,21 +26,21 @@ class EzdrmDRMIntegration: ContentProtectionIntegration { } func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - // Setting the `request.url` to a valid dummy URL is necessary to bypass a known limitation. - // Please note: As of THEOplayerSDK v2.81.0, you could just use the method `LicenseRequestCallback.respond(:data)` inside `onLicenseRequest` without the need to use `onLicenseResponse`. - request.url = "https://httpstatuses.com/200" - callback.request(request: request) - } - - func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - guard let serviceUrl = URL(string: response.request.url) else { - fatalError("'\(response.request.url)' is not a valid URL") - } - var request = URLRequest(url: serviceUrl) - request.httpMethod = "POST" - request.httpBody = response.request.body - request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type") - URLSession.shared.dataTask(with: request) { (data, response, error) in + // `LicenseRequestCallback.respond(:data)` - `LicenseRequestCallback.error(:error)` - `CertificateRequestCallback.respond(:data)` and + // `CertificateRequestCallback.error(:error)` are available as of v2.81.0, so in THEOplayer versions < 2.81.0, setting the `request.url` to a valid + // dummy URL is necessary to bypass a known limitation. + // - step: 1 + // in `onLicenseRequest(:request:callback)` + // request.url = "https://httpstatuses.com/200" + // callback.request(request: request) + // - step: 2 + // in `onLicenseResponse(:response:callback)` you need to download the actual license + // and give it back to THEOplayer using `LicenseResponseCallback.respond(:data)` + var urlRequest = URLRequest(url: URL(string: request.url)!) + urlRequest.httpMethod = "POST" + urlRequest.httpBody = request.body + urlRequest.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type") + URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in if let data = data { callback.respond(license: data) } else { From 518889fe83ca3991d2808df3e5dbbd57d2a0b273 Mon Sep 17 00:00:00 2001 From: Savdeep Gandhi Date: Fri, 5 Mar 2021 12:21:07 +0100 Subject: [PATCH 06/85] Added EZ DRM Configuration --- ios/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/README.md b/ios/README.md index 1cd0ba2a..faf3c49f 100644 --- a/ios/README.md +++ b/ios/README.md @@ -120,6 +120,7 @@ Finally, build and run the app on an iOS device. - Vualto VuDRM - Microsoft Azure DRM - Verizon Uplynk DRM +- EZ DRM ### Testing an integration From 74564d5adf3e0050f80de5b4863d3a16b6cc9dbd Mon Sep 17 00:00:00 2001 From: Thijs Date: Tue, 16 Mar 2021 14:53:18 -0400 Subject: [PATCH 07/85] Feature/irdeto control (#1) Add Irdeto Control FairPlay connector, and template examples for FairPlay, Widevine and PlayReady. * Add initial Irdeto Control FairPlay connector * Add support for automatic detection of keyId of contentId to use in the license acquisition URL The Irdeto Control FairPlay connector uses the following order to determine the keyId and contentId: 1) Check if keyId and/or contentId are in the predefined license acquisition URL. If present: use those values. If not present: see #2. 2) Check if keyId and/or contentId are in the integration parameters. If present: use those values. If not present: see #3. 3) Check if keyId and/or contentId are in the HLS manifest. If present: use those values. If not present: don't use keyId and/or contentId in the license acquisition URL Add support for applicationId as an integration parameter. This value is used if there isn't already an applicationId query parameter in the certificateURL. * Fix typo in comments Rename "Key ID" to "Application ID" in the description of the optional applicationId property. * Add Irdeto Control Widevine and PlayReady examples. Add example to add Authorization header. Co-authored-by: thijsl --- web/src/index.ts | 5 +- .../IrdetoControlConfiguration.ts | 38 ++++++++ ...rolFairplayContentProtectionIntegration.ts | 93 +++++++++++++++++++ ...playContentProtectionIntegrationFactory.ts | 12 +++ web/test/irdetocontrol/fairplay.html | 57 ++++++++++++ web/test/irdetocontrol/playready.html | 40 ++++++++ web/test/irdetocontrol/widevine.html | 40 ++++++++ 7 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 web/src/integration/irdetocontrol/IrdetoControlConfiguration.ts create mode 100644 web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts create mode 100644 web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts create mode 100644 web/test/irdetocontrol/fairplay.html create mode 100644 web/test/irdetocontrol/playready.html create mode 100644 web/test/irdetocontrol/widevine.html diff --git a/web/src/index.ts b/web/src/index.ts index 42ec6f34..dfbd9624 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -18,6 +18,8 @@ import { AxinomDrmPlayReadyContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory'; import { AxinomDrmFairplayContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory'; +import { IrdetoControlFairplayContentProtectionIntegrationFactory} from + './integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory'; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -29,5 +31,6 @@ export { EzdrmFairplayContentProtectionIntegrationFactory, AzureDrmWidevineContentProtectionIntegrationFactory, AzureDrmPlayReadyContentProtectionIntegrationFactory, - AzureDrmFairplayContentProtectionIntegrationFactory + AzureDrmFairplayContentProtectionIntegrationFactory, + IrdetoControlFairplayContentProtectionIntegrationFactory }; diff --git a/web/src/integration/irdetocontrol/IrdetoControlConfiguration.ts b/web/src/integration/irdetocontrol/IrdetoControlConfiguration.ts new file mode 100644 index 00000000..43d6ce94 --- /dev/null +++ b/web/src/integration/irdetocontrol/IrdetoControlConfiguration.ts @@ -0,0 +1,38 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Irdeto Control integration. + */ +export type IrdetoControlIntegrationID = 'irdetocontrol'; + +/** + * Describes the configuration of the Irdeto Control DRM integration. + */ +export interface IrdetoControlConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: IrdetoControlIntegrationID; + + integrationParameters?: { + /** + * The Irdeto Control Content ID. + * + *
- This Content ID will be used for the license request. + */ + contentId?: string; + /** + * The Irdeto Control Key ID. + * + *
- This Key ID will be used for the license request. + */ + keyId?: string; + /** + * The Irdeto Control Application ID. + * + *
- This Application ID will be used for the certificate request. + */ + applicationId?: string; + } +} diff --git a/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts b/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts new file mode 100644 index 00000000..92d7200f --- /dev/null +++ b/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts @@ -0,0 +1,93 @@ +import { + BufferSource, + ContentProtectionIntegration, + CertificateRequest, + LicenseRequest, + LicenseResponse, + MaybeAsync +} from 'THEOplayer'; +import { IrdetoControlConfiguration } from './IrdetoControlConfiguration'; + +export class IrdetoControlFairplayContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: IrdetoControlConfiguration; + private contentId: string | undefined = undefined; + private keyId: string | undefined = undefined; + + constructor(configuration: IrdetoControlConfiguration) { + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.certificateURL) { + throw new Error('The FairPlay Irdeto Control certificate url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; + if (!this.hasQueryParameter(request.url, "applicationId") && this.contentProtectionConfiguration.integrationParameters?.applicationId) { + request.url = this.appendQueryParameter(request.url, "applicationId", this.contentProtectionConfiguration.integrationParameters?.applicationId); + } + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { + throw new Error('The FairPlay Irdeto DRM license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; + if (!this.hasQueryParameter(request.url, "contentId")) { + if (this.contentProtectionConfiguration.integrationParameters?.contentId) { + request.url = this.appendQueryParameter(request.url, "contentId", this.contentProtectionConfiguration.integrationParameters?.contentId); + } else if (this.contentId) { + request.url = this.appendQueryParameter(request.url, "contentId", this.contentId); + } + } + if (!this.hasQueryParameter(request.url, "keyId")) { + if (this.contentProtectionConfiguration.integrationParameters?.keyId) { + request.url = this.appendQueryParameter(request.url, "keyId", this.contentProtectionConfiguration.integrationParameters?.keyId); + } else if (this.keyId) { + request.url = this.appendQueryParameter(request.url, "keyId", this.keyId); + } + } + return request; + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + return response.body; + } + + extractFairplayContentId(skdUrl: string): string { + let parameters = skdUrl.split("?")[1].split("&"); + for (let i = 0; i < parameters.length; i++) { + const pair = parameters[i].split("="); + if (pair[0] == "contentId") { + this.contentId = pair[1]; + } else if (pair[0] == "keyId") { + this.keyId = pair[1]; + } + } + return skdUrl; + } + + hasQueryParameter(url : string, parameter: string) : Boolean { + const queryParameters = url.split("?"); + if (!queryParameters || !queryParameters[1]) { + return false; + } + const pairs = queryParameters[1].split("&"); + for (let i = 0; i < pairs.length; i++) { + const pair = pairs[i].split("="); + if (pair[0] == parameter) { + return true; + } + } + return false; + } + + appendQueryParameter(url: string, key: string, value: string | undefined) : string { + const queryParameters = url.split("?"); + if (!queryParameters || !queryParameters[1]) { + return (url + "?" + key + "=" + value); + } else { + return (url + "&" + key + "=" + value); + } + } +} diff --git a/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts b/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..624b2e7e --- /dev/null +++ b/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { IrdetoControlConfiguration } from './IrdetoControlConfiguration'; +import { IrdetoControlFairplayContentProtectionIntegration } from './IrdetoControlFairplayContentProtectionIntegration'; + +export class IrdetoControlFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: IrdetoControlConfiguration): ContentProtectionIntegration { + return new IrdetoControlFairplayContentProtectionIntegration(configuration); + } +} diff --git a/web/test/irdetocontrol/fairplay.html b/web/test/irdetocontrol/fairplay.html new file mode 100644 index 00000000..1092a724 --- /dev/null +++ b/web/test/irdetocontrol/fairplay.html @@ -0,0 +1,57 @@ + + + + + Irdeto Control FairPlay Test + + + + + +
+ + + diff --git a/web/test/irdetocontrol/playready.html b/web/test/irdetocontrol/playready.html new file mode 100644 index 00000000..cabeab56 --- /dev/null +++ b/web/test/irdetocontrol/playready.html @@ -0,0 +1,40 @@ + + + + + Irdeto Control PlayReady Test + + + + +
+ + + diff --git a/web/test/irdetocontrol/widevine.html b/web/test/irdetocontrol/widevine.html new file mode 100644 index 00000000..58aaef08 --- /dev/null +++ b/web/test/irdetocontrol/widevine.html @@ -0,0 +1,40 @@ + + + + + Irdeto Control Widevine Test + + + + +
+ + + From 579ed726768afafe135372c1d1d709d9097fc59a Mon Sep 17 00:00:00 2001 From: Thijs Date: Wed, 17 Mar 2021 12:45:27 -0400 Subject: [PATCH 08/85] Add initial Nagra DRM example (#2) --- web/README.md | 2 + web/src/index.ts | 11 +- .../nagradrm/NagraDrmConfiguration.ts | 30 +++++ ...DrmFairPlayContentProtectionIntegration.ts | 78 +++++++++++ ...PlayContentProtectionIntegrationFactory.ts | 13 ++ ...rmPlayReadyContentProtectionIntegration.ts | 50 +++++++ ...eadyContentProtectionIntegrationFactory.ts | 13 ++ web/src/integration/nagradrm/NagraDrmUtils.ts | 7 + ...DrmWidevineContentProtectionIntegration.ts | 50 +++++++ ...vineContentProtectionIntegrationFactory.ts | 13 ++ web/test/nagradrm/fairplay.html | 114 ++++++++++++++++ web/test/nagradrm/playready.html | 123 ++++++++++++++++++ web/test/nagradrm/style.css | 16 +++ web/test/nagradrm/widevine.html | 123 ++++++++++++++++++ 14 files changed, 642 insertions(+), 1 deletion(-) create mode 100644 web/src/integration/nagradrm/NagraDrmConfiguration.ts create mode 100644 web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts create mode 100644 web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts create mode 100644 web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/nagradrm/NagraDrmUtils.ts create mode 100644 web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts create mode 100644 web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts create mode 100644 web/test/nagradrm/fairplay.html create mode 100644 web/test/nagradrm/playready.html create mode 100644 web/test/nagradrm/style.css create mode 100644 web/test/nagradrm/widevine.html diff --git a/web/README.md b/web/README.md index 52713e6e..160ecc04 100644 --- a/web/README.md +++ b/web/README.md @@ -175,6 +175,8 @@ passed during registration, an instance of `CustomContentProtectionIntegration` - EZDRM (only for Fairplay, as Widevine and PlayReady can use the default implementation) - Microsoft Azure DRM - Axinom DRM +- Irdeto Control +- Nagra DRM ### Testing an integration diff --git a/web/src/index.ts b/web/src/index.ts index dfbd9624..f5accdb9 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -20,6 +20,12 @@ import { AxinomDrmFairplayContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory'; import { IrdetoControlFairplayContentProtectionIntegrationFactory} from './integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory'; +import { NagraDrmWidevineContentProtectionIntegrationFactory } from + './integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory'; +import { NagraDrmPlayReadyContentProtectionIntegrationFactory } from + './integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory'; +import { NagraDrmFairPlayContentProtectionIntegrationFactory } from + './integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory'; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -32,5 +38,8 @@ export { AzureDrmWidevineContentProtectionIntegrationFactory, AzureDrmPlayReadyContentProtectionIntegrationFactory, AzureDrmFairplayContentProtectionIntegrationFactory, - IrdetoControlFairplayContentProtectionIntegrationFactory + IrdetoControlFairplayContentProtectionIntegrationFactory, + NagraDrmWidevineContentProtectionIntegrationFactory, + NagraDrmPlayReadyContentProtectionIntegrationFactory, + NagraDrmFairPlayContentProtectionIntegrationFactory }; diff --git a/web/src/integration/nagradrm/NagraDrmConfiguration.ts b/web/src/integration/nagradrm/NagraDrmConfiguration.ts new file mode 100644 index 00000000..e3b99bd6 --- /dev/null +++ b/web/src/integration/nagradrm/NagraDrmConfiguration.ts @@ -0,0 +1,30 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Nagra integration. + */ +export type NagraIntegrationId = "axinom"; + +/** + * Describes the configuration of the Axinom DRM integration. + */ +export interface NagraDrmConfiguration extends DRMConfiguration { + /** + * The identifier of the DRM integration. + */ + integration: NagraIntegrationId; + + /** + * An object of key/value pairs which can be used to pass in specific parameters related to a source into a + * ContentProtectionIntegration. + */ + integrationParameters: { + /** + * The Axinom Authorization Token. + * + *
- Token that will be added to the headers of the license request. + */ + token: string; + tenantId: string; + }; +} diff --git a/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts new file mode 100644 index 00000000..210ff5f5 --- /dev/null +++ b/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts @@ -0,0 +1,78 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + LicenseResponse, + MaybeAsync, + BufferSource, + CertificateRequest +} from 'THEOplayer'; +import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; +import { isNagraDrmDRMConfiguration } from "./NagraDrmUtils"; + +export class NagraDrmFairPlayContentProtectionIntegration + implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: NagraDrmConfiguration; + private contentId: string | undefined = undefined; + + constructor(configuration: NagraDrmConfiguration) { + if (!isNagraDrmDRMConfiguration(configuration)) { + throw new Error("The Nagra token has not been correctly configured."); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest( + request: CertificateRequest + ): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.certificateURL) { + throw new Error( + "The Nagra certificate url has not been correctly configured." + ); + } + request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; + request.headers = { + ...request.headers, + "nv-authorizations": this.contentProtectionConfiguration + .integrationParameters.token, + "content-type": "application/octet-stream" + }; + return request; + } + + onLicenseRequest( + request: LicenseRequest + ): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { + throw new Error( + "The Nagra Fairplay license url has not been correctly configured." + ); + } + request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + "nv-authorizations": this.contentProtectionConfiguration + .integrationParameters.token, + "nv-tenant-id": this.contentProtectionConfiguration.integrationParameters + .tenantId, + "content-type": "application/octet-stream" + }; + return request; + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + var responseAsText = new TextDecoder().decode(response.body); + var responseCkcMessage = JSON.parse(responseAsText)["CkcMessage"]; + var raw = window.atob(responseCkcMessage); + var rawLength = raw.length; + var array = new Uint8Array(new ArrayBuffer(rawLength)); + for (var i = 0; i < rawLength; i++) { + array[i] = raw.charCodeAt(i); + } + return array; + } + + extractFairplayContentId(skdUrl: string): string { + this.contentId = window.atob(skdUrl.split("skd://")[1].split("?")[0]); + return this.contentId; + } +} diff --git a/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts b/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..f390504f --- /dev/null +++ b/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts @@ -0,0 +1,13 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; +import { NagraDrmFairPlayContentProtectionIntegration } from "./NagraDrmFairPlayContentProtectionIntegration"; + +export class NagraDrmFairPlayContentProtectionIntegrationFactory + implements ContentProtectionIntegrationFactory { + build(configuration: NagraDrmConfiguration): ContentProtectionIntegration { + return new NagraDrmFairPlayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts new file mode 100644 index 00000000..b8a3d5c3 --- /dev/null +++ b/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts @@ -0,0 +1,50 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + CertificateRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; +import { isNagraDrmDRMConfiguration } from "./NagraDrmUtils"; + +export class NagraDrmPlayReadyContentProtectionIntegration + implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: NagraDrmConfiguration; + + constructor(configuration: NagraDrmConfiguration) { + if (!isNagraDrmDRMConfiguration(configuration)) { + throw new Error("The Axinom token has not been correctly configured."); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest( + request: CertificateRequest + ): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + "nv-authorizations": this.contentProtectionConfiguration + .integrationParameters.token, + "Content-Type": "application/octet-stream" + }; + return request; + } + + onLicenseRequest( + request: LicenseRequest + ): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.playready?.licenseAcquisitionURL) { + throw new Error( + "The PlayReady Axinom license url has not been correctly configured." + ); + } + request.url = this.contentProtectionConfiguration.playready?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + "X-AxDRM-Message": this.contentProtectionConfiguration + .integrationParameters.token + }; + return request; + } +} diff --git a/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts b/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..ebd09852 --- /dev/null +++ b/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -0,0 +1,13 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; +import { NagraDrmPlayReadyContentProtectionIntegration } from "./NagraDrmPlayReadyContentProtectionIntegration"; + +export class NagraDrmPlayReadyContentProtectionIntegrationFactory + implements ContentProtectionIntegrationFactory { + build(configuration: NagraDrmConfiguration): ContentProtectionIntegration { + return new NagraDrmPlayReadyContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/nagradrm/NagraDrmUtils.ts b/web/src/integration/nagradrm/NagraDrmUtils.ts new file mode 100644 index 00000000..255fbae9 --- /dev/null +++ b/web/src/integration/nagradrm/NagraDrmUtils.ts @@ -0,0 +1,7 @@ +import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; + +export function isNagraDrmDRMConfiguration( + configuration: NagraDrmConfiguration +): boolean { + return configuration.integrationParameters.token !== undefined; +} diff --git a/web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts b/web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts new file mode 100644 index 00000000..b050e285 --- /dev/null +++ b/web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts @@ -0,0 +1,50 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + CertificateRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; +import { isNagraDrmDRMConfiguration } from "./NagraDrmUtils"; + +export class NagraDrmWidevineContentProtectionIntegration + implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: NagraDrmConfiguration; + + constructor(configuration: NagraDrmConfiguration) { + if (!isNagraDrmDRMConfiguration(configuration)) { + throw new Error("The Nagra token has not been correctly configured."); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest( + request: CertificateRequest + ): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + "nv-authorizations": this.contentProtectionConfiguration + .integrationParameters.token, + "Content-Type": "application/octet-stream" + }; + return request; + } + + onLicenseRequest( + request: LicenseRequest + ): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { + throw new Error( + "The Widevine Nagra license url has not been correctly configured." + ); + } + request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + "nv-authorizations": this.contentProtectionConfiguration + .integrationParameters.token + }; + return request; + } +} diff --git a/web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..de37d371 --- /dev/null +++ b/web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts @@ -0,0 +1,13 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; +import { NagraDrmWidevineContentProtectionIntegration } from "./NagraDrmWidevineContentProtectionIntegration"; + +export class NagraDrmWidevineContentProtectionIntegrationFactory + implements ContentProtectionIntegrationFactory { + build(configuration: NagraDrmConfiguration): ContentProtectionIntegration { + return new NagraDrmWidevineContentProtectionIntegration(configuration); + } +} diff --git a/web/test/nagradrm/fairplay.html b/web/test/nagradrm/fairplay.html new file mode 100644 index 00000000..a230b836 --- /dev/null +++ b/web/test/nagradrm/fairplay.html @@ -0,0 +1,114 @@ + + + THEOplayer Web SDK Nagra FairPlay + + + + + + + + + +
+
+
+
+
+

Enter valid data below, and hit play.

+ + + + + + + + + + + +
+
+ + + + diff --git a/web/test/nagradrm/playready.html b/web/test/nagradrm/playready.html new file mode 100644 index 00000000..c6b47334 --- /dev/null +++ b/web/test/nagradrm/playready.html @@ -0,0 +1,123 @@ + + + THEOplayer Web SDK Nagra PlayReady + + + + + + + + + +
+
+
+
+
+

Enter valid data below, and hit play.

+ + + + + + + +
+
+ + + + diff --git a/web/test/nagradrm/style.css b/web/test/nagradrm/style.css new file mode 100644 index 00000000..22a6b036 --- /dev/null +++ b/web/test/nagradrm/style.css @@ -0,0 +1,16 @@ +.row { + display: flex; +} + +.column { + flex: 50%; + padding: 5px; +} + +input[type="text"] { + width: 100%; +} + +#update { + margin-top: 5px; +} diff --git a/web/test/nagradrm/widevine.html b/web/test/nagradrm/widevine.html new file mode 100644 index 00000000..bb00cba5 --- /dev/null +++ b/web/test/nagradrm/widevine.html @@ -0,0 +1,123 @@ + + + THEOplayer Web SDK Nagra Widevine + + + + + + + + + +
+
+
+
+
+

Enter valid data below, and hit play.

+ + + + + + + +
+
+ + + + From fdc373a14aeac08efbf7c5da2152712c54a576df Mon Sep 17 00:00:00 2001 From: Thijs Date: Thu, 18 Mar 2021 10:24:20 -0400 Subject: [PATCH 09/85] Feature/comcast (#3) Add initial THEOplayer Web SDK Comcast DRM examples --- .../project.pbxproj | 14 +- .../AppDelegate.swift | 2 +- package-lock.json | 3 + web/README.md | 2 +- web/package-lock.json | 2693 ++++++++++++++++- web/src/index.ts | 6 + .../comcastdrm/ComcastDrmConfiguration.ts | 45 + ...DrmFairPlayContentProtectionIntegration.ts | 61 + ...PlayContentProtectionIntegrationFactory.ts | 12 + .../integration/comcastdrm/ComcastDrmUtils.ts | 7 + ...DrmWidevineContentProtectionIntegration.ts | 69 + ...vineContentProtectionIntegrationFactory.ts | 12 + web/test/comcastdrm/fairplay.html | 56 + web/test/comcastdrm/playready.html | 47 + web/test/comcastdrm/widevine.html | 54 + 15 files changed, 3076 insertions(+), 7 deletions(-) create mode 100644 package-lock.json create mode 100644 web/src/integration/comcastdrm/ComcastDrmConfiguration.ts create mode 100644 web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts create mode 100644 web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/comcastdrm/ComcastDrmUtils.ts create mode 100644 web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts create mode 100644 web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts create mode 100644 web/test/comcastdrm/fairplay.html create mode 100644 web/test/comcastdrm/playready.html create mode 100644 web/test/comcastdrm/widevine.html diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj index 6eba54c6..0c2bf196 100644 --- a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj +++ b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj @@ -336,7 +336,9 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = 8YAB8ZY55Y; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", @@ -346,8 +348,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.theoplayer.ContentProtectionIntegration; + PRODUCT_BUNDLE_IDENTIFIER = theoplayer.ContentProtectionIntegration; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "match Development theoplayer.*"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -357,7 +360,9 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = 8YAB8ZY55Y; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", @@ -367,8 +372,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.theoplayer.ContentProtectionIntegration; + PRODUCT_BUNDLE_IDENTIFIER = theoplayer.ContentProtectionIntegration; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "match Development theoplayer.*"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/ios/ContentProtectionIntegration/AppDelegate.swift b/ios/ContentProtectionIntegration/AppDelegate.swift index cbb5788e..efa393a3 100644 --- a/ios/ContentProtectionIntegration/AppDelegate.swift +++ b/ios/ContentProtectionIntegration/AppDelegate.swift @@ -19,7 +19,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { THEOplayer.registerContentProtectionIntegration(integrationId: UplynkDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: UplynkDRMIntegrationFactory()) THEOplayer.registerContentProtectionIntegration(integrationId: AzureDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: AzureDRMIntegrationFactory()) - + THEOplayer.registerContentProtectionIntegration(integrationId: EzdrmDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: EzdrmDRMIntegrationFactory()) return true } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..48e341a0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/web/README.md b/web/README.md index 160ecc04..7dcb7ba4 100644 --- a/web/README.md +++ b/web/README.md @@ -182,6 +182,6 @@ passed during registration, an instance of `CustomContentProtectionIntegration` - Include a THEOplayer build in the root folder under `THEOplayer/`. It should contain the THEOplayer javascript library `THEOplayer.js`, the declaration file `THEOplayer.d.ts` with all exported TypeScript types, and `ui.css`. -- Run `npm install && npm build` in the root folder to create the integrations library `bundle.js` under `dist/`. +- Run `npm install && npm run build` in the root folder to create the integrations library `bundle.js` under `dist/`. - Start http-server in the root folder by running `npm run server`. - Go to `localhost:8080/test/[integration you want to test]`. diff --git a/web/package-lock.json b/web/package-lock.json index 399518fa..ff80fc01 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,8 +1,2699 @@ { "name": "drm-api-plugins", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "drm-api-plugins", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@types/long": "^4.0.1", + "conditional-type-checks": "^1.0.5", + "lodash": "^4.17.20", + "long": "^4.0.0" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^15.0.0", + "@rollup/plugin-node-resolve": "^9.0.0", + "@rollup/plugin-typescript": "^5.0.2", + "@types/lodash": "^4.14.161", + "@types/node": "^14.6.3", + "@typescript-eslint/eslint-plugin": "^4.0.1", + "@typescript-eslint/parser": "^4.0.1", + "eslint": "^7.8.1", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-plugin-import": "^2.22.0", + "http-server": "^0.12.3", + "rollup": "^2.26.9", + "ts-node": "^9.0.0", + "tslib": "^2.0.1", + "typescript": "^4.0.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", + "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz", + "integrity": "sha512-8uAdikHqVyrT32w1zB9VhW6uGwGjhKgnDNP4pQJsjdnyF4FgCj6/bmv24c7v2CuKhq32CcyCwRzMPEElaKkn0w==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz", + "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-5.0.2.tgz", + "integrity": "sha512-CkS028Itwjqm1uLbFVfpJgtVtnNvZ+og/m6UlNRR5wOOnNTWPcVQzOu5xGdEX+WWJxdvWIqUq2uR/RBt2ZipWg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.1", + "resolve": "^1.14.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.161", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", + "integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA==", + "dev": true + }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "node_modules/@types/node": { + "version": "14.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz", + "integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww==", + "dev": true + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz", + "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.0.1", + "@typescript-eslint/scope-manager": "4.0.1", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz", + "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.0.1", + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/typescript-estree": "4.0.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz", + "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "4.0.1", + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/typescript-estree": "4.0.1", + "debug": "^4.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz", + "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/visitor-keys": "4.0.1" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz", + "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz", + "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/visitor-keys": "4.0.1", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz", + "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.0.1", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + } + }, + "node_modules/acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "node_modules/ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/conditional-type-checks": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/conditional-type-checks/-/conditional-type-checks-1.0.5.tgz", + "integrity": "sha512-DkfkvmjXVe4ye4llJ1JADtO3dNvqqcQM08cA9BhNt9Oe8pyRW8X1CZyBg9Qst05bDV9BJM01KLmnFh78NcJgNg==" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", + "dev": true + }, + "node_modules/contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dev": true, + "dependencies": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + }, + "bin": { + "ecstatic": "lib/ecstatic.js" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", + "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.1.3", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", + "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.9", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", + "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", + "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-server": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", + "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", + "dev": true, + "dependencies": { + "basic-auth": "^1.0.3", + "colors": "^1.4.0", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.18.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.25", + "secure-compare": "3.0.1", + "union": "~0.5.0" + }, + "bin": { + "hs": "bin/http-server", + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.entries": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", + "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "dependencies": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "dependencies": { + "pify": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rollup": { + "version": "2.26.9", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.9.tgz", + "integrity": "sha512-XIiWYLayLqV+oY4S2Lub/shJq4uk/QQLwWToYCL4LjZbYHbFK3czea4UDVRUJu+zNmKmxq5Zb/OG7c5HSvH2TQ==", + "dev": true, + "dependencies": { + "fsevents": "~2.1.2" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, + "node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", + "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", + "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.10.4", diff --git a/web/src/index.ts b/web/src/index.ts index f5accdb9..cb9bcce5 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -18,6 +18,10 @@ import { AxinomDrmPlayReadyContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory'; import { AxinomDrmFairplayContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory'; +import { ComcastDrmWidevineContentProtectionIntegrationFactory } from + './integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory'; +import { ComcastDrmFairPlayContentProtectionIntegrationFactory } from + './integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory'; import { IrdetoControlFairplayContentProtectionIntegrationFactory} from './integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory'; import { NagraDrmWidevineContentProtectionIntegrationFactory } from @@ -38,6 +42,8 @@ export { AzureDrmWidevineContentProtectionIntegrationFactory, AzureDrmPlayReadyContentProtectionIntegrationFactory, AzureDrmFairplayContentProtectionIntegrationFactory, + ComcastDrmWidevineContentProtectionIntegrationFactory, + ComcastDrmFairPlayContentProtectionIntegrationFactory, IrdetoControlFairplayContentProtectionIntegrationFactory, NagraDrmWidevineContentProtectionIntegrationFactory, NagraDrmPlayReadyContentProtectionIntegrationFactory, diff --git a/web/src/integration/comcastdrm/ComcastDrmConfiguration.ts b/web/src/integration/comcastdrm/ComcastDrmConfiguration.ts new file mode 100644 index 00000000..b66c0a04 --- /dev/null +++ b/web/src/integration/comcastdrm/ComcastDrmConfiguration.ts @@ -0,0 +1,45 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Comcast DRM integration. + */ +export type ComcastIntegrationID = 'comcast'; + +/** + * Describes the configuration of the Comcast DRM integration. + */ +export interface ComcastDrmConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: ComcastIntegrationID; + + /** + * An object of key/value pairs which can be used to pass in specific parameters related to a source into a + * ContentProtectionIntegration. + */ + integrationParameters: { + + /** + * The Comcast Release Pid. + * + *
- This releasePid will be used for the license request. + */ + releasePid: string; + + /** + * The Comcast Account ID. + * + *
- This accountId will be used for the license request. + */ + accountId: string; + + /** + * The Comcast Token. + * + *
- This token will be used for the license request. + */ + token: string; + } +} diff --git a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts new file mode 100644 index 00000000..e77af30e --- /dev/null +++ b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -0,0 +1,61 @@ +import { + BufferSource, + ContentProtectionIntegration, + LicenseRequest, + LicenseResponse, + MaybeAsync, + utils +} from 'THEOplayer'; +import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; +import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; +import { extractContentId } from '../../utils/FairplayUtils'; + +export class ComcastDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: ComcastDrmConfiguration; + private contentId: string | undefined = undefined; + + constructor(configuration: ComcastDrmConfiguration) { + if (!isComcastDrmDRMConfiguration(configuration)) { + throw new Error('The FairPlay ComcastDRM configuration is incorrect.' + + 'Please verify that you have configured a token, releasePid and accountId.'); + } + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { + throw new Error('The FairPlay ComcastDRM license url has not been correctly configured.'); + } + const { token, accountId, releasePid } = this.contentProtectionConfiguration.integrationParameters; + let spcMessage = utils.base64.encode(new Uint8Array(request.body!)); + let body = { + "getFairplayLicense": { + "releasePid": releasePid, + "spcMessage": spcMessage + } + }; + + let newBody = new TextEncoder().encode(JSON.stringify(body)); + return { + ...request, + url: request.url + `&token=${token}&account=${accountId}&form=json`, + headers: { + 'Content-Type': 'application/json' + }, + body: newBody + }; + + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + const responseAsText = new TextDecoder().decode(response.body); + const responseObject = JSON.parse(responseAsText); + return Uint8Array.from(atob(responseObject.getFairplayLicenseResponse.ckcResponse), c => c.charCodeAt(0)).buffer; + } + + extractFairplayContentId(skdUrl: string): string { + const modifiedContentId = skdUrl.replace('FairPlay', this.contentProtectionConfiguration.integrationParameters.releasePid); + this.contentId = extractContentId(modifiedContentId); + return this.contentId; + } +} diff --git a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..6cc94d61 --- /dev/null +++ b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; +import { ComcastDrmFairPlayContentProtectionIntegration } from './ComcastDrmFairPlayContentProtectionIntegration'; + +export class ComcastDrmFairPlayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: ComcastDrmConfiguration): ContentProtectionIntegration { + return new ComcastDrmFairPlayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/comcastdrm/ComcastDrmUtils.ts b/web/src/integration/comcastdrm/ComcastDrmUtils.ts new file mode 100644 index 00000000..06af86ba --- /dev/null +++ b/web/src/integration/comcastdrm/ComcastDrmUtils.ts @@ -0,0 +1,7 @@ +import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; + +export function isComcastDrmDRMConfiguration(configuration: ComcastDrmConfiguration): boolean { + return (configuration.integrationParameters.token !== undefined && + configuration.integrationParameters.releasePid !== undefined && + configuration.integrationParameters.accountId !== undefined); +} \ No newline at end of file diff --git a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts new file mode 100644 index 00000000..f0a2621d --- /dev/null +++ b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts @@ -0,0 +1,69 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource, utils, LicenseResponse, CertificateRequest, CertificateResponse +} from 'THEOplayer'; +import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; +import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; + +export class ComcastDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: ComcastDrmConfiguration; + + constructor(configuration: ComcastDrmConfiguration) { + if(!isComcastDrmDRMConfiguration(configuration)){ + throw new Error('The Widevine AzureDRM token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + const { token, accountId, releasePid } = this.contentProtectionConfiguration.integrationParameters; + let widevineChallenge = utils.base64.encode(new Uint8Array(request.body!)); + let body = { + "getWidevineLicense": { + "releasePid": releasePid, + "widevineChallenge": widevineChallenge + } + }; + return { + ...request, + url: request.url + `&token=${token}&account=${accountId}`, + body: new TextEncoder().encode(JSON.stringify(body)) + }; + } + + onCertificateResponse(response: CertificateResponse): MaybeAsync { + const responseAsText = new TextDecoder().decode(response.body); + const responseObject = JSON.parse(responseAsText); + return Uint8Array.from(atob(responseObject.getWidevineLicenseResponse.license), c => c.charCodeAt(0)).buffer; + + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { + throw new Error('The Widevine AzureDRM license url has not been correctly configured.'); + } + const { token, accountId, releasePid } = this.contentProtectionConfiguration.integrationParameters; + let widevineChallenge = utils.base64.encode(new Uint8Array(request.body!)); + let body = { + "getWidevineLicense": { + "releasePid": releasePid, + "widevineChallenge": widevineChallenge + } + }; + return { + ...request, + url: request.url + `&token=${token}&account=${accountId}`, + body: new TextEncoder().encode(JSON.stringify(body)) + }; + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + const responseAsText = new TextDecoder().decode(response.body); + const responseObject = JSON.parse(responseAsText); + return Uint8Array.from(atob(responseObject.getWidevineLicenseResponse.license), c => c.charCodeAt(0)).buffer; + } + +} diff --git a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..28eddd4c --- /dev/null +++ b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; +import { ComcastDrmWidevineContentProtectionIntegration } from './ComcastDrmWidevineContentProtectionIntegration'; + +export class ComcastDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: ComcastDrmConfiguration): ContentProtectionIntegration { + return new ComcastDrmWidevineContentProtectionIntegration(configuration); + } +} diff --git a/web/test/comcastdrm/fairplay.html b/web/test/comcastdrm/fairplay.html new file mode 100644 index 00000000..d7112988 --- /dev/null +++ b/web/test/comcastdrm/fairplay.html @@ -0,0 +1,56 @@ + + + + + Comcast drm FairPlay Test + + + + + +
+ + + diff --git a/web/test/comcastdrm/playready.html b/web/test/comcastdrm/playready.html new file mode 100644 index 00000000..1641575c --- /dev/null +++ b/web/test/comcastdrm/playready.html @@ -0,0 +1,47 @@ + + + + + Comcast drm PlayReady Test + + + + +
+ + + diff --git a/web/test/comcastdrm/widevine.html b/web/test/comcastdrm/widevine.html new file mode 100644 index 00000000..81c105c6 --- /dev/null +++ b/web/test/comcastdrm/widevine.html @@ -0,0 +1,54 @@ + + + + + Comcast drm Widevine Test + + + + + +
+ + + From 9d54dafc5404ddccef721122ffd1a67317f1055c Mon Sep 17 00:00:00 2001 From: Savdeep Gandhi Date: Thu, 22 Apr 2021 17:08:01 +0200 Subject: [PATCH 10/85] Added KeyOS DRM Sample Integration --- web/src/index.ts | 8 ++- .../keyos/KeyOSDrmConfiguration.ts | 30 ++++++++++ ...DrmFairplayContentProtectionIntegration.ts | 59 +++++++++++++++++++ ...playContentProtectionIntegrationFactory.ts | 12 ++++ web/src/integration/keyos/KeyOSDrmUtils.ts | 5 ++ ...DrmWidevineContentProtectionIntegration.ts | 32 ++++++++++ ...vineContentProtectionIntegrationFactory.ts | 12 ++++ web/test/keyos/fairplay.html | 47 +++++++++++++++ web/test/keyos/widevine.html | 46 +++++++++++++++ 9 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 web/src/integration/keyos/KeyOSDrmConfiguration.ts create mode 100644 web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts create mode 100644 web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/keyos/KeyOSDrmUtils.ts create mode 100644 web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts create mode 100644 web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts create mode 100644 web/test/keyos/fairplay.html create mode 100644 web/test/keyos/widevine.html diff --git a/web/src/index.ts b/web/src/index.ts index cb9bcce5..85e79569 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -30,6 +30,10 @@ import { NagraDrmPlayReadyContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory'; import { NagraDrmFairPlayContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory'; +import { KeyOSDrmFairplayContentProtectionIntegrationFactory } from + './integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory'; +import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from + "./integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory"; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -47,5 +51,7 @@ export { IrdetoControlFairplayContentProtectionIntegrationFactory, NagraDrmWidevineContentProtectionIntegrationFactory, NagraDrmPlayReadyContentProtectionIntegrationFactory, - NagraDrmFairPlayContentProtectionIntegrationFactory + NagraDrmFairPlayContentProtectionIntegrationFactory, + KeyOSDrmWidevineContentProtectionIntegrationFactory, + KeyOSDrmFairplayContentProtectionIntegrationFactory }; diff --git a/web/src/integration/keyos/KeyOSDrmConfiguration.ts b/web/src/integration/keyos/KeyOSDrmConfiguration.ts new file mode 100644 index 00000000..5c4437b1 --- /dev/null +++ b/web/src/integration/keyos/KeyOSDrmConfiguration.ts @@ -0,0 +1,30 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the KeyOS integration. + */ +export type KeyOSIntegrationId = 'keyos'; + +/** + * Describes the configuration of the Axinom DRM integration. + */ +export interface KeyOSDrmConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: KeyOSIntegrationId; + + /** + * An object of key/value pairs which can be used to pass in specific parameters related to a source into a + * ContentProtectionIntegration. + */ + integrationParameters: { + /** + * The KeyOS Authorization Token. + * + *
- Token that will be added to the headers of the license request. + */ + token: string; + } +} diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts new file mode 100644 index 00000000..24bfdb11 --- /dev/null +++ b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -0,0 +1,59 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource, + CertificateRequest, utils, LicenseResponse +} from 'THEOplayer'; +import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; +import { isKeyOSDrmDRMConfiguration } from "./KeyOSDrmUtils"; +import {extractContentId, unwrapCkc} from "../../utils/FairplayUtils"; + +export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: KeyOSDrmConfiguration; + private contentId: string | undefined = undefined; + + constructor(configuration: KeyOSDrmConfiguration) { + if (!isKeyOSDrmDRMConfiguration(configuration)) { + throw new Error('The KeyOS token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.certificateURL) { + throw new Error('The KeyOS certificate url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; + request.headers = { + ...request.headers, + 'x-dt-auth-token': this.contentProtectionConfiguration.integrationParameters.token + }; + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { + throw new Error('The KeyOS Fairplay license url has not been correctly configured.'); + } + + request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + 'x-dt-auth-token': this.contentProtectionConfiguration.integrationParameters.token + }; + const licenseParameters = `spc=${encodeURIComponent(utils.base64.encode(new Uint8Array(request.body!)))}&assetId=${encodeURIComponent(this.contentId!)}`; + request.body = new TextEncoder().encode(licenseParameters); + return request; + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + return unwrapCkc(response.body); + } + + extractFairplayContentId(skdUrl: string): string { + this.contentId = extractContentId(skdUrl); + return this.contentId; + } +} diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..5f8f9e16 --- /dev/null +++ b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; +import { KeyOSDrmFairplayContentProtectionIntegration } from "./KeyOSDrmFairplayContentProtectionIntegration"; + +export class KeyOSDrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: KeyOSDrmConfiguration): ContentProtectionIntegration { + return new KeyOSDrmFairplayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/keyos/KeyOSDrmUtils.ts b/web/src/integration/keyos/KeyOSDrmUtils.ts new file mode 100644 index 00000000..96f580c7 --- /dev/null +++ b/web/src/integration/keyos/KeyOSDrmUtils.ts @@ -0,0 +1,5 @@ +import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; + +export function isKeyOSDrmDRMConfiguration(configuration: KeyOSDrmConfiguration): boolean { + return configuration.integrationParameters.token !== undefined; +} diff --git a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts new file mode 100644 index 00000000..00708fbe --- /dev/null +++ b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts @@ -0,0 +1,32 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; +import { isKeyOSDrmDRMConfiguration } from "./KeyOSDrmUtils"; + +export class KeyOSDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: KeyOSDrmConfiguration; + + constructor(configuration: KeyOSDrmConfiguration) { + if (!isKeyOSDrmDRMConfiguration(configuration)) { + throw new Error('The KeyOS token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { + throw new Error('The Widevine KeyOS license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + 'x-dt-auth-token': this.contentProtectionConfiguration.integrationParameters.token + }; + return request; + } +} diff --git a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..e5eb68c2 --- /dev/null +++ b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; +import { KeyOSDrmWidevineContentProtectionIntegration } from "./KeyOSDrmWidevineContentProtectionIntegration"; + +export class KeyOSDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: KeyOSDrmConfiguration): ContentProtectionIntegration { + return new KeyOSDrmWidevineContentProtectionIntegration(configuration); + } +} diff --git a/web/test/keyos/fairplay.html b/web/test/keyos/fairplay.html new file mode 100644 index 00000000..093ef278 --- /dev/null +++ b/web/test/keyos/fairplay.html @@ -0,0 +1,47 @@ + + + + + KeyOS drm FairPlay Test + + + + + +
+ + + diff --git a/web/test/keyos/widevine.html b/web/test/keyos/widevine.html new file mode 100644 index 00000000..eec05fdc --- /dev/null +++ b/web/test/keyos/widevine.html @@ -0,0 +1,46 @@ + + + + + Azure drm Widevine Test + + + + + +
+ + + From 688cd5b10dd5c99913eacc9eded45c3a18dd0da3 Mon Sep 17 00:00:00 2001 From: Savdeep Gandhi Date: Thu, 22 Apr 2021 17:09:49 +0200 Subject: [PATCH 11/85] Updated Readme File --- web/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/web/README.md b/web/README.md index 7dcb7ba4..6ebd646f 100644 --- a/web/README.md +++ b/web/README.md @@ -177,6 +177,7 @@ passed during registration, an instance of `CustomContentProtectionIntegration` - Axinom DRM - Irdeto Control - Nagra DRM +- BuyDRM KeyOS ### Testing an integration From d5bd5956deeb213bf84eb2455cd4ca631b95dd22 Mon Sep 17 00:00:00 2001 From: Savdeep Gandhi Date: Fri, 23 Apr 2021 13:11:41 +0200 Subject: [PATCH 12/85] Updated the KeyOS DRM --- web/package-lock.json | 2693 +---------------- web/src/index.ts | 5 +- ...DrmFairplayContentProtectionIntegration.ts | 17 +- ...rmPlayReadyContentProtectionIntegration.ts | 32 + web/src/integration/keyos/KeyOSDrmUtils.ts | 10 + ...DrmWidevineContentProtectionIntegration.ts | 2 +- ...eadyContentProtectionIntegrationFactory.ts | 12 + web/test/keyos/fairplay.html | 4 +- web/test/keyos/playready.html | 46 + web/test/keyos/widevine.html | 6 +- 10 files changed, 122 insertions(+), 2705 deletions(-) create mode 100644 web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts create mode 100644 web/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts create mode 100644 web/test/keyos/playready.html diff --git a/web/package-lock.json b/web/package-lock.json index ff80fc01..399518fa 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,2699 +1,8 @@ { "name": "drm-api-plugins", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "drm-api-plugins", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@types/long": "^4.0.1", - "conditional-type-checks": "^1.0.5", - "lodash": "^4.17.20", - "long": "^4.0.0" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^15.0.0", - "@rollup/plugin-node-resolve": "^9.0.0", - "@rollup/plugin-typescript": "^5.0.2", - "@types/lodash": "^4.14.161", - "@types/node": "^14.6.3", - "@typescript-eslint/eslint-plugin": "^4.0.1", - "@typescript-eslint/parser": "^4.0.1", - "eslint": "^7.8.1", - "eslint-config-airbnb-base": "^14.2.0", - "eslint-plugin-import": "^2.22.0", - "http-server": "^0.12.3", - "rollup": "^2.26.9", - "ts-node": "^9.0.0", - "tslib": "^2.0.1", - "typescript": "^4.0.2" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "node_modules/@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", - "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz", - "integrity": "sha512-8uAdikHqVyrT32w1zB9VhW6uGwGjhKgnDNP4pQJsjdnyF4FgCj6/bmv24c7v2CuKhq32CcyCwRzMPEElaKkn0w==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz", - "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@rollup/plugin-typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-5.0.2.tgz", - "integrity": "sha512-CkS028Itwjqm1uLbFVfpJgtVtnNvZ+og/m6UlNRR5wOOnNTWPcVQzOu5xGdEX+WWJxdvWIqUq2uR/RBt2ZipWg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.0.1", - "resolve": "^1.14.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "node_modules/@types/lodash": { - "version": "4.14.161", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", - "integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA==", - "dev": true - }, - "node_modules/@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "node_modules/@types/node": { - "version": "14.6.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz", - "integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz", - "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "4.0.1", - "@typescript-eslint/scope-manager": "4.0.1", - "debug": "^4.1.1", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz", - "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz", - "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", - "debug": "^4.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz", - "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz", - "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==", - "dev": true, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz", - "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz", - "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.0.1", - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true - }, - "node_modules/ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", - "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "dependencies": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/conditional-type-checks": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/conditional-type-checks/-/conditional-type-checks-1.0.5.tgz", - "integrity": "sha512-DkfkvmjXVe4ye4llJ1JADtO3dNvqqcQM08cA9BhNt9Oe8pyRW8X1CZyBg9Qst05bDV9BJM01KLmnFh78NcJgNg==" - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", - "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", - "dev": true - }, - "node_modules/contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/corser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", - "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/ecstatic": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", - "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", - "dev": true, - "dependencies": { - "he": "^1.1.1", - "mime": "^1.6.0", - "minimist": "^1.1.0", - "url-join": "^2.0.5" - }, - "bin": { - "ecstatic": "lib/ecstatic.js" - } - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "dependencies": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", - "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.1.3", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^1.3.0", - "espree": "^7.3.0", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", - "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.9", - "object.assign": "^4.1.0", - "object.entries": "^1.1.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "dependencies": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", - "dev": true, - "dependencies": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-module-utils/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-plugin-import": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", - "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.3", - "eslint-module-utils": "^2.6.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "dependencies": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", - "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", - "dev": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "dependencies": { - "flat-cache": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "dependencies": { - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-server": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", - "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", - "dev": true, - "dependencies": { - "basic-auth": "^1.0.3", - "colors": "^1.4.0", - "corser": "^2.0.1", - "ecstatic": "^3.3.2", - "http-proxy": "^1.18.0", - "minimist": "^1.2.5", - "opener": "^1.5.1", - "portfinder": "^1.0.25", - "secure-compare": "3.0.1", - "union": "~0.5.0" - }, - "bin": { - "hs": "bin/http-server", - "http-server": "bin/http-server" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.entries": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", - "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true, - "bin": { - "opener": "bin/opener-bin.js" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "dependencies": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "dependencies": { - "pify": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/rollup": { - "version": "2.26.9", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.9.tgz", - "integrity": "sha512-XIiWYLayLqV+oY4S2Lub/shJq4uk/QQLwWToYCL4LjZbYHbFK3czea4UDVRUJu+zNmKmxq5Zb/OG7c5HSvH2TQ==", - "dev": true, - "dependencies": { - "fsevents": "~2.1.2" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "node_modules/secure-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", - "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", - "dev": true - }, - "node_modules/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-node": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", - "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", - "dev": true, - "dependencies": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tslib": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", - "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/typescript": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", - "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/union": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", - "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", - "dev": true, - "dependencies": { - "qs": "^6.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-join": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", - "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", - "dev": true - }, - "node_modules/v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - }, "dependencies": { "@babel/code-frame": { "version": "7.10.4", diff --git a/web/src/index.ts b/web/src/index.ts index 85e79569..2570eec9 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -34,6 +34,8 @@ import { KeyOSDrmFairplayContentProtectionIntegrationFactory } from './integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory'; import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from "./integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory"; +import {KeyOSDrmPlayReadyContentProtectionIntegration} from + "./integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration"; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -53,5 +55,6 @@ export { NagraDrmPlayReadyContentProtectionIntegrationFactory, NagraDrmFairPlayContentProtectionIntegrationFactory, KeyOSDrmWidevineContentProtectionIntegrationFactory, - KeyOSDrmFairplayContentProtectionIntegrationFactory + KeyOSDrmFairplayContentProtectionIntegrationFactory, + KeyOSDrmPlayReadyContentProtectionIntegration }; diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts index 24bfdb11..6c519333 100644 --- a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -6,8 +6,8 @@ import { CertificateRequest, utils, LicenseResponse } from 'THEOplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; -import { isKeyOSDrmDRMConfiguration } from "./KeyOSDrmUtils"; -import {extractContentId, unwrapCkc} from "../../utils/FairplayUtils"; +import { isKeyOSDrmDRMConfiguration, extractContentId } from "./KeyOSDrmUtils"; + export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { @@ -28,7 +28,7 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; request.headers = { ...request.headers, - 'x-dt-auth-token': this.contentProtectionConfiguration.integrationParameters.token + 'customdata': this.contentProtectionConfiguration.integrationParameters.token }; return request; } @@ -41,15 +41,20 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; request.headers = { ...request.headers, - 'x-dt-auth-token': this.contentProtectionConfiguration.integrationParameters.token + 'customdata': this.contentProtectionConfiguration.integrationParameters.token }; - const licenseParameters = `spc=${encodeURIComponent(utils.base64.encode(new Uint8Array(request.body!)))}&assetId=${encodeURIComponent(this.contentId!)}`; + const licenseParameters = `spc=${window.THEOplayer.utils.base64.encode(request.body!)}&assetId=${this.contentId}`; request.body = new TextEncoder().encode(licenseParameters); return request; } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - return unwrapCkc(response.body); + let bodyAsString = new TextDecoder('utf-8').decode(response.body) + let keyText = bodyAsString.trim() + if (keyText.substr(0, 5) === '' && keyText.substr(-6) === '') { + keyText = keyText.slice(5, -6) + } + return window.THEOplayer.utils.base64.decode(keyText) } extractFairplayContentId(skdUrl: string): string { diff --git a/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts new file mode 100644 index 00000000..753acbad --- /dev/null +++ b/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts @@ -0,0 +1,32 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource +} from 'THEOplayer'; +import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; +import { isKeyOSDrmDRMConfiguration } from "./KeyOSDrmUtils"; + +export class KeyOSDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: KeyOSDrmConfiguration; + + constructor(configuration: KeyOSDrmConfiguration) { + if (!isKeyOSDrmDRMConfiguration(configuration)) { + throw new Error('The KeyOS token has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + if (!this.contentProtectionConfiguration.playready?.licenseAcquisitionURL) { + throw new Error('The PlayReady KeyOS license url has not been correctly configured.'); + } + request.url = this.contentProtectionConfiguration.playready?.licenseAcquisitionURL; + request.headers = { + ...request.headers, + 'customdata': this.contentProtectionConfiguration.integrationParameters.token + }; + return request; + } +} diff --git a/web/src/integration/keyos/KeyOSDrmUtils.ts b/web/src/integration/keyos/KeyOSDrmUtils.ts index 96f580c7..8d4508c7 100644 --- a/web/src/integration/keyos/KeyOSDrmUtils.ts +++ b/web/src/integration/keyos/KeyOSDrmUtils.ts @@ -3,3 +3,13 @@ import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; export function isKeyOSDrmDRMConfiguration(configuration: KeyOSDrmConfiguration): boolean { return configuration.integrationParameters.token !== undefined; } + +export function extractContentId(skdUrl: string): string { + if (skdUrl.indexOf("skd") > 0 || skdUrl.indexOf("http") > 0) { + skdUrl = skdUrl.substring(1); + } + var link = document.createElement('a'); + link.href = skdUrl; + console.log(link.hostname, skdUrl) + return link.hostname; +} \ No newline at end of file diff --git a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts index 00708fbe..9e8f8d8e 100644 --- a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts @@ -25,7 +25,7 @@ export class KeyOSDrmWidevineContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL; request.headers = { ...request.headers, - 'x-dt-auth-token': this.contentProtectionConfiguration.integrationParameters.token + 'customdata': this.contentProtectionConfiguration.integrationParameters.token }; return request; } diff --git a/web/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts b/web/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..649814fe --- /dev/null +++ b/web/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; +import { KeyOSDrmPlayReadyContentProtectionIntegration } from "./KeyOSDrmPlayReadyContentProtectionIntegration"; + +export class KeyOSDrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: KeyOSDrmConfiguration): ContentProtectionIntegration { + return new KeyOSDrmPlayReadyContentProtectionIntegration(configuration); + } +} diff --git a/web/test/keyos/fairplay.html b/web/test/keyos/fairplay.html index 093ef278..86893f94 100644 --- a/web/test/keyos/fairplay.html +++ b/web/test/keyos/fairplay.html @@ -19,7 +19,7 @@ }); THEOplayer.registerContentProtectionIntegration( - 'buyDRM-keyos', + 'keyos', 'fairplay', new ContentProtectionIntegrations.KeyOSDrmFairplayContentProtectionIntegrationFactory() ); @@ -34,7 +34,7 @@ licenseAcquisitionURL: 'insert license url here' }, preferredKeySystems: ['fairplay', 'widevine', 'playready'], - integration: 'azure', + integration: 'keyos', integrationParameters: { token: 'insert token here', } diff --git a/web/test/keyos/playready.html b/web/test/keyos/playready.html new file mode 100644 index 00000000..c5271f0f --- /dev/null +++ b/web/test/keyos/playready.html @@ -0,0 +1,46 @@ + + + + + KeyOS drm PlayReady Test + + + + + +
+ + + diff --git a/web/test/keyos/widevine.html b/web/test/keyos/widevine.html index eec05fdc..e900f0bc 100644 --- a/web/test/keyos/widevine.html +++ b/web/test/keyos/widevine.html @@ -2,7 +2,7 @@ - Azure drm Widevine Test + KeyOS drm Widevine Test @@ -19,7 +19,7 @@ }); THEOplayer.registerContentProtectionIntegration( - 'buyDRM-keyos', + 'keyos', 'widevine', new ContentProtectionIntegrations.KeyOSDrmWidevineContentProtectionIntegrationFactory() ); @@ -29,7 +29,7 @@ { src: 'insert manifest url here', contentProtection: { - integration: 'azure', + integration: 'keyos', widevine: { licenseAcquisitionURL: 'insert license url here' }, From 959e54404fe8af43a840bcba927034f6291a1560 Mon Sep 17 00:00:00 2001 From: Thijs Date: Fri, 23 Apr 2021 09:02:31 -0400 Subject: [PATCH 13/85] Add default Widevine implementation for Comcast, and use account instead of accountId in Comcast connector (#5) --- .../comcastdrm/ComcastDrmConfiguration.ts | 4 +- ...DrmFairPlayContentProtectionIntegration.ts | 6 +- .../integration/comcastdrm/ComcastDrmUtils.ts | 2 +- ...DrmWidevineContentProtectionIntegration.ts | 8 +- web/test/comcastdrm/fairplay.html | 8 +- web/test/comcastdrm/widevine.html | 88 ++++++++++++++----- 6 files changed, 79 insertions(+), 37 deletions(-) diff --git a/web/src/integration/comcastdrm/ComcastDrmConfiguration.ts b/web/src/integration/comcastdrm/ComcastDrmConfiguration.ts index b66c0a04..b651fb99 100644 --- a/web/src/integration/comcastdrm/ComcastDrmConfiguration.ts +++ b/web/src/integration/comcastdrm/ComcastDrmConfiguration.ts @@ -31,9 +31,9 @@ export interface ComcastDrmConfiguration extends DRMConfiguration { /** * The Comcast Account ID. * - *
- This accountId will be used for the license request. + *
- This account will be used for the license request. */ - accountId: string; + account: string; /** * The Comcast Token. diff --git a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts index e77af30e..d3661790 100644 --- a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -17,7 +17,7 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr constructor(configuration: ComcastDrmConfiguration) { if (!isComcastDrmDRMConfiguration(configuration)) { throw new Error('The FairPlay ComcastDRM configuration is incorrect.' + - 'Please verify that you have configured a token, releasePid and accountId.'); + 'Please verify that you have configured a token, releasePid and account.'); } this.contentProtectionConfiguration = configuration; } @@ -26,7 +26,7 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { throw new Error('The FairPlay ComcastDRM license url has not been correctly configured.'); } - const { token, accountId, releasePid } = this.contentProtectionConfiguration.integrationParameters; + const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; let spcMessage = utils.base64.encode(new Uint8Array(request.body!)); let body = { "getFairplayLicense": { @@ -38,7 +38,7 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr let newBody = new TextEncoder().encode(JSON.stringify(body)); return { ...request, - url: request.url + `&token=${token}&account=${accountId}&form=json`, + url: request.url + `&token=${token}&account=${account}&form=json`, headers: { 'Content-Type': 'application/json' }, diff --git a/web/src/integration/comcastdrm/ComcastDrmUtils.ts b/web/src/integration/comcastdrm/ComcastDrmUtils.ts index 06af86ba..556d0133 100644 --- a/web/src/integration/comcastdrm/ComcastDrmUtils.ts +++ b/web/src/integration/comcastdrm/ComcastDrmUtils.ts @@ -3,5 +3,5 @@ import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; export function isComcastDrmDRMConfiguration(configuration: ComcastDrmConfiguration): boolean { return (configuration.integrationParameters.token !== undefined && configuration.integrationParameters.releasePid !== undefined && - configuration.integrationParameters.accountId !== undefined); + configuration.integrationParameters.account !== undefined); } \ No newline at end of file diff --git a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts index f0a2621d..4b896aa9 100644 --- a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts +++ b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts @@ -19,7 +19,7 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - const { token, accountId, releasePid } = this.contentProtectionConfiguration.integrationParameters; + const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; let widevineChallenge = utils.base64.encode(new Uint8Array(request.body!)); let body = { "getWidevineLicense": { @@ -29,7 +29,7 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr }; return { ...request, - url: request.url + `&token=${token}&account=${accountId}`, + url: request.url + `&token=${token}&account=${account}`, body: new TextEncoder().encode(JSON.stringify(body)) }; } @@ -45,7 +45,7 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { throw new Error('The Widevine AzureDRM license url has not been correctly configured.'); } - const { token, accountId, releasePid } = this.contentProtectionConfiguration.integrationParameters; + const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; let widevineChallenge = utils.base64.encode(new Uint8Array(request.body!)); let body = { "getWidevineLicense": { @@ -55,7 +55,7 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr }; return { ...request, - url: request.url + `&token=${token}&account=${accountId}`, + url: request.url + `&token=${token}&account=${account}`, body: new TextEncoder().encode(JSON.stringify(body)) }; } diff --git a/web/test/comcastdrm/fairplay.html b/web/test/comcastdrm/fairplay.html index d7112988..ca53d083 100644 --- a/web/test/comcastdrm/fairplay.html +++ b/web/test/comcastdrm/fairplay.html @@ -25,11 +25,13 @@ ); const src = ''; - const licenseAcquisitionURL = 'https://fairplay.entitlement.eu.theplatform.com/fpls/web/FairPlay?schema=1.0&form=json'; + const region = '.eu'; // might be optional. Omit or set to empty string "" if not needed. + const licenseAcquisitionURL = 'https://fairplay.entitlement' + region + '.theplatform.com/fpls/web/FairPlay?schema=1.0&form=json'; const certificateURL = ''; const token = ''; const releasePid = ''; - const accountId = 'http://access.auth.theplatform.com/data/Account/'; + const accountId = '' + const account = 'http://access.auth.theplatform.com/data/Account/' + accountId; player.source = { sources: [ { @@ -45,7 +47,7 @@ integrationParameters: { token: token, releasePid: releasePid, - accountId: accountId + account: account } } } diff --git a/web/test/comcastdrm/widevine.html b/web/test/comcastdrm/widevine.html index 81c105c6..c8bf691d 100644 --- a/web/test/comcastdrm/widevine.html +++ b/web/test/comcastdrm/widevine.html @@ -18,36 +18,76 @@ libraryLocation: '/THEOplayer/', }); - THEOplayer.registerContentProtectionIntegration( - 'comcast', - 'widevine', - new ContentProtectionIntegrations.ComcastDrmWidevineContentProtectionIntegrationFactory() - ); + /* Comcast writes at https://docs.theplatform.com/help/ent-getrawwidevinelicense-method: + The getRawWidevineLicense method retrieves licenses for content protected by Widevine Modular DRM. + The getRawWidevineLicense method returns the license without a JSON wrapper. + The getWidevineLicense method returns the license in a JSON wrapper. + + This example uses the getRawWidevineLicense method when useRawWidevine == true. + The advantage of uses the getRawWidevineLicense method is that it allows you to use a + "default Widevine integration", and that you don't have to use a custom connector. This reduces + the overhead, and also makes it compatible with THEOplayer's default Chromecast Receiver App. + (Our default Chromecast Receiver App doesn't implement this custom Comcast connector.) + + This example uses the getWidevineLicense method when useRawWidevine == false. + When you use this method, you need to use the custom Comcast DRM connector, as demonstrated + in the else-condition uses getWidevineLicense, because it requires custom handling of the JSON wrapper. + */ + const useRawWidevine = true; const src = ''; - const licenseAcquisitionURL = 'https://widevine.entitlement.eu.theplatform.com/wv/web/ModularDrm?schema=1.0&form=json'; + const region = ".eu"; // might be optional. Omit or set to empty string "" if not needed. const token = ''; const releasePid = ''; - const accountId = 'http://access.auth.theplatform.com/data/Account/'; - player.source = { - sources: [ - { - src: src, - type: 'application/dash+xml', - contentProtection: { - widevine: { - licenseAcquisitionURL: licenseAcquisitionURL, - }, - preferredKeySystems: ['widevine', 'playready', 'fairplay'], - integration: 'comcast', - integrationParameters: { - token: token, - releasePid: releasePid, - accountId: accountId + const accountId = ''; + const account = 'http://access.auth.theplatform.com/data/Account/' + accountId; + if (useRawWidevine) { + const licenseAcquisitionURL = 'https://widevine.entitlement' + region + + '.theplatform.com/wv/web/ModularDrm/getRawWidevineLicense?schema=1.0' + + '&releasePid=' + releasePid + '&token=' + token + '&account=' + account; + player.source = { + "sources": [ + { + "src": src, + "type": "application/dash+xml", + "contentProtection": { + "widevine": { + // If the network response on the licenseAcquisitionURL is a 422 status code, + // then your this URL is most likely malformed. + // Reach out to Comcast for assistance. + "licenseAcquisitionURL": licenseAcquisitionURL + } + } + } + ] + } + } else { + THEOplayer.registerContentProtectionIntegration( + 'comcast', + 'widevine', + new ContentProtectionIntegrations.ComcastDrmWidevineContentProtectionIntegrationFactory() + ); + const licenseAcquisitionURL = 'https://widevine.entitlement' + region + '.theplatform.com/wv/web/ModularDrm?schema=1.0&form=json'; + player.source = { + sources: [ + { + src: src, + type: 'application/dash+xml', + contentProtection: { + widevine: { + licenseAcquisitionURL: licenseAcquisitionURL, + }, + preferredKeySystems: ['widevine', 'playready', 'fairplay'], + integration: 'comcast', + integrationParameters: { + token: token, + releasePid: releasePid, + account: account + } } } - } - ] + ] + }; } From e076282a82c3695ed1a2734e6ab290d50f64a14d Mon Sep 17 00:00:00 2001 From: Thijs Date: Wed, 28 Apr 2021 17:04:41 -0400 Subject: [PATCH 14/85] Add GUI to Comcast tests to facilitate entering stream data, and allow users to handshake the THEOplayer SDK through a 'license' string. (#6) Co-authored-by: thijsl --- web/test/comcastdrm/fairplay.html | 125 +++++++++++++----- web/test/comcastdrm/playready.html | 119 +++++++++++++---- web/test/comcastdrm/style.css | 17 +++ web/test/comcastdrm/widevine.html | 203 +++++++++++++++++++---------- 4 files changed, 339 insertions(+), 125 deletions(-) create mode 100644 web/test/comcastdrm/style.css diff --git a/web/test/comcastdrm/fairplay.html b/web/test/comcastdrm/fairplay.html index ca53d083..e99f1244 100644 --- a/web/test/comcastdrm/fairplay.html +++ b/web/test/comcastdrm/fairplay.html @@ -2,20 +2,68 @@ - Comcast drm FairPlay Test - - + Comcast DRM FairPlay Test + + + -
+
+
+

Comcast DRM FairPlay

+

Enter valid data below, and hit play. Only use this test player on FairPlay-enabled platforms, such as Safari.

+ + + + + + + + + + + + + +
+
+
+
+
diff --git a/web/test/comcastdrm/playready.html b/web/test/comcastdrm/playready.html index 1641575c..66fc3d58 100644 --- a/web/test/comcastdrm/playready.html +++ b/web/test/comcastdrm/playready.html @@ -2,46 +2,113 @@ - Comcast drm PlayReady Test - - + Comcast DRM PlayReady Test + + + + -
+
+
+

Comcast DRM PlayReady

+

Enter valid data below, and hit play. Only use this test player on PlayReady-enabled platforms, such as Edge.

+ + + + + + + + + + + + + +
+
+
+
+
diff --git a/web/test/comcastdrm/style.css b/web/test/comcastdrm/style.css new file mode 100644 index 00000000..7c0c429c --- /dev/null +++ b/web/test/comcastdrm/style.css @@ -0,0 +1,17 @@ +.row { + display: flex; +} + +.column { + flex: 50%; + padding: 5px; +} + +input[type="text"] { + width: 100%; +} + +#update { + margin-top: 5px; + display: block; +} diff --git a/web/test/comcastdrm/widevine.html b/web/test/comcastdrm/widevine.html index c8bf691d..d8c454a4 100644 --- a/web/test/comcastdrm/widevine.html +++ b/web/test/comcastdrm/widevine.html @@ -2,93 +2,158 @@ - Comcast drm Widevine Test - - + Comcast DRM Widevine Test + + + -
+
+
+

Comcast DRM Widevine

+

Enter valid data below, and hit play. Only use this test player on Widevine-enabled platforms, such as Chrome.

+ + + + + + + + + + + + + +
+
+
+
+
From b18c0de289c8d5161b8cd4290c830a044ce33ddf Mon Sep 17 00:00:00 2001 From: Savdeep Gandhi Date: Fri, 30 Apr 2021 13:13:08 +0200 Subject: [PATCH 15/85] Updated the Playready factory setting --- web/src/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/index.ts b/web/src/index.ts index 2570eec9..30a15148 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -34,8 +34,8 @@ import { KeyOSDrmFairplayContentProtectionIntegrationFactory } from './integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory'; import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from "./integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory"; -import {KeyOSDrmPlayReadyContentProtectionIntegration} from - "./integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration"; +import {KeyOSDrmPlayReadyContentProtectionIntegrationFactory} from + "./integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory"; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -56,5 +56,5 @@ export { NagraDrmFairPlayContentProtectionIntegrationFactory, KeyOSDrmWidevineContentProtectionIntegrationFactory, KeyOSDrmFairplayContentProtectionIntegrationFactory, - KeyOSDrmPlayReadyContentProtectionIntegration + KeyOSDrmPlayReadyContentProtectionIntegrationFactory }; From 66940466c5d80faa2f5e0addacf33123b8042ea3 Mon Sep 17 00:00:00 2001 From: Thijs Date: Tue, 4 May 2021 12:39:39 -0400 Subject: [PATCH 16/85] Fix typos originating from copy-pasting another connector (#7) Co-authored-by: thijsl --- web/src/integration/nagradrm/NagraDrmConfiguration.ts | 2 +- .../nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/integration/nagradrm/NagraDrmConfiguration.ts b/web/src/integration/nagradrm/NagraDrmConfiguration.ts index e3b99bd6..25d024b5 100644 --- a/web/src/integration/nagradrm/NagraDrmConfiguration.ts +++ b/web/src/integration/nagradrm/NagraDrmConfiguration.ts @@ -3,7 +3,7 @@ import { DRMConfiguration } from 'THEOplayer'; /** * The identifier of the Nagra integration. */ -export type NagraIntegrationId = "axinom"; +export type NagraIntegrationId = "nagra"; /** * Describes the configuration of the Axinom DRM integration. diff --git a/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts index b8a3d5c3..8e58d7c8 100644 --- a/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts +++ b/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts @@ -14,7 +14,7 @@ export class NagraDrmPlayReadyContentProtectionIntegration constructor(configuration: NagraDrmConfiguration) { if (!isNagraDrmDRMConfiguration(configuration)) { - throw new Error("The Axinom token has not been correctly configured."); + throw new Error("The Nagra token has not been correctly configured."); } this.contentProtectionConfiguration = configuration; } @@ -36,7 +36,7 @@ export class NagraDrmPlayReadyContentProtectionIntegration ): MaybeAsync | BufferSource> { if (!this.contentProtectionConfiguration.playready?.licenseAcquisitionURL) { throw new Error( - "The PlayReady Axinom license url has not been correctly configured." + "The PlayReady Nagra license url has not been correctly configured." ); } request.url = this.contentProtectionConfiguration.playready?.licenseAcquisitionURL; From 6ceef4ee0cb93b28dcd684889c933d8d9feedba7 Mon Sep 17 00:00:00 2001 From: Thijs Date: Fri, 14 May 2021 09:55:08 -0400 Subject: [PATCH 17/85] Rename keyos integration to keyos_buydrm to avoid overlap with existing keyos pre-integration. Rename token to customdata to align with KeyOS terminology. (#8) Co-authored-by: thijsl --- web/README.md | 1 + web/src/integration/keyos/KeyOSDrmConfiguration.ts | 10 +++++----- .../KeyOSDrmFairplayContentProtectionIntegration.ts | 8 ++++---- .../KeyOSDrmPlayReadyContentProtectionIntegration.ts | 4 ++-- web/src/integration/keyos/KeyOSDrmUtils.ts | 3 +-- .../KeyOSDrmWidevineContentProtectionIntegration.ts | 2 +- web/test/keyos/fairplay.html | 7 ++++--- web/test/keyos/playready.html | 7 ++++--- web/test/keyos/widevine.html | 7 ++++--- 9 files changed, 26 insertions(+), 23 deletions(-) diff --git a/web/README.md b/web/README.md index 6ebd646f..fc63d073 100644 --- a/web/README.md +++ b/web/README.md @@ -178,6 +178,7 @@ passed during registration, an instance of `CustomContentProtectionIntegration` - Irdeto Control - Nagra DRM - BuyDRM KeyOS +- Comcast DRM ### Testing an integration diff --git a/web/src/integration/keyos/KeyOSDrmConfiguration.ts b/web/src/integration/keyos/KeyOSDrmConfiguration.ts index 5c4437b1..a43eb47c 100644 --- a/web/src/integration/keyos/KeyOSDrmConfiguration.ts +++ b/web/src/integration/keyos/KeyOSDrmConfiguration.ts @@ -1,12 +1,12 @@ import { DRMConfiguration } from 'THEOplayer'; /** - * The identifier of the KeyOS integration. + * The identifier of the KeyOS BuyDRM integration. */ -export type KeyOSIntegrationId = 'keyos'; +export type KeyOSIntegrationId = 'keyos_buydrm'; /** - * Describes the configuration of the Axinom DRM integration. + * Describes the configuration of the KeyOS BuyDRM DRM integration. */ export interface KeyOSDrmConfiguration extends DRMConfiguration { @@ -21,10 +21,10 @@ export interface KeyOSDrmConfiguration extends DRMConfiguration { */ integrationParameters: { /** - * The KeyOS Authorization Token. + * The KeyOS BuyDRM Authorization Token. * *
- Token that will be added to the headers of the license request. */ - token: string; + customdata: string; } } diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts index 6c519333..85b536cc 100644 --- a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -3,7 +3,7 @@ import { LicenseRequest, MaybeAsync, BufferSource, - CertificateRequest, utils, LicenseResponse + CertificateRequest, LicenseResponse } from 'THEOplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; import { isKeyOSDrmDRMConfiguration, extractContentId } from "./KeyOSDrmUtils"; @@ -16,7 +16,7 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt constructor(configuration: KeyOSDrmConfiguration) { if (!isKeyOSDrmDRMConfiguration(configuration)) { - throw new Error('The KeyOS token has not been correctly configured.'); + throw new Error('The KeyOS customdata value has not been correctly configured.'); } this.contentProtectionConfiguration = configuration; } @@ -28,7 +28,7 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; request.headers = { ...request.headers, - 'customdata': this.contentProtectionConfiguration.integrationParameters.token + 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata }; return request; } @@ -41,7 +41,7 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; request.headers = { ...request.headers, - 'customdata': this.contentProtectionConfiguration.integrationParameters.token + 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata }; const licenseParameters = `spc=${window.THEOplayer.utils.base64.encode(request.body!)}&assetId=${this.contentId}`; request.body = new TextEncoder().encode(licenseParameters); diff --git a/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts index 753acbad..382539ac 100644 --- a/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts @@ -13,7 +13,7 @@ export class KeyOSDrmPlayReadyContentProtectionIntegration implements ContentPro constructor(configuration: KeyOSDrmConfiguration) { if (!isKeyOSDrmDRMConfiguration(configuration)) { - throw new Error('The KeyOS token has not been correctly configured.'); + throw new Error('The KeyOS customdata value has not been correctly configured.'); } this.contentProtectionConfiguration = configuration; } @@ -25,7 +25,7 @@ export class KeyOSDrmPlayReadyContentProtectionIntegration implements ContentPro request.url = this.contentProtectionConfiguration.playready?.licenseAcquisitionURL; request.headers = { ...request.headers, - 'customdata': this.contentProtectionConfiguration.integrationParameters.token + 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata }; return request; } diff --git a/web/src/integration/keyos/KeyOSDrmUtils.ts b/web/src/integration/keyos/KeyOSDrmUtils.ts index 8d4508c7..6d01f6ea 100644 --- a/web/src/integration/keyos/KeyOSDrmUtils.ts +++ b/web/src/integration/keyos/KeyOSDrmUtils.ts @@ -1,7 +1,7 @@ import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; export function isKeyOSDrmDRMConfiguration(configuration: KeyOSDrmConfiguration): boolean { - return configuration.integrationParameters.token !== undefined; + return configuration.integrationParameters.customdata !== undefined; } export function extractContentId(skdUrl: string): string { @@ -10,6 +10,5 @@ export function extractContentId(skdUrl: string): string { } var link = document.createElement('a'); link.href = skdUrl; - console.log(link.hostname, skdUrl) return link.hostname; } \ No newline at end of file diff --git a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts index 9e8f8d8e..bcec7949 100644 --- a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts @@ -25,7 +25,7 @@ export class KeyOSDrmWidevineContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL; request.headers = { ...request.headers, - 'customdata': this.contentProtectionConfiguration.integrationParameters.token + 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata }; return request; } diff --git a/web/test/keyos/fairplay.html b/web/test/keyos/fairplay.html index 86893f94..8dbd9836 100644 --- a/web/test/keyos/fairplay.html +++ b/web/test/keyos/fairplay.html @@ -19,7 +19,7 @@ }); THEOplayer.registerContentProtectionIntegration( - 'keyos', + 'keyos_buydrm', 'fairplay', new ContentProtectionIntegrations.KeyOSDrmFairplayContentProtectionIntegrationFactory() ); @@ -28,15 +28,16 @@ sources: [ { src: 'insert manifest url here', + type: 'application/x-mpegurl', contentProtection: { + integration: 'keyos_buydrm', fairplay: { certificateURL: 'insert certificate url here', licenseAcquisitionURL: 'insert license url here' }, preferredKeySystems: ['fairplay', 'widevine', 'playready'], - integration: 'keyos', integrationParameters: { - token: 'insert token here', + customdata: 'insert customdata here', } } } diff --git a/web/test/keyos/playready.html b/web/test/keyos/playready.html index c5271f0f..9e5e8489 100644 --- a/web/test/keyos/playready.html +++ b/web/test/keyos/playready.html @@ -19,7 +19,7 @@ }); THEOplayer.registerContentProtectionIntegration( - 'keyos', + 'keyos_buydrm', 'playready', new ContentProtectionIntegrations.KeyOSDrmPlayReadyContentProtectionIntegrationFactory() ); @@ -28,14 +28,15 @@ sources: [ { src: 'insert manifest url here', + type: 'application/dash+xml', contentProtection: { - integration: 'keyos', + integration: 'keyos_buydrm', playready: { licenseAcquisitionURL: 'insert license url here', }, preferredKeySystems: ['playready', 'widevine', 'fairplay'], integrationParameters: { - token: 'insert token here' + customdata: 'insert customdata here' } } } diff --git a/web/test/keyos/widevine.html b/web/test/keyos/widevine.html index e900f0bc..cfab8f92 100644 --- a/web/test/keyos/widevine.html +++ b/web/test/keyos/widevine.html @@ -19,7 +19,7 @@ }); THEOplayer.registerContentProtectionIntegration( - 'keyos', + 'keyos_buydrm', 'widevine', new ContentProtectionIntegrations.KeyOSDrmWidevineContentProtectionIntegrationFactory() ); @@ -28,14 +28,15 @@ sources: [ { src: 'insert manifest url here', + type: 'application/dash+xml', contentProtection: { - integration: 'keyos', + integration: 'keyos_buydrm', widevine: { licenseAcquisitionURL: 'insert license url here' }, preferredKeySystems: ['widevine', 'playready', 'fairplay'], integrationParameters: { - token: 'insert token here' + customdata: 'insert customdata here' } } } From fbec6ec68fa50035e2e6f86b389193d6b7d87231 Mon Sep 17 00:00:00 2001 From: Thijs Date: Wed, 19 May 2021 09:11:23 -0400 Subject: [PATCH 18/85] Add initial Verimatrix MultiDRM Core DRM (#9) Co-authored-by: thijsl --- web/README.md | 1 + web/src/index.ts | 5 +- .../VerimatrixDrmConfiguration.ts | 17 ++++++ ...DrmFairPlayContentProtectionIntegration.ts | 55 +++++++++++++++++++ ...PlayContentProtectionIntegrationFactory.ts | 12 ++++ web/test/verimatrixcoredrm/fairplay.html | 49 +++++++++++++++++ web/test/verimatrixcoredrm/playready.html | 43 +++++++++++++++ web/test/verimatrixcoredrm/widevine.html | 43 +++++++++++++++ 8 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixDrmConfiguration.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory.ts create mode 100644 web/test/verimatrixcoredrm/fairplay.html create mode 100644 web/test/verimatrixcoredrm/playready.html create mode 100644 web/test/verimatrixcoredrm/widevine.html diff --git a/web/README.md b/web/README.md index fc63d073..d2f42fbf 100644 --- a/web/README.md +++ b/web/README.md @@ -179,6 +179,7 @@ passed during registration, an instance of `CustomContentProtectionIntegration` - Nagra DRM - BuyDRM KeyOS - Comcast DRM +- Verimatrix MultiDRM Core DRM ### Testing an integration diff --git a/web/src/index.ts b/web/src/index.ts index 30a15148..86b5e9e9 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -36,6 +36,8 @@ import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from "./integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory"; import {KeyOSDrmPlayReadyContentProtectionIntegrationFactory} from "./integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory"; +import { VerimatrixDrmFairPlayContentProtectionIntegrationFactory } from + './integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory'; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -56,5 +58,6 @@ export { NagraDrmFairPlayContentProtectionIntegrationFactory, KeyOSDrmWidevineContentProtectionIntegrationFactory, KeyOSDrmFairplayContentProtectionIntegrationFactory, - KeyOSDrmPlayReadyContentProtectionIntegrationFactory + KeyOSDrmPlayReadyContentProtectionIntegrationFactory, + VerimatrixDrmFairPlayContentProtectionIntegrationFactory }; diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmConfiguration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmConfiguration.ts new file mode 100644 index 00000000..e5bffbe3 --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixDrmConfiguration.ts @@ -0,0 +1,17 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Verimatrix Core DRM integration. + */ +export type VerimatrixIntegrationID = 'verimatrixcore'; + +/** + * Describes the configuration of the Verimatrix Core DRM integration. + */ +export interface VerimatrixDrmConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: VerimatrixIntegrationID; +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts new file mode 100644 index 00000000..26812bc6 --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts @@ -0,0 +1,55 @@ +import { + BufferSource, + ContentProtectionIntegration, + LicenseRequest, + LicenseResponse, + MaybeAsync, + utils +} from 'THEOplayer'; +import { VerimatrixDrmConfiguration } from './VerimatrixDrmConfiguration'; + +export class VerimatrixDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: VerimatrixDrmConfiguration; + private contentId: string | undefined = undefined; + + static readonly DEFAULT_FAIRPLAY_LICENSE_URL = 'https://multidrm.vsaas.verimatrixcloud.net/fairplay'; + + constructor(configuration: VerimatrixDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + let spcMessage = utils.base64.encode(new Uint8Array(request.body!)); + let body = { + "spc": spcMessage + }; + let newBody = new TextEncoder().encode(JSON.stringify(body)); + const newRequest = { + ...request, + url: this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? + VerimatrixDrmFairPlayContentProtectionIntegration.DEFAULT_FAIRPLAY_LICENSE_URL, + headers: { + 'Content-Type': 'application/json' + }, + body: newBody + }; + return newRequest; + + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + const responseAsText = new TextDecoder().decode(response.body); + const responseObject = JSON.parse(responseAsText); + return Uint8Array.from(atob(responseObject.ckc), c => c.charCodeAt(0)).buffer; + } + + extractFairplayContentId(skdUrl: string): string { + if (skdUrl.indexOf("skd") > 0 || skdUrl.indexOf("http") > 0) { + skdUrl = skdUrl.substring(1); + } + const link = document.createElement('a'); + link.href = skdUrl; + this.contentId = link.hostname; + return this.contentId; + } +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..7cf4553c --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { VerimatrixDrmConfiguration } from './VerimatrixDrmConfiguration'; +import { VerimatrixDrmFairPlayContentProtectionIntegration } from './VerimatrixDrmFairPlayContentProtectionIntegration'; + +export class VerimatrixDrmFairPlayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: VerimatrixDrmConfiguration): ContentProtectionIntegration { + return new VerimatrixDrmFairPlayContentProtectionIntegration(configuration); + } +} diff --git a/web/test/verimatrixcoredrm/fairplay.html b/web/test/verimatrixcoredrm/fairplay.html new file mode 100644 index 00000000..beaefc56 --- /dev/null +++ b/web/test/verimatrixcoredrm/fairplay.html @@ -0,0 +1,49 @@ + + + + + Verimatrix Core DRM FairPlay Test + + + + + +
+ + + diff --git a/web/test/verimatrixcoredrm/playready.html b/web/test/verimatrixcoredrm/playready.html new file mode 100644 index 00000000..604ee032 --- /dev/null +++ b/web/test/verimatrixcoredrm/playready.html @@ -0,0 +1,43 @@ + + + + + Verimatrix Core DRM PlayReady Test + + + + +
+ + + diff --git a/web/test/verimatrixcoredrm/widevine.html b/web/test/verimatrixcoredrm/widevine.html new file mode 100644 index 00000000..326f82a4 --- /dev/null +++ b/web/test/verimatrixcoredrm/widevine.html @@ -0,0 +1,43 @@ + + + + + Verimatrix Core DRM Widevine Test + + + + +
+ + + From 881eddf65d59b660df560b630ff0e666febf19d0 Mon Sep 17 00:00:00 2001 From: theoplayerSupport <39338186+theoplayerSupport@users.noreply.github.com> Date: Fri, 18 Jun 2021 19:24:49 +0200 Subject: [PATCH 19/85] add buydrm keyos samples for android and ios (#10) Co-authored-by: Wonne Joosen --- android/.gitignore | 1 + .../SourceManager.java | 20 +++++ ...sWidevineContentProtectionIntegration.java | 31 +++++++ ...neContentProtectionIntegrationFactory.java | 15 ++++ .../project.pbxproj | 36 +++++++-- .../AppDelegate.swift | 2 + .../ViewController.swift | 10 +-- .../integration/KeyOsDRMIntegration.swift | 81 +++++++++++++++++++ 8 files changed, 183 insertions(+), 13 deletions(-) create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.java create mode 100644 ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift diff --git a/android/.gitignore b/android/.gitignore index 603b1407..941bab58 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -10,5 +10,6 @@ .DS_Store /build /captures +/app/libs .externalNativeBuild .cxx diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java index 45db4934..178e9b73 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java @@ -7,6 +7,7 @@ import com.theoplayer.android.api.source.SourceDescription; import com.theoplayer.android.api.source.drm.DRMConfiguration; import com.theoplayer.contentprotectionintegration.integration.azuredrm.AzureWidevineContentProtectionIntegrationFactory; +import com.theoplayer.contentprotectionintegration.integration.keyos.KeyOsWidevineContentProtectionIntegrationFactory; import com.theoplayer.contentprotectionintegration.integration.vudrm.VudrmWidevineContentProtectionIntegrationFactory; import java.util.HashMap; @@ -96,6 +97,25 @@ private void initSources(Context context) { ) ); + // BuyDRM KeyOS Widevine content protect integration + String KEYOS_ID = "buydrm-keyos"; + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + KEYOS_ID, + KeySystemId.WIDEVINE, + new KeyOsWidevineContentProtectionIntegrationFactory() + ); + sources.put( + "BuyDRM KeyOs Widevine", + buildWidevineSourceDescription( + KEYOS_ID, + "", + new HashMap() {{ + put("customdata", "insert_customdata_here"); + }} + ) + ); + // add other registrations & sources here ... } } diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java new file mode 100644 index 00000000..0fdad631 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java @@ -0,0 +1,31 @@ +package com.theoplayer.contentprotectionintegration.integration.keyos; + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; +import com.theoplayer.android.api.contentprotection.Request; +import com.theoplayer.android.api.source.drm.DRMConfiguration; + +public class KeyOsWidevineContentProtectionIntegration extends ContentProtectionIntegration { + private final DRMConfiguration contentProtectionConfiguration; + + public KeyOsWidevineContentProtectionIntegration(DRMConfiguration configuration) { + this.contentProtectionConfiguration = configuration; + } + + @Override + public void onLicenseRequest(Request request, LicenseRequestCallback callback) { + + if (this.contentProtectionConfiguration.getWidevine() == null) { + throw new NullPointerException("The license acquisition URL can not be null"); + } + + request.setUrl(contentProtectionConfiguration.getWidevine().getLicenseAcquisitionURL()); + request.getHeaders().put( + "customdata", + contentProtectionConfiguration.getIntegrationParameters().get("customdata").toString() + ); + callback.request(request); + + } + +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.java new file mode 100644 index 00000000..0f7c049b --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.java @@ -0,0 +1,15 @@ +package com.theoplayer.contentprotectionintegration.integration.keyos; + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; +import com.theoplayer.android.api.source.drm.DRMConfiguration; +import com.theoplayer.contentprotectionintegration.integration.keyos.KeyOsWidevineContentProtectionIntegration; + +public class KeyOsWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + @Override + public ContentProtectionIntegration build(DRMConfiguration configuration) { + return new KeyOsWidevineContentProtectionIntegration(configuration); + } +} + + diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj index 0c2bf196..f8dc4330 100644 --- a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj +++ b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj @@ -7,6 +7,13 @@ objects = { /* Begin PBXBuildFile section */ + 620E3EA0267CF4910049F3FF /* KeyOsDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */; }; + 620E3EA3267CF6590049F3FF /* THEOplayerSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA2267CF6590049F3FF /* THEOplayerSDK.framework */; }; + 620E3EA4267CF6590049F3FF /* THEOplayerSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA2267CF6590049F3FF /* THEOplayerSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 620E3EA7267CF6C70049F3FF /* GoogleCast.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA6267CF6C70049F3FF /* GoogleCast.framework */; }; + 620E3EA8267CF6C70049F3FF /* GoogleCast.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA6267CF6C70049F3FF /* GoogleCast.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 620E3EAA267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA9267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework */; }; + 620E3EAB267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA9267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */; }; D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */; }; D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */; }; @@ -17,18 +24,18 @@ E279FE4125139E4700EC0EFA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE3F25139E4700EC0EFA /* Main.storyboard */; }; E279FE4325139E4900EC0EFA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4225139E4900EC0EFA /* Assets.xcassets */; }; E279FE4625139E4900EC0EFA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */; }; - E279FE4F25139EBA00EC0EFA /* THEOplayerSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */; }; - E279FE5025139EBA00EC0EFA /* THEOplayerSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ - E279FE5125139EBA00EC0EFA /* Embed Frameworks */ = { + 620E3EA5267CF6590049F3FF /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - E279FE5025139EBA00EC0EFA /* THEOplayerSDK.framework in Embed Frameworks */, + 620E3EAB267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework in Embed Frameworks */, + 620E3EA8267CF6C70049F3FF /* GoogleCast.framework in Embed Frameworks */, + 620E3EA4267CF6590049F3FF /* THEOplayerSDK.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -36,6 +43,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyOsDRMIntegration.swift; sourceTree = ""; }; + 620E3EA2267CF6590049F3FF /* THEOplayerSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = THEOplayerSDK.framework; path = ContentProtectionIntegration/THEOplayerSDK.framework; sourceTree = ""; }; + 620E3EA6267CF6C70049F3FF /* GoogleCast.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleCast.framework; path = ContentProtectionIntegration/GoogleCast.framework; sourceTree = ""; }; + 620E3EA9267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleInteractiveMediaAds.framework; path = ContentProtectionIntegration/GoogleInteractiveMediaAds.framework; sourceTree = ""; }; D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VuDRMIntegration.swift; sourceTree = ""; }; D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UplynkDRMIntegration.swift; sourceTree = ""; }; D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDRMIntegration.swift; sourceTree = ""; }; @@ -56,7 +67,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E279FE4F25139EBA00EC0EFA /* THEOplayerSDK.framework in Frameworks */, + 620E3EAA267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework in Frameworks */, + 620E3EA7267CF6C70049F3FF /* GoogleCast.framework in Frameworks */, + 620E3EA3267CF6590049F3FF /* THEOplayerSDK.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -98,6 +111,9 @@ E279FE4D25139EBA00EC0EFA /* Frameworks */ = { isa = PBXGroup; children = ( + 620E3EA9267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework */, + 620E3EA6267CF6C70049F3FF /* GoogleCast.framework */, + 620E3EA2267CF6590049F3FF /* THEOplayerSDK.framework */, E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */, ); name = Frameworks; @@ -107,6 +123,7 @@ isa = PBXGroup; children = ( D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */, + 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */, D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */, D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */, D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */, @@ -124,7 +141,7 @@ E279FE3225139E4700EC0EFA /* Sources */, E279FE3325139E4700EC0EFA /* Frameworks */, E279FE3425139E4700EC0EFA /* Resources */, - E279FE5125139EBA00EC0EFA /* Embed Frameworks */, + 620E3EA5267CF6590049F3FF /* Embed Frameworks */, ); buildRules = ( ); @@ -192,6 +209,7 @@ D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */, E279FE3A25139E4700EC0EFA /* AppDelegate.swift in Sources */, D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */, + 620E3EA0267CF4910049F3FF /* KeyOsDRMIntegration.swift in Sources */, E279FE3C25139E4700EC0EFA /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -342,6 +360,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", + "$(PROJECT_DIR)/ContentProtectionIntegration", ); INFOPLIST_FILE = ContentProtectionIntegration/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -350,7 +369,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = theoplayer.ContentProtectionIntegration; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development theoplayer.*"; + PROVISIONING_PROFILE_SPECIFIER = "match Development theoplayer.* 1613572623"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -366,6 +385,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", + "$(PROJECT_DIR)/ContentProtectionIntegration", ); INFOPLIST_FILE = ContentProtectionIntegration/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -374,7 +394,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = theoplayer.ContentProtectionIntegration; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development theoplayer.*"; + PROVISIONING_PROFILE_SPECIFIER = "match Development theoplayer.* 1613572623"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/ios/ContentProtectionIntegration/AppDelegate.swift b/ios/ContentProtectionIntegration/AppDelegate.swift index efa393a3..65e88528 100644 --- a/ios/ContentProtectionIntegration/AppDelegate.swift +++ b/ios/ContentProtectionIntegration/AppDelegate.swift @@ -21,6 +21,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { THEOplayer.registerContentProtectionIntegration(integrationId: AzureDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: AzureDRMIntegrationFactory()) THEOplayer.registerContentProtectionIntegration(integrationId: EzdrmDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: EzdrmDRMIntegrationFactory()) + + THEOplayer.registerContentProtectionIntegration(integrationId: KeyOsDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: KeyOsDRMIntegrationFactory()) return true } diff --git a/ios/ContentProtectionIntegration/ViewController.swift b/ios/ContentProtectionIntegration/ViewController.swift index 6a09efff..4fc69994 100644 --- a/ios/ContentProtectionIntegration/ViewController.swift +++ b/ios/ContentProtectionIntegration/ViewController.swift @@ -30,13 +30,13 @@ class ViewController: UIViewController { var sampleSource: SourceDescription { return SourceDescription( source: TypedSource( - src: "", + src: "your stream url", type: "application/x-mpegurl", drm: FairPlayDRMConfiguration( - customIntegrationId: UplynkDRMIntegration.integrationID, - licenseAcquisitionURL: "", - certificateURL: "", - integrationParameters: [:] + customIntegrationId: KeyOsDRMIntegration.integrationID, + licenseAcquisitionURL: "your license acquisition url", + certificateURL: "your certificate url", + integrationParameters: ["customdata":"your custom data"] ) ) ) diff --git a/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift new file mode 100644 index 00000000..4a3f279d --- /dev/null +++ b/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift @@ -0,0 +1,81 @@ +// +// KeyOsDRMIntegration.swift +// ContentProtectionIntegration +// +// Created by Wonne Joosen on 18/06/2021. +// Copyright © 2021 THEOplayer. All rights reserved. +// + +import Foundation +import THEOplayerSDK + +class KeyOsDRMIntegration: ContentProtectionIntegration { + static let integrationID = "customkeyosDRM" + var configuration: DRMConfiguration + + var contentId: String? + + init(configuration: DRMConfiguration) { + self.configuration = configuration + } + + func extractFairplayContentId(skdUrl: String) -> String { + let components = skdUrl.components(separatedBy: "?") + let skd = components.last! + self.contentId = skd.replacingOccurrences(of: "skd://", with: "") + return skd + } + + func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { + request.headers.updateValue(self.getCustomdataFromDrmConfiguration(), forKey: "customdata") + callback.request(request: request) + + } + + func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { + callback.respond(certificate: response.body) + } + + + func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { + guard let contentId = self.contentId else { + fatalError("contentID was nil.") + } + + request.headers.updateValue(self.getCustomdataFromDrmConfiguration(), forKey: "customdata") + + if let body64 = request.body?.base64EncodedString() { + let body = "spc=\(body64)&assetId=\(contentId)" + request.body = body.data(using: .utf8)! + callback.request(request: request) + } else { + fatalError("RequestBody was nil.") + } + } + + func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { + guard var licenseBody = String(data: response.body, encoding: .utf8) else { + fatalError("Could not create a string from the reponseBody provided.") + } + licenseBody = licenseBody.replacingOccurrences(of: "", with: "") + licenseBody = licenseBody.replacingOccurrences(of: "", with: "") + if let data = Data(base64Encoded: licenseBody) { + callback.respond(license: data) + } else { + fatalError("Could not create a Data Object from the responseBody provided.") + } + } + + private func getCustomdataFromDrmConfiguration() -> String { + guard let customdata = self.configuration.integrationParameters?["customdata"] as? String else { + fatalError("Could not find the customdata value in the integrationParameters.") + } + return customdata + } +} + +class KeyOsDRMIntegrationFactory: ContentProtectionIntegrationFactory { + func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { + return KeyOsDRMIntegration(configuration: configuration) + } +} From a199f1d901d32dfdad7e3221db5b98d95bb706d4 Mon Sep 17 00:00:00 2001 From: Thijs Date: Mon, 2 Aug 2021 13:43:44 -0400 Subject: [PATCH 20/85] Castlabs multikey (#11) * Add initial CastLabs multikey attempt. Not yet functional. * updated CastLabs sample code * Clean up CastLabs FairPlay integration (remove logs, ...) * Add examples for Widevine and PlayReady that use the "hardcoded" DRM Today integration. Co-authored-by: thijsl Co-authored-by: Daniel Dallos --- web/src/index.ts | 5 +- .../castlabs/CastLabsDrmConfiguration.ts | 45 +++++++++++++++ ...DrmFairPlayContentProtectionIntegration.ts | 57 +++++++++++++++++++ ...PlayContentProtectionIntegrationFactory.ts | 12 ++++ .../integration/castlabs/CastLabsDrmUtils.ts | 7 +++ web/test/castlabs/fairplay.html | 57 +++++++++++++++++++ web/test/castlabs/playready.html | 45 +++++++++++++++ web/test/castlabs/widevine.html | 45 +++++++++++++++ 8 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 web/src/integration/castlabs/CastLabsDrmConfiguration.ts create mode 100644 web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts create mode 100644 web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/castlabs/CastLabsDrmUtils.ts create mode 100644 web/test/castlabs/fairplay.html create mode 100644 web/test/castlabs/playready.html create mode 100644 web/test/castlabs/widevine.html diff --git a/web/src/index.ts b/web/src/index.ts index 86b5e9e9..b29b8171 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -22,6 +22,8 @@ import { ComcastDrmWidevineContentProtectionIntegrationFactory } from './integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory'; import { ComcastDrmFairPlayContentProtectionIntegrationFactory } from './integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory'; +import { CastLabsDrmFairPlayContentProtectionIntegrationFactory } from + './integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory'; import { IrdetoControlFairplayContentProtectionIntegrationFactory} from './integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory'; import { NagraDrmWidevineContentProtectionIntegrationFactory } from @@ -59,5 +61,6 @@ export { KeyOSDrmWidevineContentProtectionIntegrationFactory, KeyOSDrmFairplayContentProtectionIntegrationFactory, KeyOSDrmPlayReadyContentProtectionIntegrationFactory, - VerimatrixDrmFairPlayContentProtectionIntegrationFactory + VerimatrixDrmFairPlayContentProtectionIntegrationFactory, + CastLabsDrmFairPlayContentProtectionIntegrationFactory }; diff --git a/web/src/integration/castlabs/CastLabsDrmConfiguration.ts b/web/src/integration/castlabs/CastLabsDrmConfiguration.ts new file mode 100644 index 00000000..8fbdb71c --- /dev/null +++ b/web/src/integration/castlabs/CastLabsDrmConfiguration.ts @@ -0,0 +1,45 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Comcast DRM integration. + */ +export type DRMTodayIntegrationID = 'castlabs'; + +/** + * Describes the configuration of the Comcast DRM integration. + */ +export interface CastLabsDrmConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: DRMTodayIntegrationID; + + /** + * An object of key/value pairs which can be used to pass in specific parameters related to a source into a + * ContentProtectionIntegration. + */ + integrationParameters: { + + /** + * The Comcast Release Pid. + * + *
- This releasePid will be used for the license request. + */ + merchant: string; + + /** + * The Comcast Account ID. + * + *
- This account will be used for the license request. + */ + sessionId: string; + + /** + * The Comcast Token. + * + *
- This token will be used for the license request. + */ + userId: string; + } +} diff --git a/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts new file mode 100644 index 00000000..153e2792 --- /dev/null +++ b/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts @@ -0,0 +1,57 @@ +import { + BufferSource, CertificateRequest, + ContentProtectionIntegration, + LicenseRequest, + LicenseResponse, + utils, + MaybeAsync +} from 'THEOplayer'; +import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; +import { unwrapCkc } from '../../utils/FairplayUtils'; + + +export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: CastLabsDrmConfiguration; + private contentId: string | undefined = undefined; + private generatedToken: string; + + constructor(configuration: CastLabsDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + const jsonString = JSON.stringify({ + userId: this.contentProtectionConfiguration.integrationParameters.userId, + sessionId: this.contentProtectionConfiguration.integrationParameters.sessionId, + merchant: this.contentProtectionConfiguration.integrationParameters.merchant + }); + const base64String = btoa(jsonString); + this.generatedToken = base64String; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + 'dt-custom-data': this.generatedToken! + }; + return request + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + 'content-type': 'application/x-www-form-urlencoded', + 'dt-custom-data': this.generatedToken!, + }; + const body = `spc=${encodeURIComponent(utils.base64.encode(new Uint8Array(request.body!)))}&${encodeURIComponent(this.contentId!)}`; + request.body = new TextEncoder().encode(body); + return request; + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + return unwrapCkc(response.body); + } + + + extractFairplayContentId(skdUrl: string): string { + this.contentId = skdUrl + return this.contentId; + } +} diff --git a/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts b/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..17ddca07 --- /dev/null +++ b/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; +import { CastLabsDrmFairPlayContentProtectionIntegration } from './CastLabsDrmFairPlayContentProtectionIntegration'; + +export class CastLabsDrmFairPlayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: CastLabsDrmConfiguration): ContentProtectionIntegration { + return new CastLabsDrmFairPlayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/castlabs/CastLabsDrmUtils.ts b/web/src/integration/castlabs/CastLabsDrmUtils.ts new file mode 100644 index 00000000..2c2f4da5 --- /dev/null +++ b/web/src/integration/castlabs/CastLabsDrmUtils.ts @@ -0,0 +1,7 @@ +import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; + +export function isDCastLabsDrmDRMConfiguration(configuration: CastLabsDrmConfiguration): boolean { + return (configuration.integrationParameters.merchant !== undefined && + configuration.integrationParameters.sessionId !== undefined && + configuration.integrationParameters.userId !== undefined); +} \ No newline at end of file diff --git a/web/test/castlabs/fairplay.html b/web/test/castlabs/fairplay.html new file mode 100644 index 00000000..94c2e43f --- /dev/null +++ b/web/test/castlabs/fairplay.html @@ -0,0 +1,57 @@ + + + + + CastLabs FairPlay Test + + + + + +
+ + + diff --git a/web/test/castlabs/playready.html b/web/test/castlabs/playready.html new file mode 100644 index 00000000..982541ba --- /dev/null +++ b/web/test/castlabs/playready.html @@ -0,0 +1,45 @@ + + + + + CastLabs PlayReady Test + + + + +

This example uses the integration documented at https://docs.theoplayer.com/how-to-guides/04-drm/02-castlabs-drmtoday/00-introduction.md.

+
+ + + diff --git a/web/test/castlabs/widevine.html b/web/test/castlabs/widevine.html new file mode 100644 index 00000000..6c439217 --- /dev/null +++ b/web/test/castlabs/widevine.html @@ -0,0 +1,45 @@ + + + + + CastLabs Widevine Test + + + + +

This example uses the integration documented at https://docs.theoplayer.com/how-to-guides/04-drm/02-castlabs-drmtoday/00-introduction.md.

+
+ + + From 34583876377733a0e1174180dd95c6b613cd27a0 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Tue, 17 Aug 2021 14:40:59 +0200 Subject: [PATCH 21/85] Update top-level README --- README.md | 57 ++++++++++++++++++++++-- resources/custom_drm_integration_seq.svg | 3 ++ 2 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 resources/custom_drm_integration_seq.svg diff --git a/README.md b/README.md index feb84b9a..4a72822c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,60 @@ # THEOplayer DRM integrations -This repository contains a subset of the current integrated DRM integrations of THEOplayer. They serve as an example for integrating -with the THEOplayer DRM API. +### Table of contents -### Table of Contents +1. [Introduction](#introduction) +2. [DRM flow](#drm-flow) +3. [DRM integration API](#drm-integration-api) +4. [Getting started](#getting-started) + +### Introduction + +A detailed explanation on why DRM (Digital Rights Management) is necessary, and how it works, can +be found in THEOplayer's [knowledge base](https://docs.theoplayer.com/knowledge-base/02-content-protection/00-introduction.md). +For the purpose of the integration examples in this repository we will first briefly explain some key +concepts being used in the process of requesting a decryption key, or the *DRM flow*. + +### DRM flow + +The examples in this repository are grouped per platform, but they share a common overall DRM flow. +Whenever the player encounters encrypted content, it will need a *decryption or license key* to decrypt the content +before it can be played. +This key is requested from a license server by means of a *license acquisition request*. +The actual decryption is done by the *CDM (Content Decryption Module)*, a hardware or software +component external to the player, which creates (part of) the request body (the challenge) to send to the +server, and takes the resulting key from the response. + +Optionally, the license request is preceded by a *certificate request*. The certificate is then used +to encrypt certain parts of the license request itself. + +So in the whole DRM process the player just mediates and passes through information between the license +server and the CDM. The details of this communication is very specific to the type of DRM +being used and the DRM vendor, however. Handling the way the license requests and response bodies are +formatted, or wrapped with additional information, is called the *DRM integration*. +Due the vast diversity of integrations a DRM Integration API and this sample repository were created. + +### DRM integration API + +THEOplayer supports Fairplay, PlayReady and Widevine by default. In many cases however, developers +are working with a multi-DRM vendor that requires a tailored integration approach. +THEOplayer already includes a large number of pre-integrated solutions through partnerships with multi-DRM vendors. +In addition, because there is no one-fits-all approach, an API is available that allows to build a custom +DRM integrations. It gives the possibility to alter the DRM process by hooking into key points of the DRM +flow, such as right before creating certificate and license request bodies, or right after +receiving the responses. + +The sequence diagram below depicts a simplified version the DRM flow and how a custom integration can intervene +at certain key points. + +![Custom DRM integration sequence diagram](./resources/custom_drm_integration_seq.svg) + +This repository contains a number of such DRM flows that are already pre-integrated in THEOplayer, +but rewritten as a custom DRM integration. They serve as examples for integrating with the +THEOplayer Content Protection API. + +More information on the integration process can be found in the [how-to guide](https://docs.theoplayer.com/how-to-guides/04-drm/00-introduction.md). + +### Getting started - [Getting started on Web](web/README.md) - [Getting started on Android](android/README.md) - [Getting started on iOS](ios/README.md) diff --git a/resources/custom_drm_integration_seq.svg b/resources/custom_drm_integration_seq.svg new file mode 100644 index 00000000..7a245b31 --- /dev/null +++ b/resources/custom_drm_integration_seq.svg @@ -0,0 +1,3 @@ + + +
opt
opt
CDM
CDM
THEOplayer
THEOplayer
License
Server
License...
request certificate
request certificate
certificate response
certificate response
generate key request
generate key request
ContentProtection
Integration
ContentProtection...
onCertificateRequest()
onCertificateRequest()
altered request
altered request
Content
Server
Content...
encrypted
content
encrypted...
onCertificateResponse()
onCertificateResponse()
altered response
altered response
onLicenseRequest()
onLicenseRequest()
altered request
altered request
request license
request license
license response
license response
onLicenseResponse()
onLicenseResponse()
altered response
altered response
key request
key request
set license key
set license key
decrypt content
decrypt content
Viewer does not support full SVG 1.1
\ No newline at end of file From 9a388fd7c58b288f3b8b6ba8498734dfde89a81f Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Tue, 17 Aug 2021 17:54:02 +0200 Subject: [PATCH 22/85] Update Android readme --- android/README.md | 127 ++++++++++++++++++++++- resources/android_custom_drm_classes.svg | 3 + 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 resources/android_custom_drm_classes.svg diff --git a/android/README.md b/android/README.md index 75c48a06..e0f78fde 100644 --- a/android/README.md +++ b/android/README.md @@ -1,5 +1,32 @@ ## Getting started on Android +### Table of contents + +1. [Overview](#overview) +2. [Creating a new integration](#creating-a-new-integration) +3. [Request and Response types](#request-and-response-types) +4. [Available examples](#available-examples) +5. [Testing an integration](#testing-an-integration) +6. [Conclusion](#conclusion) + +### Overview + +This document provides a step-by-step approach on how to create a custom DRM integration with the THEOplayer Android SDK. +It gives an overview of which classes are involved and how they participate in the DRM flow. + +The project's top-level [README](../README.md) elaborates on what it means to create a DRM integration, gives a brief +platform-independent overview of the flow, and clarifies the terminology being used throughout the document. Make sure +to familiarise yourself with it before starting your own implementation. + +The static class diagram below depicts classes that are part of the SDK in white, while coloured classes need to be +implemented when creating a custom integration. The `ContentProtectionIntegrationFactory` subclass is only used once +by THEOplayer to create an instance of a `ContentProtectedIntegration` subclass. The latter contains the actual hook methods +being referred to in the DRM integration [sequence diagram](../README.md#drm-integration-api). + +![Custom DRM integration class diagram](../resources/android_custom_drm_classes.svg) + +In the next section a custom integration is built by implementing both subclasses. + ### Creating a new integration First create a custom implementation of [ContentProtectionIntegration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/android/latest/com/theoplayer/android/api/contentprotection/ContentProtectionIntegration.html) @@ -39,8 +66,21 @@ public class CustomContentProtectionIntegration extends ContentProtectionIntegra } public void onLicenseRequest(Request request, LicenseRequestCallback callback) { + // Optionally apply integration parameters, such as a token, which are passed when setting the source, or + // add additional header fields. // final Object token = this.contentProtectionConfiguration.getIntegrationParameters().get("token"); // request.getHeaders().put("x-token", token.toString()); + // request.getHeaders().put("Content-Type", "text/plain"); + + // If required by the DRM provider, wrap or transform the request body. + // JSONObject jsonBody = new JSONObject(); + // try { + // jsonBody.put("drm_info", TypeUtils.fromByteArrayToUint8JsonArray(request.getBody())); + // } catch (JSONException e) { + // e.printStackTrace(); + // } + // request.setBody(TypeUtils.fromJsonToByteArray(jsonBody)); + callback.request(request); } @@ -140,19 +180,104 @@ public class SourceManager { ).build(); } } -``` +``` Finally, build and run the app on an Android device or Android emulator. +### Request and Response types + +Manipulating certificate and license requests and responses requires special care. Next to adding header +fields or changing the target url, the body of the `Request` most often needs to be transformed or wrapped +before passing it along. + +```java +public class Request { + @NonNull + public String getUrl(); + public void setUrl(@NonNull String url); + + @NonNull + public RequestMethod getMethod(); + public void setMethod(@NonNull RequestMethod method); + + @NonNull + public Map getHeaders(); + public void setHeaders(@NonNull Map headers); + + @Nullable + public byte[] getBody(); + public void setBody(@Nullable byte[] body); +} +``` + +A `Request` object expects the body to be an array of `byte`. In case of a license request it originally contains the +challenge generated by the CDM. +A common way of passing extra data to the server is by wrapping the raw request body +in a JSON object with some additional properties, which is then transformed back into the required type `byte[]`. The following +example is taken from the [VuDRM integration sample](app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java): + +```java +JSONObject jsonBody = new JSONObject(); +try { + jsonBody.put("token", token); + jsonBody.put("drm_info", TypeUtils.fromByteArrayToUint8JsonArray(request.getBody())); + jsonBody.put("kid", kid); +} catch (JSONException e) { + e.printStackTrace(); +} +request.setBody(jsonBody.toString().getBytes()); +``` +where the `fromByteArrayToUint8JsonArray` helper method creates a JSON array from a `byte[]` object. + +Similarly, the `Response` object returned from the server contains among others the response headers and the response +body. The latter is again an array of `byte`, containing the certificate or license that will be passed to the CDM. + +```java +public interface Response { + @NonNull + Request getRequest(); + + @NonNull + String getUrl(); + + int getStatus(); + + @NonNull + String getStatusText(); + + @NonNull + Map getHeaders(); + + @Nullable + byte[] getBody(); +} +``` + +Depending on the DRM integration, the response body either already is a raw certificate or license that can be passed along as-is, +or needs to be transformed or unwrapped first in a way similar to the request body. + ### Available examples +The repository already contains a few integration examples that could be used as a starting point. + - Vualto VuDRM - Microsoft Azure DRM +- KeyOS ### Testing an integration +Make sure to apply the following steps before testing your custom integration. If a problem persists, please +reach out to THEOplayer [customer support](https://www.theoplayer.com/contact). + - Add your THEOplayer Android Archive (AAR) into the [/android/app/libs/]() folder and rename it to `theoplayer.aar`. - Depending on the features included in your THEOplayer build, include the necessary dependencies in `/android/app/build.gradle`. - Open the `/android` folder in [Android Studio](https://developer.android.com/studio) and build the project. - Make sure to fill in the necessary fields in `SourceManager` for the content integration that will be tested, such as the manifest url and any integration parameters. - Attach either a physical Android device or start an Android emulator, and run the project. + +### Conclusion + +This document showed how to create a custom DRM integration for Android using THEOplayer's Content Integration API, +and register it with THEOplayer. The Android integration API can slightly differ on other platforms, so it is best +to check the platform's specific document. + diff --git a/resources/android_custom_drm_classes.svg b/resources/android_custom_drm_classes.svg new file mode 100644 index 00000000..a6531968 --- /dev/null +++ b/resources/android_custom_drm_classes.svg @@ -0,0 +1,3 @@ + + +«interface»ContentProtectionIntegration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()«interface»ContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)CustomContentProtectionIntegration+ configuration: DRMConfiguration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()CustomContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)
creates
creates
DRMConfiguration+ customIntegrationId: String+ integrationParameters: Map<String, String>
Viewer does not support full SVG 1.1
\ No newline at end of file From a2b2ac55964df366e5c019be4c336156b142acd5 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 1 Sep 2021 09:28:41 +0200 Subject: [PATCH 23/85] Extract helper methods --- .../TypeUtils.java | 24 +++++++++++++++++++ ...sWidevineContentProtectionIntegration.java | 2 -- ...mWidevineContentProtectionIntegration.java | 16 +++---------- 3 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.java diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.java new file mode 100644 index 00000000..6cb41b29 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.java @@ -0,0 +1,24 @@ +package com.theoplayer.contentprotectionintegration; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class TypeUtils { + /** + * Convert an array of bytes to a JSONArray object. + */ + public static JSONArray fromByteArrayToUint8JsonArray(final byte[] bytes) { + JSONArray jsonArray = new JSONArray(); + for (byte aByte : bytes) { + jsonArray.put(aByte & 0xff); + } + return jsonArray; + } + + /** + * Convert a JSON object to an array of bytes. + */ + public static byte[] fromJsonToByteArray(final JSONObject jsonObject) { + return jsonObject.toString().getBytes(); + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java index 0fdad631..ae8035c8 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java @@ -25,7 +25,5 @@ public void onLicenseRequest(Request request, LicenseRequestCallback callback) { contentProtectionConfiguration.getIntegrationParameters().get("customdata").toString() ); callback.request(request); - } - } diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java index 82f050b9..b37cb690 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java @@ -1,14 +1,12 @@ package com.theoplayer.contentprotectionintegration.integration.vudrm; import com.theoplayer.android.api.contentprotection.CertificateRequestCallback; -import com.theoplayer.android.api.contentprotection.CertificateResponseCallback; import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; import com.theoplayer.android.api.contentprotection.Request; -import com.theoplayer.android.api.contentprotection.Response; import com.theoplayer.android.api.source.drm.DRMConfiguration; +import com.theoplayer.contentprotectionintegration.TypeUtils; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -42,12 +40,12 @@ private Request wrapRequest(Request request) { JSONObject jsonBody = new JSONObject(); try { jsonBody.put("token", token); - jsonBody.put("drm_info", toUint8JsonArray(request.getBody())); + jsonBody.put("drm_info", TypeUtils.fromByteArrayToUint8JsonArray(request.getBody())); jsonBody.put("kid", kid); } catch (JSONException e) { e.printStackTrace(); } - request.setBody(jsonBody.toString().getBytes()); + request.setBody(TypeUtils.fromJsonToByteArray(jsonBody)); return request; } @@ -66,12 +64,4 @@ public void onLicenseRequest(final Request request, LicenseRequestCallback callb callback.error(error); } } - - private JSONArray toUint8JsonArray(final byte [] bytes) { - JSONArray jsonArray = new JSONArray(); - for (byte aByte : bytes) { - jsonArray.put(aByte & 0xff); - } - return jsonArray; - } } From 06ef5bbadb7ba42d1aff4ae9121d2f5732403ea3 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 1 Sep 2021 15:47:23 +0200 Subject: [PATCH 24/85] Update web README --- resources/web_custom_drm_classes.svg | 3 + web/README.md | 115 +++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 resources/web_custom_drm_classes.svg diff --git a/resources/web_custom_drm_classes.svg b/resources/web_custom_drm_classes.svg new file mode 100644 index 00000000..61705608 --- /dev/null +++ b/resources/web_custom_drm_classes.svg @@ -0,0 +1,3 @@ + + +«interface»ContentProtectionIntegration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()«interface»ContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)CustomContentProtectionIntegration+ configuration: DRMConfiguration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()CustomContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)
creates
creates
DRMConfiguration+ customIntegrationId: string+ integrationParameters: { [name: string]: any }
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/web/README.md b/web/README.md index d2f42fbf..1d95cd46 100644 --- a/web/README.md +++ b/web/README.md @@ -1,5 +1,33 @@ ## Getting started on Web +### Table of contents + +1. [Overview](#overview) +2. [Creating a new integration](#creating-a-new-integration) +3. [Request and Response types](#request-and-response-types) +4. [Hook return types](#hook-return-types) +5. [Available examples](#available-examples) +6. [Testing an integration](#testing-an-integration) +7. [Conclusion](#conclusion) + +### Overview + +This document provides a step-by-step approach on how to create a custom DRM integration with the THEOplayer Web SDK. +It gives an overview of which classes are involved and how they participate in the DRM flow. + +The project's top-level [README](../README.md) elaborates on what it means to create a DRM integration, gives a brief +platform-independent overview of the flow, and clarifies the terminology being used throughout the document. Make sure +to familiarise yourself with it before starting your own implementation. + +The static class diagram below depicts classes that are part of the SDK in white, while coloured classes need to be +implemented when creating a custom integration. The `ContentProtectionIntegrationFactory` subclass is only used once +by THEOplayer to create an instance of a `ContentProtectedIntegration` subclass. The latter contains the actual hook methods +being referred to in the DRM integration [sequence diagram](../README.md#drm-integration-api). + +![Custom DRM integration class diagram](../resources/web_custom_drm_classes.svg) + +In the next section a custom integration is built by implementing both subclasses. + ### Creating a new integration First create a custom implementation of [ContentProtectionIntegration](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.contentprotectionintegration.md) @@ -169,16 +197,87 @@ passed during registration, an instance of `CustomContentProtectionIntegration` ``` +### Request and Response types + +Manipulating certificate and license requests and responses requires special care. Next to adding header +fields or changing the target url, the body of the `ContentProtectionRequest` most often needs to be transformed or wrapped +before passing it along. + +```javascript +interface ContentProtectionRequest { + url: string; + method: string; + headers: { [headerName: string]: string }; + body: Uint8Array | null; + useCredentials: boolean; +} + +interface LicenseRequest extends ContentProtectionRequest { + // Only available for Fairplay license requests. The value will be `undefined` otherwise. + fairplaySkdUrl: string | undefined; +} + +declare type CertificateRequest = ContentProtectionRequest; +``` + +A `ContentProtectionRequest` object expects the body to be a `Uint8Array`. +In case of a license request it originally contains the challenge generated by the CDM. +A common way of passing extra data to the server is by wrapping the raw request body +in an object with some additional properties, which is then transformed back into the required type `Uint8Array`. +The following example is taken from the [VuDRM Widevine integration sample](./src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts): + +```javascript +private wrapRequestBody(body: Uint8Array): Uint8Array { + const token = this.contentProtectionConfiguration.integrationParameters.token; + const drmInfo = fromUint8ArrayToNumberArray(body); + const kid = this.contentProtectionConfiguration.integrationParameters.keyId; + return fromObjectToUint8Array({ token, drm_info: drmInfo, kid }); +} +``` +where `fromUint8ArrayToNumberArray` and `fromObjectToUint8Array` are helper methods transforming variables to different +representations. + +Similarly, the `ContentProtectionResponse` object returned from the server contains among others the response headers and the response +body. The latter is again an array of `Uint8Array`, containing the certificate or license that will be passed to the CDM. + +```javascript +public interface ContentProtectionResponse { + request: ContentProtectionRequest; + url: string; + status: number; + statusText: string; + headers: { [headerName: string]: string }; + body: Uint8Array; +} +``` + +Depending on the DRM integration, the response body either already is a raw certificate or license that can be passed along as-is, +or needs to be transformed or unwrapped first in a way similar to the request body. + +### Hook return types + +The return types of both `onCertificateRequest()` and `onLicenseRequest()` hooks are defined as +`MaybeAsync | BufferSource>` and `MaybeAsync | BufferSource>` +respectively. This gives the flexibility to either return the optionally modified request, without the need to specify all properties +(i.e. `Partial`), or a raw certificate or license. In the latter case, the request is skipped entirely and the certificate or +license is used directly. + +`BufferSource` is defined as the union type `BufferSource = ArrayBufferView | ArrayBuffer`. + +For the `onCertificateResponse()` and `onLicenseResponse()` hooks the return type is defined as +`MaybeAsync`, meaning they are expected to return the raw certificate or license. + ### Available examples -- Vualto VuDRM -- EZDRM (only for Fairplay, as Widevine and PlayReady can use the default implementation) -- Microsoft Azure DRM - Axinom DRM +- Microsoft Azure DRM +- CastLabs DRMtoday +- Comcast DRM +- EZDRM (only for Fairplay, as Widevine and PlayReady can use the default implementation) - Irdeto Control -- Nagra DRM - BuyDRM KeyOS -- Comcast DRM +- Nagra DRM +- Vualto VuDRM - Verimatrix MultiDRM Core DRM ### Testing an integration @@ -188,3 +287,9 @@ library `THEOplayer.js`, the declaration file `THEOplayer.d.ts` with all exporte - Run `npm install && npm run build` in the root folder to create the integrations library `bundle.js` under `dist/`. - Start http-server in the root folder by running `npm run server`. - Go to `localhost:8080/test/[integration you want to test]`. + +### Conclusion + +This document showed how to create a custom DRM integration for Web using THEOplayer's Content Integration API, +and register it with THEOplayer. The Web integration API can slightly differ on other platforms, so it is best +to check the platform's specific document. From cdcd3c3137b26e40c292cf595a8152a1167e10be Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Fri, 3 Sep 2021 12:13:15 +0200 Subject: [PATCH 25/85] Extract conversion methods --- ...DrmFairplayContentProtectionIntegration.ts | 6 +-- ...rmPlayReadyContentProtectionIntegration.ts | 2 +- ...DrmWidevineContentProtectionIntegration.ts | 2 +- ...DrmFairPlayContentProtectionIntegration.ts | 15 +++---- ...DrmFairPlayContentProtectionIntegration.ts | 18 +++++--- ...DrmWidevineContentProtectionIntegration.ts | 21 ++++----- ...rolFairplayContentProtectionIntegration.ts | 4 +- ...DrmFairplayContentProtectionIntegration.ts | 13 ++++-- ...DrmFairPlayContentProtectionIntegration.ts | 3 +- ...DrmFairPlayContentProtectionIntegration.ts | 8 ++-- ...drmFairplayContentProtectionIntegration.ts | 5 ++- ...drmWidevineContentProtectionIntegration.ts | 7 +-- web/src/utils/FairplayUtils.ts | 6 +-- web/src/utils/TypeUtils.ts | 45 +++++++++++++++++++ 14 files changed, 105 insertions(+), 50 deletions(-) create mode 100644 web/src/utils/TypeUtils.ts diff --git a/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts b/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts index a9890e9a..d8ddc9f8 100644 --- a/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts +++ b/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts @@ -5,11 +5,11 @@ import { LicenseRequest, LicenseResponse, MaybeAsync, - utils } from 'THEOplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; import { extractContentId, unwrapCkc } from '../../utils/FairplayUtils'; +import { fromStringToUint8Array, fromUint8ArrayToBase64String } from "../../utils/TypeUtils"; export class AzureDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: AzureDrmConfiguration; @@ -46,8 +46,8 @@ export class AzureDrmFairplayContentProtectionIntegration implements ContentProt if (!this.contentId) { throw new Error('The FairPlay AzureDRM content ID has not been correctly configured.'); } - const licenseParameters = `spc=${encodeURIComponent(utils.base64.encode(new Uint8Array(request.body!)))}&assetId=${encodeURIComponent(this.contentId)}`; - request.body = new TextEncoder().encode(licenseParameters); + const licenseParameters = `spc=${encodeURIComponent(fromUint8ArrayToBase64String(request.body!))}&assetId=${encodeURIComponent(this.contentId)}`; + request.body = fromStringToUint8Array(licenseParameters); return request; } diff --git a/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts index d51215ab..f1428483 100644 --- a/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts +++ b/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts @@ -12,7 +12,7 @@ export class AzureDrmPlayReadyContentProtectionIntegration implements ContentPro private readonly contentProtectionConfiguration: AzureDrmConfiguration; constructor(configuration: AzureDrmConfiguration) { - if(!isAzureDrmDRMConfiguration(configuration)){ + if (!isAzureDrmDRMConfiguration(configuration)) { throw new Error('The PlayReady AzureDRM token has not been correctly configured.'); } this.contentProtectionConfiguration = configuration; diff --git a/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts b/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts index 4864c000..6cffc91c 100644 --- a/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts +++ b/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts @@ -12,7 +12,7 @@ export class AzureDrmWidevineContentProtectionIntegration implements ContentProt private readonly contentProtectionConfiguration: AzureDrmConfiguration; constructor(configuration: AzureDrmConfiguration) { - if(!isAzureDrmDRMConfiguration(configuration)){ + if (!isAzureDrmDRMConfiguration(configuration)) { throw new Error('The Widevine AzureDRM token has not been correctly configured.'); } this.contentProtectionConfiguration = configuration; diff --git a/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts index 153e2792..547ed272 100644 --- a/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts @@ -3,12 +3,11 @@ import { ContentProtectionIntegration, LicenseRequest, LicenseResponse, - utils, MaybeAsync } from 'THEOplayer'; import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; import { unwrapCkc } from '../../utils/FairplayUtils'; - +import { fromObjectToBase64String, fromStringToUint8Array, fromUint8ArrayToBase64String } from "../../utils/TypeUtils"; export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: CastLabsDrmConfiguration; @@ -17,13 +16,12 @@ export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentP constructor(configuration: CastLabsDrmConfiguration) { this.contentProtectionConfiguration = configuration; - const jsonString = JSON.stringify({ + const jsonObj = { userId: this.contentProtectionConfiguration.integrationParameters.userId, sessionId: this.contentProtectionConfiguration.integrationParameters.sessionId, merchant: this.contentProtectionConfiguration.integrationParameters.merchant - }); - const base64String = btoa(jsonString); - this.generatedToken = base64String; + }; + this.generatedToken = fromObjectToBase64String(jsonObj); } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { @@ -40,8 +38,8 @@ export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentP 'content-type': 'application/x-www-form-urlencoded', 'dt-custom-data': this.generatedToken!, }; - const body = `spc=${encodeURIComponent(utils.base64.encode(new Uint8Array(request.body!)))}&${encodeURIComponent(this.contentId!)}`; - request.body = new TextEncoder().encode(body); + const body = `spc=${encodeURIComponent(fromUint8ArrayToBase64String(request.body!))}&${encodeURIComponent(this.contentId!)}`; + request.body = fromStringToUint8Array(body); return request; } @@ -49,7 +47,6 @@ export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentP return unwrapCkc(response.body); } - extractFairplayContentId(skdUrl: string): string { this.contentId = skdUrl return this.contentId; diff --git a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts index d3661790..c522b362 100644 --- a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -4,11 +4,16 @@ import { LicenseRequest, LicenseResponse, MaybeAsync, - utils } from 'THEOplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; import { extractContentId } from '../../utils/FairplayUtils'; +import { + fromBase64StringToString, + fromObjectToUint8Array, + fromUint8ArrayToBase64String, + fromUint8ArrayToObject, +} from "../../utils/TypeUtils"; export class ComcastDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: ComcastDrmConfiguration; @@ -26,8 +31,8 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { throw new Error('The FairPlay ComcastDRM license url has not been correctly configured.'); } - const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; - let spcMessage = utils.base64.encode(new Uint8Array(request.body!)); + const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; + let spcMessage = fromUint8ArrayToBase64String(request.body!); let body = { "getFairplayLicense": { "releasePid": releasePid, @@ -35,7 +40,7 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr } }; - let newBody = new TextEncoder().encode(JSON.stringify(body)); + let newBody = fromObjectToUint8Array(body); return { ...request, url: request.url + `&token=${token}&account=${account}&form=json`, @@ -48,9 +53,8 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - const responseAsText = new TextDecoder().decode(response.body); - const responseObject = JSON.parse(responseAsText); - return Uint8Array.from(atob(responseObject.getFairplayLicenseResponse.ckcResponse), c => c.charCodeAt(0)).buffer; + const responseObject = fromUint8ArrayToObject(response.body); + return Uint8Array.from(fromBase64StringToString(responseObject.getFairplayLicenseResponse.ckcResponse), c => c.charCodeAt(0)).buffer; } extractFairplayContentId(skdUrl: string): string { diff --git a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts index 4b896aa9..8b0b674a 100644 --- a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts +++ b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts @@ -2,25 +2,26 @@ import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, - BufferSource, utils, LicenseResponse, CertificateRequest, CertificateResponse + BufferSource, LicenseResponse, CertificateRequest, CertificateResponse } from 'THEOplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; +import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToString } from "../../utils/TypeUtils"; export class ComcastDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: ComcastDrmConfiguration; constructor(configuration: ComcastDrmConfiguration) { - if(!isComcastDrmDRMConfiguration(configuration)){ + if (!isComcastDrmDRMConfiguration(configuration)) { throw new Error('The Widevine AzureDRM token has not been correctly configured.'); } this.contentProtectionConfiguration = configuration; } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; - let widevineChallenge = utils.base64.encode(new Uint8Array(request.body!)); + const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; + let widevineChallenge = fromUint8ArrayToBase64String(request.body!); let body = { "getWidevineLicense": { "releasePid": releasePid, @@ -30,12 +31,12 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr return { ...request, url: request.url + `&token=${token}&account=${account}`, - body: new TextEncoder().encode(JSON.stringify(body)) + body: fromObjectToUint8Array(body) }; } onCertificateResponse(response: CertificateResponse): MaybeAsync { - const responseAsText = new TextDecoder().decode(response.body); + const responseAsText = fromUint8ArrayToString(response.body); const responseObject = JSON.parse(responseAsText); return Uint8Array.from(atob(responseObject.getWidevineLicenseResponse.license), c => c.charCodeAt(0)).buffer; @@ -45,8 +46,8 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { throw new Error('The Widevine AzureDRM license url has not been correctly configured.'); } - const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; - let widevineChallenge = utils.base64.encode(new Uint8Array(request.body!)); + const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; + let widevineChallenge = fromUint8ArrayToBase64String(request.body!); let body = { "getWidevineLicense": { "releasePid": releasePid, @@ -56,12 +57,12 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr return { ...request, url: request.url + `&token=${token}&account=${account}`, - body: new TextEncoder().encode(JSON.stringify(body)) + body: fromObjectToUint8Array(body) }; } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - const responseAsText = new TextDecoder().decode(response.body); + const responseAsText = fromUint8ArrayToString(response.body); const responseObject = JSON.parse(responseAsText); return Uint8Array.from(atob(responseObject.getWidevineLicenseResponse.license), c => c.charCodeAt(0)).buffer; } diff --git a/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts b/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts index 92d7200f..bcbc8c91 100644 --- a/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts +++ b/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts @@ -67,7 +67,7 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten return skdUrl; } - hasQueryParameter(url : string, parameter: string) : Boolean { + hasQueryParameter(url: string, parameter: string): Boolean { const queryParameters = url.split("?"); if (!queryParameters || !queryParameters[1]) { return false; @@ -82,7 +82,7 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten return false; } - appendQueryParameter(url: string, key: string, value: string | undefined) : string { + appendQueryParameter(url: string, key: string, value: string | undefined): string { const queryParameters = url.split("?"); if (!queryParameters || !queryParameters[1]) { return (url + "?" + key + "=" + value); diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts index 85b536cc..ea4df3d8 100644 --- a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -7,6 +7,11 @@ import { } from 'THEOplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; import { isKeyOSDrmDRMConfiguration, extractContentId } from "./KeyOSDrmUtils"; +import { + fromBase64StringToUint8Array, fromStringToUint8Array, + fromUint8ArrayToBase64String, + fromUint8ArrayToUtf8String +} from "../../utils/TypeUtils"; export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { @@ -43,18 +48,18 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt ...request.headers, 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata }; - const licenseParameters = `spc=${window.THEOplayer.utils.base64.encode(request.body!)}&assetId=${this.contentId}`; - request.body = new TextEncoder().encode(licenseParameters); + const licenseParameters = `spc=${fromUint8ArrayToBase64String(request.body!)}&assetId=${this.contentId}`; + request.body = fromStringToUint8Array(licenseParameters); return request; } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - let bodyAsString = new TextDecoder('utf-8').decode(response.body) + let bodyAsString = fromUint8ArrayToUtf8String(response.body) let keyText = bodyAsString.trim() if (keyText.substr(0, 5) === '' && keyText.substr(-6) === '') { keyText = keyText.slice(5, -6) } - return window.THEOplayer.utils.base64.decode(keyText) + return fromBase64StringToUint8Array(keyText) } extractFairplayContentId(skdUrl: string): string { diff --git a/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts index 210ff5f5..0dc8df13 100644 --- a/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts @@ -8,6 +8,7 @@ import { } from 'THEOplayer'; import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; import { isNagraDrmDRMConfiguration } from "./NagraDrmUtils"; +import { fromUint8ArrayToString } from "../../utils/TypeUtils"; export class NagraDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { @@ -60,7 +61,7 @@ export class NagraDrmFairPlayContentProtectionIntegration } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - var responseAsText = new TextDecoder().decode(response.body); + var responseAsText = fromUint8ArrayToString(response.body); var responseCkcMessage = JSON.parse(responseAsText)["CkcMessage"]; var raw = window.atob(responseCkcMessage); var rawLength = raw.length; diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts index 26812bc6..1780cc57 100644 --- a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts @@ -4,9 +4,9 @@ import { LicenseRequest, LicenseResponse, MaybeAsync, - utils } from 'THEOplayer'; import { VerimatrixDrmConfiguration } from './VerimatrixDrmConfiguration'; +import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToString } from '../../utils/TypeUtils'; export class VerimatrixDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: VerimatrixDrmConfiguration; @@ -19,11 +19,11 @@ export class VerimatrixDrmFairPlayContentProtectionIntegration implements Conten } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - let spcMessage = utils.base64.encode(new Uint8Array(request.body!)); + let spcMessage = fromUint8ArrayToBase64String(request.body!); let body = { "spc": spcMessage }; - let newBody = new TextEncoder().encode(JSON.stringify(body)); + let newBody = fromObjectToUint8Array(body); const newRequest = { ...request, url: this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? @@ -38,7 +38,7 @@ export class VerimatrixDrmFairPlayContentProtectionIntegration implements Conten } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - const responseAsText = new TextDecoder().decode(response.body); + const responseAsText = fromUint8ArrayToString(response.body); const responseObject = JSON.parse(responseAsText); return Uint8Array.from(atob(responseObject.ckc), c => c.charCodeAt(0)).buffer; } diff --git a/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts b/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts index e6bb8477..392fe164 100644 --- a/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts +++ b/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts @@ -8,6 +8,7 @@ import { import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; import { extractContentId } from '../../utils/FairplayUtils'; +import { fromObjectToUint8Array, fromUint8ArrayToBase64String } from '../../utils/TypeUtils'; export class VudrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { @@ -41,13 +42,13 @@ export class VudrmFairplayContentProtectionIntegration implements ContentProtect const licenseParameters = { token: this.contentProtectionConfiguration.integrationParameters.token, contentId: this.contentId, - payload: utils.base64.encode(new Uint8Array(request.body!)) + payload: fromUint8ArrayToBase64String(request.body!) }; request.headers = { 'Content-Type': 'application/json', 'x-vudrm-token': this.contentProtectionConfiguration.integrationParameters.token } - request.body = new TextEncoder().encode((JSON.stringify(licenseParameters))); + request.body = fromObjectToUint8Array(licenseParameters); return request; } diff --git a/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts b/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts index bee39656..774ba292 100644 --- a/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts +++ b/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts @@ -6,6 +6,7 @@ import { } from 'THEOplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; +import { fromObjectToUint8Array, fromUint8ArrayToNumberArray } from '../../utils/TypeUtils'; export class VudrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { @@ -20,11 +21,11 @@ export class VudrmWidevineContentProtectionIntegration implements ContentProtect this.contentProtectionConfiguration = configuration; } - private wrapRequestBody(body: Uint8Array) { + private wrapRequestBody(body: Uint8Array): Uint8Array { const token = this.contentProtectionConfiguration.integrationParameters.token; - const drmInfo = Array.from(new Uint8Array(body)); + const drmInfo = fromUint8ArrayToNumberArray(body); const kid = this.contentProtectionConfiguration.integrationParameters.keyId; - return new TextEncoder().encode((JSON.stringify({ token, drm_info: drmInfo, kid }))); + return fromObjectToUint8Array({token, drm_info: drmInfo, kid}); } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { diff --git a/web/src/utils/FairplayUtils.ts b/web/src/utils/FairplayUtils.ts index d0f9d9c3..ca584f17 100644 --- a/web/src/utils/FairplayUtils.ts +++ b/web/src/utils/FairplayUtils.ts @@ -1,4 +1,4 @@ -import { utils } from "THEOplayer"; +import { fromBase64StringToUint8Array, fromUint8ArrayToString } from "./TypeUtils"; export function extractContentId(skdUrl: string): string { const questionMarkIndex = skdUrl.indexOf('?'); @@ -11,9 +11,9 @@ export function extractContentId(skdUrl: string): string { } export function unwrapCkc(data: Uint8Array): Uint8Array { - let license = new TextDecoder().decode(data).trim(); + let license = fromUint8ArrayToString(data).trim(); if ('' === license.substr(0, 5) && '' === license.substr(-6)) { license = license.slice(5, -6); } - return utils.base64.decode(license); + return fromBase64StringToUint8Array(license); } diff --git a/web/src/utils/TypeUtils.ts b/web/src/utils/TypeUtils.ts new file mode 100644 index 00000000..38c9d2a0 --- /dev/null +++ b/web/src/utils/TypeUtils.ts @@ -0,0 +1,45 @@ +import { utils } from 'THEOplayer'; + +export function fromObjectToUint8Array(obj: {[key: string]: any}): Uint8Array { + return new TextEncoder().encode(JSON.stringify(obj)); +} + +export function fromObjectToBase64String(obj: {[key: string]: any}): string { + return fromStringToBase64String(JSON.stringify(obj)); +} + +export function fromStringToUint8Array(str: string): Uint8Array { + return new TextEncoder().encode(str); +} + +export function fromStringToBase64String(str: string): string { + return btoa(str); +} + +export function fromBase64StringToString(str: string): string { + return atob(str); +} + +export function fromUint8ArrayToNumberArray(array: Uint8Array): number[] { + return Array.from(new Uint8Array(array)); +} + +export function fromUint8ArrayToBase64String(array: Uint8Array): string { + return utils.base64.encode(new Uint8Array(array)); +} + +export function fromBase64StringToUint8Array(str: string): Uint8Array { + return utils.base64.decode(str); +} + +export function fromUint8ArrayToString(array: Uint8Array): string { + return new TextDecoder().decode(array); +} + +export function fromUint8ArrayToObject(array: Uint8Array): {[key: string]: any} { + return JSON.parse(new TextDecoder().decode(array)); +} + +export function fromUint8ArrayToUtf8String(array: Uint8Array): string { + return new TextDecoder('utf-8').decode(array); +} From d95902037c1cd2e44c8e9ecd488f3ab08b1d0faa Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Fri, 3 Sep 2021 12:34:30 +0200 Subject: [PATCH 26/85] Refactor FairPlay licenseResponses --- ...DrmFairPlayContentProtectionIntegration.ts | 3 ++- ...DrmFairPlayContentProtectionIntegration.ts | 19 ++++++++----------- ...DrmFairPlayContentProtectionIntegration.ts | 13 +++++++++---- web/src/utils/TypeUtils.ts | 4 ++++ 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts index c522b362..05a03b5f 100644 --- a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -9,6 +9,7 @@ import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; import { extractContentId } from '../../utils/FairplayUtils'; import { + fromBase64StringToArrayBuffer, fromBase64StringToString, fromObjectToUint8Array, fromUint8ArrayToBase64String, @@ -54,7 +55,7 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr onLicenseResponse?(response: LicenseResponse): MaybeAsync { const responseObject = fromUint8ArrayToObject(response.body); - return Uint8Array.from(fromBase64StringToString(responseObject.getFairplayLicenseResponse.ckcResponse), c => c.charCodeAt(0)).buffer; + return fromBase64StringToArrayBuffer(responseObject.getFairplayLicenseResponse.ckcResponse); } extractFairplayContentId(skdUrl: string): string { diff --git a/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts index 0dc8df13..dd32f99f 100644 --- a/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts @@ -8,7 +8,11 @@ import { } from 'THEOplayer'; import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; import { isNagraDrmDRMConfiguration } from "./NagraDrmUtils"; -import { fromUint8ArrayToString } from "../../utils/TypeUtils"; +import { + fromBase64StringToArrayBuffer, + fromBase64StringToString, + fromUint8ArrayToObject, +} from "../../utils/TypeUtils"; export class NagraDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { @@ -61,19 +65,12 @@ export class NagraDrmFairPlayContentProtectionIntegration } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - var responseAsText = fromUint8ArrayToString(response.body); - var responseCkcMessage = JSON.parse(responseAsText)["CkcMessage"]; - var raw = window.atob(responseCkcMessage); - var rawLength = raw.length; - var array = new Uint8Array(new ArrayBuffer(rawLength)); - for (var i = 0; i < rawLength; i++) { - array[i] = raw.charCodeAt(i); - } - return array; + const responseObject = fromUint8ArrayToObject(response.body); + return fromBase64StringToArrayBuffer(responseObject.CkcMessage); } extractFairplayContentId(skdUrl: string): string { - this.contentId = window.atob(skdUrl.split("skd://")[1].split("?")[0]); + this.contentId = fromBase64StringToString(skdUrl.split("skd://")[1].split("?")[0]); return this.contentId; } } diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts index 1780cc57..18e634a3 100644 --- a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts @@ -6,7 +6,13 @@ import { MaybeAsync, } from 'THEOplayer'; import { VerimatrixDrmConfiguration } from './VerimatrixDrmConfiguration'; -import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToString } from '../../utils/TypeUtils'; +import { + fromBase64StringToArrayBuffer, + fromBase64StringToString, + fromObjectToUint8Array, + fromUint8ArrayToBase64String, fromUint8ArrayToObject, + fromUint8ArrayToString +} from '../../utils/TypeUtils'; export class VerimatrixDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: VerimatrixDrmConfiguration; @@ -38,9 +44,8 @@ export class VerimatrixDrmFairPlayContentProtectionIntegration implements Conten } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - const responseAsText = fromUint8ArrayToString(response.body); - const responseObject = JSON.parse(responseAsText); - return Uint8Array.from(atob(responseObject.ckc), c => c.charCodeAt(0)).buffer; + const responseObject = fromUint8ArrayToObject(response.body); + return fromBase64StringToArrayBuffer(responseObject.ckc); } extractFairplayContentId(skdUrl: string): string { diff --git a/web/src/utils/TypeUtils.ts b/web/src/utils/TypeUtils.ts index 38c9d2a0..a3b4df79 100644 --- a/web/src/utils/TypeUtils.ts +++ b/web/src/utils/TypeUtils.ts @@ -20,6 +20,10 @@ export function fromBase64StringToString(str: string): string { return atob(str); } +export function fromBase64StringToArrayBuffer(str: string): ArrayBuffer { + return Uint8Array.from(fromBase64StringToString(str), c => c.charCodeAt(0)).buffer; +} + export function fromUint8ArrayToNumberArray(array: Uint8Array): number[] { return Array.from(new Uint8Array(array)); } From abe0fc2c62f9928598289daa222ecbbbe5c20b3b Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Tue, 7 Sep 2021 14:12:27 +0200 Subject: [PATCH 27/85] Update iOS README --- ios/README.md | 122 +++++++++++++++++++++++++++ resources/ios_custom_drm_classes.svg | 3 + 2 files changed, 125 insertions(+) create mode 100644 resources/ios_custom_drm_classes.svg diff --git a/ios/README.md b/ios/README.md index faf3c49f..09bfd13e 100644 --- a/ios/README.md +++ b/ios/README.md @@ -1,5 +1,30 @@ ## Getting started on iOS +1. [Overview](#overview) +2. [Creating a new integration](#creating-a-new-integration) +3. [Request and Response types](#request-and-response-types) +4. [Available examples](#available-examples) +5. [Testing an integration](#testing-an-integration) +6. [Conclusion](#conclusion) + +### Overview + +This document provides a step-by-step approach on how to create a custom DRM integration with the THEOplayer iOS SDK. +It gives an overview of which classes are involved and how they participate in the DRM flow. + +The project's top-level [README](../README.md) elaborates on what it means to create a DRM integration, gives a brief +platform-independent overview of the flow, and clarifies the terminology being used throughout the document. Make sure +to familiarise yourself with it before starting your own implementation. + +The static class diagram below depicts classes that are part of the SDK in white, while coloured classes need to be +implemented when creating a custom integration. The `ContentProtectionIntegrationFactory` subclass is only used once +by THEOplayer to create an instance of a `ContentProtectedIntegration` subclass. The latter contains the actual hook methods +being referred to in the DRM integration [sequence diagram](../README.md#drm-integration-api). + +![Custom DRM integration class diagram](../resources/ios_custom_drm_classes.svg) + +In the next section a custom integration is built by implementing both subclasses. + ### Creating a new integration First create a custom implementation of [ContentProtectionIntegration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/ios/latest/External%20Content%20Protection%20integration%20API.html#/c:@M@THEOplayerSDK@objc(pl)ContentProtectionIntegration) @@ -115,6 +140,97 @@ var sampleSource: SourceDescription { ``` Finally, build and run the app on an iOS device. +### Request and Response types + +Manipulating certificate and license requests and responses requires special care. Next to adding header +fields or changing the target url, the bodies of `CertificateRequest` and`LicenseRequest` most often +need to be transformed or wrapped before passing it along. + +```objc +@objc public class CertificateRequest : THEOplayerSDK.Request { + @objc override public init( + url: String, + method: String, + headers: [String : String], + body: Data? + ) + required public init(from decoder: Decoder) throws +} + +@objc public class LicenseRequest : THEOplayerSDK.Request { + @objc public var fairplaySkdUrl: String? + @objc override public init( + url: String, + method: String, + headers: [String : String], + body: Data? + ) + @objc public init( + url: String, + method: String, + headers: [String : String], + body: Data?, + fairplaySkdUrl: String?, + useCredentials: Bool + ) +} +``` + +Both `CertificateRequest` and `LicenseRequest` objects expect the body to be of byte buffer type +[Data](https://developer.apple.com/documentation/foundation/data). +In case of a license request it originally contains the challenge generated by the CDM. +A common way of passing extra data to the server is by wrapping the raw request body +in a JSON object with some additional properties, which is then transformed back into the required type `Data`. The following +example in Swift is taken from the [VuDRM integration sample](ContentProtectionIntegration/integration/VuDRMIntegration.swift): + +```swift +var dict = [String: String]() +dict.updateValue(self.getTokenFromDrmConfiguration(), forKey: "token") +dict.updateValue(contentID, forKey: "contentId") +if let payload = fromDataToBase64String(data: request.body) { + dict.updateValue(payload, forKey: "payload") +} +do { + request.body = try JSONEncoder().encode(dict) + callback.request(request: request) +} catch let error { + fatalError(error.localizedDescription) +} +``` +where the `fromDataToBase64String` helper method creates a base64-encoded string from the request body. + +Similarly, `CertificateResponse` and `LicenseResponse` objects returned from the server contain among others the +response headers and the response body. +The latter is again of type [Data](https://developer.apple.com/documentation/foundation/data), +containing the certificate or license that will be passed to the CDM. + +```obj +@objc public class CertificateResponse : THEOplayerSDK.Response { + @objc public init( + certificateRequest: THEOplayerSDK.CertificateRequest, + url: String, + status: Int, + statusText: String, + headers: [String : String], + body: Data + ) +} + +@objc public class LicenseResponse : THEOplayerSDK.Response { + @objc public init( + licenseRequest: THEOplayerSDK.LicenseRequest, + url: String, + status: Int, + statusText: String, + headers: [String : String], + body: Data + ) +} +``` + +Depending on the DRM integration, the response body either already is a raw certificate or license that can be passed along as-is, +or needs to be transformed or unwrapped first in a way similar to the request body. + ### Available examples - Vualto VuDRM @@ -130,3 +246,9 @@ Finally, build and run the app on an iOS device. to your project. - Make sure to fill in the necessary fields `ViewController` for the content integration that will be tested, such as the manifest url and any integration parameters. - Attach an iOS device, and finally build and run the project. + +### Conclusion + +This document showed how to create a custom DRM integration for iOS using THEOplayer's Content Integration API, +and register it with THEOplayer. The iOS integration API can slightly differ on other platforms, so it is best +to check the platform's specific document. diff --git a/resources/ios_custom_drm_classes.svg b/resources/ios_custom_drm_classes.svg new file mode 100644 index 00000000..65a48221 --- /dev/null +++ b/resources/ios_custom_drm_classes.svg @@ -0,0 +1,3 @@ + + +«interface»ContentProtectionIntegration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()«interface»ContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)CustomContentProtectionIntegration+ configuration: DRMConfiguration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()CustomContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)
creates
creates
DRMConfiguration+ customIntegrationId: String+ integrationParameters: [String : Any]
Viewer does not support full SVG 1.1
\ No newline at end of file From ecc6d7163dcc91367c6e61a6b951213616816fd7 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Tue, 7 Sep 2021 14:24:47 +0200 Subject: [PATCH 28/85] Add conversion methods --- .../project.pbxproj | 4 ++++ .../TypeUtils.swift | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 ios/ContentProtectionIntegration/TypeUtils.swift diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj index f8dc4330..2ed6755a 100644 --- a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj +++ b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ E279FE4125139E4700EC0EFA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE3F25139E4700EC0EFA /* Main.storyboard */; }; E279FE4325139E4900EC0EFA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4225139E4900EC0EFA /* Assets.xcassets */; }; E279FE4625139E4900EC0EFA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */; }; + E2B43C8C26E791480048696B /* TypeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B43C8B26E791470048696B /* TypeUtils.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -60,6 +61,7 @@ E279FE4525139E4900EC0EFA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; E279FE4725139E4900EC0EFA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = THEOplayerSDK.framework; sourceTree = ""; }; + E2B43C8B26E791470048696B /* TypeUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TypeUtils.swift; path = "../../../samples-drm-integration-comcast/ios/ContentProtectionIntegration/TypeUtils.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -97,6 +99,7 @@ isa = PBXGroup; children = ( E279FE5225139F2000EC0EFA /* integration */, + E2B43C8B26E791470048696B /* TypeUtils.swift */, E279FE3925139E4700EC0EFA /* AppDelegate.swift */, E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */, E279FE3D25139E4700EC0EFA /* ViewController.swift */, @@ -206,6 +209,7 @@ D99BC03525A4679200AE24B0 /* EzdrmDRMIntegration.swift in Sources */, D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */, E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */, + E2B43C8C26E791480048696B /* TypeUtils.swift in Sources */, D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */, E279FE3A25139E4700EC0EFA /* AppDelegate.swift in Sources */, D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */, diff --git a/ios/ContentProtectionIntegration/TypeUtils.swift b/ios/ContentProtectionIntegration/TypeUtils.swift new file mode 100644 index 00000000..bd93e4a0 --- /dev/null +++ b/ios/ContentProtectionIntegration/TypeUtils.swift @@ -0,0 +1,24 @@ +// +// TypeUtils.swift +// ContentProtectionIntegration +// +// Copyright © 2020 THEOplayer. All rights reserved. +// + +import Foundation + +func fromUtf8StringToData(str: String) -> Data? { + return str.data(using: .utf8) +} + +func fromBase64StringToData(base64Encoded: String) -> Data? { + return Data(base64Encoded: base64Encoded) +} + +func fromDataToBase64String(data: Data?) -> String? { + return data?.base64EncodedString() +} + +func fromDataToUtf8String(data: Data) -> String? { + return String(data: data, encoding: .utf8) +} From 7f4dafa2e6d7874fdd8923f3ac73c4b053e20988 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Tue, 7 Sep 2021 14:25:25 +0200 Subject: [PATCH 29/85] Refactor to use conversion methods --- .../integration/AzureDRMIntegration.swift | 9 ++++----- .../integration/KeyOsDRMIntegration.swift | 9 ++++----- .../integration/UplynkDRMIntegration.swift | 4 ++-- .../integration/VuDRMIntegration.swift | 2 +- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift index 81916761..3ca073c3 100644 --- a/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift +++ b/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift @@ -45,9 +45,8 @@ class AzureDRMIntegration: ContentProtectionIntegration { "Authorization": "Bearer \(self.getTokenFromDrmConfiguration())", "Content-Type": "application/x-www-form-urlencoded" ] - if let body64 = request.body?.base64EncodedString() { - let body = "spc=\(body64)&assetId=\(contentId)" - request.body = body.data(using: .utf8)! + if let body64 = fromDataToBase64String(data: request.body) { + request.body = fromUtf8StringToData(str: "spc=\(body64)&assetId=\(contentId)") callback.request(request: request) } else { fatalError("RequestBody was nil.") @@ -55,12 +54,12 @@ class AzureDRMIntegration: ContentProtectionIntegration { } func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - guard var licenseBody = String(data: response.body, encoding: .utf8) else { + guard var licenseBody = fromDataToUtf8String(data: response.body) else { fatalError("Could not create a string from the reponseBody provided.") } licenseBody = licenseBody.replacingOccurrences(of: "", with: "") licenseBody = licenseBody.replacingOccurrences(of: "", with: "") - if let data = Data(base64Encoded: licenseBody) { + if let data = fromBase64StringToData(base64Encoded: licenseBody) { callback.respond(license: data) } else { fatalError("Could not create a Data Object from the responseBody provided.") diff --git a/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift index 4a3f279d..1ed72b18 100644 --- a/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift +++ b/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift @@ -44,9 +44,8 @@ class KeyOsDRMIntegration: ContentProtectionIntegration { request.headers.updateValue(self.getCustomdataFromDrmConfiguration(), forKey: "customdata") - if let body64 = request.body?.base64EncodedString() { - let body = "spc=\(body64)&assetId=\(contentId)" - request.body = body.data(using: .utf8)! + if let body64 = fromDataToBase64String(data: request.body) { + request.body = fromUtf8StringToData(str: "spc=\(body64)&assetId=\(contentId)") callback.request(request: request) } else { fatalError("RequestBody was nil.") @@ -54,12 +53,12 @@ class KeyOsDRMIntegration: ContentProtectionIntegration { } func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - guard var licenseBody = String(data: response.body, encoding: .utf8) else { + guard var licenseBody = fromDataToUtf8String(data: response.body) else { fatalError("Could not create a string from the reponseBody provided.") } licenseBody = licenseBody.replacingOccurrences(of: "", with: "") licenseBody = licenseBody.replacingOccurrences(of: "", with: "") - if let data = Data(base64Encoded: licenseBody) { + if let data = fromBase64StringToData(base64Encoded: licenseBody) { callback.respond(license: data) } else { fatalError("Could not create a Data Object from the responseBody provided.") diff --git a/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift index 261dbe23..6f12bcca 100644 --- a/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift +++ b/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift @@ -45,7 +45,7 @@ class UplynkDRMIntegration: ContentProtectionIntegration { let laURL = skdUrl.replacingOccurrences(of: "skd://", with: "https://") request.url = laURL var dict = [String: String]() - if let spc = request.body?.base64EncodedString() { + if let spc = fromDataToBase64String(data: request.body) { dict.updateValue(spc, forKey: "spc") } do { @@ -59,7 +59,7 @@ class UplynkDRMIntegration: ContentProtectionIntegration { func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { do { let dto = try JSONDecoder().decode(UplynkDRMLicenseResponse.self, from: response.body) - guard let responseBody = Data(base64Encoded: dto.ckc) else { + guard let responseBody = fromBase64StringToData(base64Encoded: dto.ckc) else { fatalError("Could not Decode base64Encoded ckc") } response.body = responseBody diff --git a/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift index d1128208..341f54ed 100644 --- a/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift +++ b/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift @@ -44,7 +44,7 @@ class VuDRMIntegration: ContentProtectionIntegration { var dict = [String: String]() dict.updateValue(self.getTokenFromDrmConfiguration(), forKey: "token") dict.updateValue(contentID, forKey: "contentId") - if let payload = request.body?.base64EncodedString() { + if let payload = fromDataToBase64String(data: request.body) { dict.updateValue(payload, forKey: "payload") } do { From 7d9fb7148d9fe046c502a709447efb02c3382033 Mon Sep 17 00:00:00 2001 From: Thijs Date: Fri, 18 Feb 2022 11:48:39 -0500 Subject: [PATCH 30/85] Feature/buydrm update 202202 (#15) * [ios] Use BuyDRM KeyOS stream by default in ViewController.swift, and use x-keyos-authorization instead of customdata in keyOsDRMIntegration. * [ios] Use Cocoapods instead of a manual SDK to load THEOplayer. * [android] Use Maven instead of a manual SDK to load THEOplayer. * [android] Use x-keyos-authorization instead of customdata in keyOsWidevineContentProtectionIntegration.java, and put a relevant stream in SourceManager.java. * [web] Use existing BuyDRM KeyOS stream in keyos test files, and use x-keyos-authorization instead of customdata for keyos. * Adjust customdata to x-keyos-authorization in playready.html * [web] Use NPM instead of a manual SDK to load THEOplayer * [web] Load a THEOplayer from src/index.ts in all web tests Co-authored-by: thijsl --- android/README.md | 2 +- android/app/build.gradle | 4 +- android/app/src/main/AndroidManifest.xml | 3 + .../SourceManager.java | 6 +- ...sWidevineContentProtectionIntegration.java | 4 +- android/build.gradle | 2 + .../project.pbxproj | 106 +++++++++++------- .../ViewController.swift | 14 ++- .../integration/KeyOsDRMIntegration.swift | 10 +- ios/Podfile | 11 ++ ios/README.md | 8 +- web/README.md | 3 +- web/package-lock.json | 100 +++++++++++++++++ web/package.json | 2 + web/rollup.config.js | 12 +- web/src/index.ts | 2 + .../keyos/KeyOSDrmConfiguration.ts | 2 +- ...DrmFairplayContentProtectionIntegration.ts | 4 +- ...rmPlayReadyContentProtectionIntegration.ts | 2 +- web/src/integration/keyos/KeyOSDrmUtils.ts | 2 +- ...DrmWidevineContentProtectionIntegration.ts | 2 +- web/test/axinomdrm/fairplay.html | 1 + web/test/axinomdrm/playready.html | 1 + web/test/axinomdrm/widevine.html | 1 + web/test/azuredrm/fairplay.html | 1 + web/test/azuredrm/playready.html | 1 + web/test/azuredrm/widevine.html | 1 + web/test/castlabs/fairplay.html | 1 + web/test/castlabs/playready.html | 1 + web/test/castlabs/widevine.html | 1 + web/test/comcastdrm/fairplay.html | 4 +- web/test/comcastdrm/playready.html | 4 +- web/test/comcastdrm/widevine.html | 4 +- web/test/ezdrm/fairplay.html | 3 +- web/test/irdetocontrol/fairplay.html | 3 +- web/test/irdetocontrol/playready.html | 3 +- web/test/irdetocontrol/widevine.html | 3 +- web/test/keyos/fairplay.html | 11 +- web/test/keyos/playready.html | 9 +- web/test/keyos/widevine.html | 9 +- web/test/nagradrm/fairplay.html | 1 + web/test/nagradrm/playready.html | 1 + web/test/nagradrm/widevine.html | 1 + web/test/verimatrixcoredrm/fairplay.html | 3 +- web/test/verimatrixcoredrm/playready.html | 3 +- web/test/verimatrixcoredrm/widevine.html | 3 +- web/test/vudrm/fairplay.html | 3 +- web/test/vudrm/playready.html | 3 +- web/test/vudrm/widevine.html | 3 +- 49 files changed, 284 insertions(+), 100 deletions(-) create mode 100644 ios/Podfile diff --git a/android/README.md b/android/README.md index e0f78fde..1dfaf519 100644 --- a/android/README.md +++ b/android/README.md @@ -269,9 +269,9 @@ The repository already contains a few integration examples that could be used as Make sure to apply the following steps before testing your custom integration. If a problem persists, please reach out to THEOplayer [customer support](https://www.theoplayer.com/contact). -- Add your THEOplayer Android Archive (AAR) into the [/android/app/libs/]() folder and rename it to `theoplayer.aar`. - Depending on the features included in your THEOplayer build, include the necessary dependencies in `/android/app/build.gradle`. - Open the `/android` folder in [Android Studio](https://developer.android.com/studio) and build the project. +- Ensure that a valid license key is entered in the `AndroidManifest.xml` instead of `"YOUR_LICENSE_HERE"`. More information is available at https://github.com/THEOplayer/theoplayer-sdk-android. - Make sure to fill in the necessary fields in `SourceManager` for the content integration that will be tested, such as the manifest url and any integration parameters. - Attach either a physical Android device or start an Android emulator, and run the project. diff --git a/android/app/build.gradle b/android/app/build.gradle index 16779101..4f7977be 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -6,7 +6,7 @@ android { defaultConfig { applicationId "com.theoplayer.contentprotectionintegration" - minSdkVersion 16 + minSdkVersion 21 targetSdkVersion 30 multiDexEnabled true } @@ -16,6 +16,6 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.1' implementation 'com.google.code.gson:gson:2.8.6' - implementation(name:'theoplayer', ext:'aar') + implementation 'com.theoplayer.theoplayer-sdk-android:basic-minapi21:+' implementation 'com.android.support:multidex:1.0.3' } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ac25b369..47e6ca60 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -12,6 +12,9 @@ android:supportsRtl="true" android:networkSecurityConfig="@xml/network_security_config" android:theme="@style/AppTheme"> + diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java index 178e9b73..9d684760 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java @@ -108,10 +108,10 @@ private void initSources(Context context) { "BuyDRM KeyOs Widevine", buildWidevineSourceDescription( KEYOS_ID, - "", + "https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd", + "https://wv-keyos.licensekeyserver.com", new HashMap() {{ - put("customdata", "insert_customdata_here"); + put("x-keyos-authorization", "PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg=="); }} ) ); diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java index ae8035c8..03c92c67 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java @@ -21,8 +21,8 @@ public void onLicenseRequest(Request request, LicenseRequestCallback callback) { request.setUrl(contentProtectionConfiguration.getWidevine().getLicenseAcquisitionURL()); request.getHeaders().put( - "customdata", - contentProtectionConfiguration.getIntegrationParameters().get("customdata").toString() + "x-keyos-authorization", + contentProtectionConfiguration.getIntegrationParameters().get("x-keyos-authorization").toString() ); callback.request(request); } diff --git a/android/build.gradle b/android/build.gradle index d72153a7..29ce391e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -11,6 +11,8 @@ buildscript { allprojects { repositories { google() + mavenCentral() + maven { url 'https://jitpack.io' } jcenter() flatDir { dirs 'libs' diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj index 2ed6755a..e6fbf660 100644 --- a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj +++ b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj @@ -3,17 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ 620E3EA0267CF4910049F3FF /* KeyOsDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */; }; - 620E3EA3267CF6590049F3FF /* THEOplayerSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA2267CF6590049F3FF /* THEOplayerSDK.framework */; }; - 620E3EA4267CF6590049F3FF /* THEOplayerSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA2267CF6590049F3FF /* THEOplayerSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 620E3EA7267CF6C70049F3FF /* GoogleCast.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA6267CF6C70049F3FF /* GoogleCast.framework */; }; - 620E3EA8267CF6C70049F3FF /* GoogleCast.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA6267CF6C70049F3FF /* GoogleCast.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 620E3EAA267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA9267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework */; }; - 620E3EAB267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 620E3EA9267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 765B351C27B44D520001270E /* TypeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 765B351B27B44D520001270E /* TypeUtils.swift */; }; + 8FF28873064ABFF844CA8F8B /* Pods_ContentProtectionIntegration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7E0E5387344C04F3BAFF4A8 /* Pods_ContentProtectionIntegration.framework */; }; D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */; }; D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */; }; D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */; }; @@ -24,30 +20,13 @@ E279FE4125139E4700EC0EFA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE3F25139E4700EC0EFA /* Main.storyboard */; }; E279FE4325139E4900EC0EFA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4225139E4900EC0EFA /* Assets.xcassets */; }; E279FE4625139E4900EC0EFA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */; }; - E2B43C8C26E791480048696B /* TypeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B43C8B26E791470048696B /* TypeUtils.swift */; }; /* End PBXBuildFile section */ -/* Begin PBXCopyFilesBuildPhase section */ - 620E3EA5267CF6590049F3FF /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 620E3EAB267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework in Embed Frameworks */, - 620E3EA8267CF6C70049F3FF /* GoogleCast.framework in Embed Frameworks */, - 620E3EA4267CF6590049F3FF /* THEOplayerSDK.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyOsDRMIntegration.swift; sourceTree = ""; }; - 620E3EA2267CF6590049F3FF /* THEOplayerSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = THEOplayerSDK.framework; path = ContentProtectionIntegration/THEOplayerSDK.framework; sourceTree = ""; }; - 620E3EA6267CF6C70049F3FF /* GoogleCast.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleCast.framework; path = ContentProtectionIntegration/GoogleCast.framework; sourceTree = ""; }; - 620E3EA9267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleInteractiveMediaAds.framework; path = ContentProtectionIntegration/GoogleInteractiveMediaAds.framework; sourceTree = ""; }; + 765B351B27B44D520001270E /* TypeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeUtils.swift; sourceTree = ""; }; + 9579374696DA3C9C1AC37A64 /* Pods-ContentProtectionIntegration.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentProtectionIntegration.debug.xcconfig"; path = "Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration.debug.xcconfig"; sourceTree = ""; }; + CD6ABAD3AD9CFA4F41C8F0E5 /* Pods-ContentProtectionIntegration.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentProtectionIntegration.release.xcconfig"; path = "Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration.release.xcconfig"; sourceTree = ""; }; D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VuDRMIntegration.swift; sourceTree = ""; }; D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UplynkDRMIntegration.swift; sourceTree = ""; }; D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDRMIntegration.swift; sourceTree = ""; }; @@ -60,8 +39,7 @@ E279FE4225139E4900EC0EFA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; E279FE4525139E4900EC0EFA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; E279FE4725139E4900EC0EFA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = THEOplayerSDK.framework; sourceTree = ""; }; - E2B43C8B26E791470048696B /* TypeUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TypeUtils.swift; path = "../../../samples-drm-integration-comcast/ios/ContentProtectionIntegration/TypeUtils.swift"; sourceTree = ""; }; + E7E0E5387344C04F3BAFF4A8 /* Pods_ContentProtectionIntegration.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ContentProtectionIntegration.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,21 +47,29 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 620E3EAA267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework in Frameworks */, - 620E3EA7267CF6C70049F3FF /* GoogleCast.framework in Frameworks */, - 620E3EA3267CF6590049F3FF /* THEOplayerSDK.framework in Frameworks */, + 8FF28873064ABFF844CA8F8B /* Pods_ContentProtectionIntegration.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1247B51564027806B98BE478 /* Pods */ = { + isa = PBXGroup; + children = ( + 9579374696DA3C9C1AC37A64 /* Pods-ContentProtectionIntegration.debug.xcconfig */, + CD6ABAD3AD9CFA4F41C8F0E5 /* Pods-ContentProtectionIntegration.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; E279FE2D25139E4700EC0EFA = { isa = PBXGroup; children = ( E279FE3825139E4700EC0EFA /* ContentProtectionIntegration */, E279FE3725139E4700EC0EFA /* Products */, E279FE4D25139EBA00EC0EFA /* Frameworks */, + 1247B51564027806B98BE478 /* Pods */, ); sourceTree = ""; }; @@ -99,7 +85,6 @@ isa = PBXGroup; children = ( E279FE5225139F2000EC0EFA /* integration */, - E2B43C8B26E791470048696B /* TypeUtils.swift */, E279FE3925139E4700EC0EFA /* AppDelegate.swift */, E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */, E279FE3D25139E4700EC0EFA /* ViewController.swift */, @@ -107,6 +92,7 @@ E279FE4225139E4900EC0EFA /* Assets.xcassets */, E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */, E279FE4725139E4900EC0EFA /* Info.plist */, + 765B351B27B44D520001270E /* TypeUtils.swift */, ); path = ContentProtectionIntegration; sourceTree = ""; @@ -114,10 +100,7 @@ E279FE4D25139EBA00EC0EFA /* Frameworks */ = { isa = PBXGroup; children = ( - 620E3EA9267CF73B0049F3FF /* GoogleInteractiveMediaAds.framework */, - 620E3EA6267CF6C70049F3FF /* GoogleCast.framework */, - 620E3EA2267CF6590049F3FF /* THEOplayerSDK.framework */, - E279FE4E25139EBA00EC0EFA /* THEOplayerSDK.framework */, + E7E0E5387344C04F3BAFF4A8 /* Pods_ContentProtectionIntegration.framework */, ); name = Frameworks; sourceTree = ""; @@ -141,10 +124,11 @@ isa = PBXNativeTarget; buildConfigurationList = E279FE4A25139E4900EC0EFA /* Build configuration list for PBXNativeTarget "ContentProtectionIntegration" */; buildPhases = ( + 0D15DADA531C7EBE18F2747C /* [CP] Check Pods Manifest.lock */, E279FE3225139E4700EC0EFA /* Sources */, E279FE3325139E4700EC0EFA /* Frameworks */, E279FE3425139E4700EC0EFA /* Resources */, - 620E3EA5267CF6590049F3FF /* Embed Frameworks */, + 50CBB4E6454573C97513B0CC /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -201,6 +185,48 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 0D15DADA531C7EBE18F2747C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ContentProtectionIntegration-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 50CBB4E6454573C97513B0CC /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ E279FE3225139E4700EC0EFA /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -209,7 +235,7 @@ D99BC03525A4679200AE24B0 /* EzdrmDRMIntegration.swift in Sources */, D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */, E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */, - E2B43C8C26E791480048696B /* TypeUtils.swift in Sources */, + 765B351C27B44D520001270E /* TypeUtils.swift in Sources */, D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */, E279FE3A25139E4700EC0EFA /* AppDelegate.swift in Sources */, D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */, @@ -356,6 +382,7 @@ }; E279FE4B25139E4900EC0EFA /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 9579374696DA3C9C1AC37A64 /* Pods-ContentProtectionIntegration.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -381,6 +408,7 @@ }; E279FE4C25139E4900EC0EFA /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = CD6ABAD3AD9CFA4F41C8F0E5 /* Pods-ContentProtectionIntegration.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; diff --git a/ios/ContentProtectionIntegration/ViewController.swift b/ios/ContentProtectionIntegration/ViewController.swift index 4fc69994..12f22cc5 100644 --- a/ios/ContentProtectionIntegration/ViewController.swift +++ b/ios/ContentProtectionIntegration/ViewController.swift @@ -21,8 +21,10 @@ class ViewController: UIViewController { var frame: CGRect = UIScreen.main.bounds frame.origin.y = 0 frame.size.height = frame.size.width * 9 / 16 - - self.theoplayer = THEOplayer() + self.theoplayer = THEOplayer(configuration: THEOplayerConfiguration( + pip: nil, + license: "YOUR_LICENSE_HERE" + )) self.theoplayer.frame = frame self.theoplayer.addAsSubview(of: self.view) } @@ -30,13 +32,13 @@ class ViewController: UIViewController { var sampleSource: SourceDescription { return SourceDescription( source: TypedSource( - src: "your stream url", + src: "https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-19.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/hls-fp/master.m3u8", type: "application/x-mpegurl", drm: FairPlayDRMConfiguration( customIntegrationId: KeyOsDRMIntegration.integrationID, - licenseAcquisitionURL: "your license acquisition url", - certificateURL: "your certificate url", - integrationParameters: ["customdata":"your custom data"] + licenseAcquisitionURL: "https://fp-keyos.licensekeyserver.com/getkey/", + certificateURL: "https://fp-keyos.licensekeyserver.com/cert/7e11400c7dccd29d0174c674397d99dd.der", + integrationParameters: ["x-keyos-authorization":"PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg=="] ) ) ) diff --git a/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift index 1ed72b18..01b4415c 100644 --- a/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift +++ b/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift @@ -27,7 +27,7 @@ class KeyOsDRMIntegration: ContentProtectionIntegration { } func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - request.headers.updateValue(self.getCustomdataFromDrmConfiguration(), forKey: "customdata") + request.headers.updateValue(self.getXKeyosAuthorizationFromDrmConfiguration(), forKey: "x-keyos-authorization") callback.request(request: request) } @@ -42,7 +42,7 @@ class KeyOsDRMIntegration: ContentProtectionIntegration { fatalError("contentID was nil.") } - request.headers.updateValue(self.getCustomdataFromDrmConfiguration(), forKey: "customdata") + request.headers.updateValue(self.getXKeyosAuthorizationFromDrmConfiguration(), forKey: "x-keyos-authorization") if let body64 = fromDataToBase64String(data: request.body) { request.body = fromUtf8StringToData(str: "spc=\(body64)&assetId=\(contentId)") @@ -65,9 +65,9 @@ class KeyOsDRMIntegration: ContentProtectionIntegration { } } - private func getCustomdataFromDrmConfiguration() -> String { - guard let customdata = self.configuration.integrationParameters?["customdata"] as? String else { - fatalError("Could not find the customdata value in the integrationParameters.") + private func getXKeyosAuthorizationFromDrmConfiguration() -> String { + guard let customdata = self.configuration.integrationParameters?["x-keyos-authorization"] as? String else { + fatalError("Could not find the x-keyos-authorization value in the integrationParameters.") } return customdata } diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 00000000..f3c0a4b9 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,11 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'ContentProtectionIntegration' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for ContentProtectionIntegration + pod 'THEOplayerSDK-basic' + +end diff --git a/ios/README.md b/ios/README.md index 09bfd13e..a0acf9f7 100644 --- a/ios/README.md +++ b/ios/README.md @@ -240,10 +240,10 @@ or needs to be transformed or unwrapped first in a way similar to the request bo ### Testing an integration -- Add your iOS THEOplayerSDK framework into the [/ios]() folder. -- Open the [project](/ios/ContentProtectionIntegration.xcodeproj) and - [add the framework as a dependency](https://docs.portal.theoplayer.com/getting-started/01-sdks/03-ios/00-getting-started.md#configure-theoplayer-sdk-framework) - to your project. +- Ensure that your Podfile is point to an appropriate [THEOplayer iOS SDK](https://github.com/THEOplayer/theoplayer-sdk-ios). +- Run `pod install --repo-update` in the `ios/` folder to install your Podfile. +- Open the `.xcworkspace` file instead of the `.xcodeproj` file. +- Enter a valid license key in `ViewController.swift` instead of `"YOUR_LICENSE_HERE"`. - Make sure to fill in the necessary fields `ViewController` for the content integration that will be tested, such as the manifest url and any integration parameters. - Attach an iOS device, and finally build and run the project. diff --git a/web/README.md b/web/README.md index 1d95cd46..ed9373b2 100644 --- a/web/README.md +++ b/web/README.md @@ -282,8 +282,7 @@ For the `onCertificateResponse()` and `onLicenseResponse()` hooks the return typ ### Testing an integration -- Include a THEOplayer build in the root folder under `THEOplayer/`. It should contain the THEOplayer javascript -library `THEOplayer.js`, the declaration file `THEOplayer.d.ts` with all exported TypeScript types, and `ui.css`. +- Enter your [THEOplayer license](https://portal.theoplayer.com) instead of `YOUR_LICENSE_HERE` in `src/index.ts`. - Run `npm install && npm run build` in the root folder to create the integrations library `bundle.js` under `dist/`. - Start http-server in the root folder by running `npm run server`. - Go to `localhost:8080/test/[integration you want to test]`. diff --git a/web/package-lock.json b/web/package-lock.json index 399518fa..2a36f565 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -165,6 +165,25 @@ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "dev": true }, + "@types/fs-extra": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", + "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "@types/json-schema": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", @@ -188,6 +207,12 @@ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, "@types/node": { "version": "14.6.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz", @@ -504,6 +529,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", @@ -1061,6 +1092,17 @@ "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", "dev": true }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1289,6 +1331,12 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true + }, "is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", @@ -1371,6 +1419,15 @@ "minimist": "^1.2.0" } }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1804,6 +1861,37 @@ "fsevents": "~2.1.2" } }, + "rollup-plugin-copy": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", + "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", + "dev": true, + "requires": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "dependencies": { + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + } + } + }, "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", @@ -2010,6 +2098,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "theoplayer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-3.0.0.tgz", + "integrity": "sha512-tYeFmEAgMYEBQENfK5/7MRsMM1CecOrsvuoFrfPC0hvWTA26nr2anog9xqEN8z9RVBFLso7UPzybDIVOg2Dw/w==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2097,6 +2191,12 @@ "qs": "^6.4.0" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", diff --git a/web/package.json b/web/package.json index 748cb039..5493c48f 100644 --- a/web/package.json +++ b/web/package.json @@ -29,6 +29,8 @@ "eslint-plugin-import": "^2.22.0", "http-server": "^0.12.3", "rollup": "^2.26.9", + "rollup-plugin-copy": "^3.4.0", + "theoplayer": "latest", "ts-node": "^9.0.0", "tslib": "^2.0.1", "typescript": "^4.0.2" diff --git a/web/rollup.config.js b/web/rollup.config.js index 5f0678dd..7a0a2a75 100644 --- a/web/rollup.config.js +++ b/web/rollup.config.js @@ -1,5 +1,6 @@ import commonJs from "@rollup/plugin-commonjs"; import resolve from "@rollup/plugin-node-resolve"; +import copy from 'rollup-plugin-copy'; import typescript from "@rollup/plugin-typescript"; export default { @@ -12,5 +13,14 @@ export default { globals: { THEOplayer: 'THEOplayer' } }, external: ['THEOplayer'], - plugins: [resolve(), commonJs({ extensions: [".js", ".ts"] }), typescript()], + plugins: [ + resolve(), + commonJs({ extensions: [".js", ".ts"] }), + copy({ + targets: [ + { src: './node_modules/theoplayer/*.(js|css|html)' , dest: './THEOplayer' } + ] + }), + typescript() + ], }; diff --git a/web/src/index.ts b/web/src/index.ts index b29b8171..546c9989 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -64,3 +64,5 @@ export { VerimatrixDrmFairPlayContentProtectionIntegrationFactory, CastLabsDrmFairPlayContentProtectionIntegrationFactory }; + +export const THEOPLAYER_LICENSE = "YOUR_LICENSE_HERE"; \ No newline at end of file diff --git a/web/src/integration/keyos/KeyOSDrmConfiguration.ts b/web/src/integration/keyos/KeyOSDrmConfiguration.ts index a43eb47c..6cae01e5 100644 --- a/web/src/integration/keyos/KeyOSDrmConfiguration.ts +++ b/web/src/integration/keyos/KeyOSDrmConfiguration.ts @@ -25,6 +25,6 @@ export interface KeyOSDrmConfiguration extends DRMConfiguration { * *
- Token that will be added to the headers of the license request. */ - customdata: string; + 'x-keyos-authorization': string; } } diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts index ea4df3d8..c6f835aa 100644 --- a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -33,7 +33,7 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; request.headers = { ...request.headers, - 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata + 'x-keyos-authorization': this.contentProtectionConfiguration.integrationParameters['x-keyos-authorization'] }; return request; } @@ -46,7 +46,7 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; request.headers = { ...request.headers, - 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata + 'x-keyos-authorization': this.contentProtectionConfiguration.integrationParameters['x-keyos-authorization'] }; const licenseParameters = `spc=${fromUint8ArrayToBase64String(request.body!)}&assetId=${this.contentId}`; request.body = fromStringToUint8Array(licenseParameters); diff --git a/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts index 382539ac..41f934d9 100644 --- a/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts @@ -25,7 +25,7 @@ export class KeyOSDrmPlayReadyContentProtectionIntegration implements ContentPro request.url = this.contentProtectionConfiguration.playready?.licenseAcquisitionURL; request.headers = { ...request.headers, - 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata + 'x-keyos-authorization': this.contentProtectionConfiguration.integrationParameters['x-keyos-authorization'] }; return request; } diff --git a/web/src/integration/keyos/KeyOSDrmUtils.ts b/web/src/integration/keyos/KeyOSDrmUtils.ts index 6d01f6ea..785d977f 100644 --- a/web/src/integration/keyos/KeyOSDrmUtils.ts +++ b/web/src/integration/keyos/KeyOSDrmUtils.ts @@ -1,7 +1,7 @@ import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; export function isKeyOSDrmDRMConfiguration(configuration: KeyOSDrmConfiguration): boolean { - return configuration.integrationParameters.customdata !== undefined; + return configuration.integrationParameters['x-keyos-authorization'] !== undefined; } export function extractContentId(skdUrl: string): string { diff --git a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts index bcec7949..194d2717 100644 --- a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts @@ -25,7 +25,7 @@ export class KeyOSDrmWidevineContentProtectionIntegration implements ContentProt request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL; request.headers = { ...request.headers, - 'customdata': this.contentProtectionConfiguration.integrationParameters.customdata + 'x-keyos-authorization': this.contentProtectionConfiguration.integrationParameters['x-keyos-authorization'] }; return request; } diff --git a/web/test/axinomdrm/fairplay.html b/web/test/axinomdrm/fairplay.html index 56fa021e..38d99573 100644 --- a/web/test/axinomdrm/fairplay.html +++ b/web/test/axinomdrm/fairplay.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/axinomdrm/playready.html b/web/test/axinomdrm/playready.html index d849d6de..75c275a4 100644 --- a/web/test/axinomdrm/playready.html +++ b/web/test/axinomdrm/playready.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/axinomdrm/widevine.html b/web/test/axinomdrm/widevine.html index 7ab72a4c..56b9468e 100644 --- a/web/test/axinomdrm/widevine.html +++ b/web/test/axinomdrm/widevine.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/azuredrm/fairplay.html b/web/test/azuredrm/fairplay.html index 4d3a8c7b..6e1af3b1 100644 --- a/web/test/azuredrm/fairplay.html +++ b/web/test/azuredrm/fairplay.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/azuredrm/playready.html b/web/test/azuredrm/playready.html index 31517105..b0f7ee3e 100644 --- a/web/test/azuredrm/playready.html +++ b/web/test/azuredrm/playready.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/azuredrm/widevine.html b/web/test/azuredrm/widevine.html index ca0bb2e2..84b8397b 100644 --- a/web/test/azuredrm/widevine.html +++ b/web/test/azuredrm/widevine.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/castlabs/fairplay.html b/web/test/castlabs/fairplay.html index 94c2e43f..dbf4d79e 100644 --- a/web/test/castlabs/fairplay.html +++ b/web/test/castlabs/fairplay.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/castlabs/playready.html b/web/test/castlabs/playready.html index 982541ba..7db8b3d6 100644 --- a/web/test/castlabs/playready.html +++ b/web/test/castlabs/playready.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/castlabs/widevine.html b/web/test/castlabs/widevine.html index 6c439217..f35e79bb 100644 --- a/web/test/castlabs/widevine.html +++ b/web/test/castlabs/widevine.html @@ -15,6 +15,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: '/THEOplayer/', }); diff --git a/web/test/comcastdrm/fairplay.html b/web/test/comcastdrm/fairplay.html index e99f1244..1c22d6b3 100644 --- a/web/test/comcastdrm/fairplay.html +++ b/web/test/comcastdrm/fairplay.html @@ -62,8 +62,8 @@

Comcast DRM FairPlay

fluid: true }, mutedAutoplay: true, - libraryLocation: '/THEOplayer/', - license: '' // enter your license from your SDK at portal.theoplayer.com + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/web/test/comcastdrm/playready.html b/web/test/comcastdrm/playready.html index 66fc3d58..befa3a6f 100644 --- a/web/test/comcastdrm/playready.html +++ b/web/test/comcastdrm/playready.html @@ -62,8 +62,8 @@

Comcast DRM PlayReady

fluid: true }, mutedAutoplay: true, - libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/', - license: '' // enter your license from your SDK at portal.theoplayer.com + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/' }); let configureStream = function (src, auth, releasePid, account, schema, licenseUrl) { diff --git a/web/test/comcastdrm/widevine.html b/web/test/comcastdrm/widevine.html index d8c454a4..d1f381b0 100644 --- a/web/test/comcastdrm/widevine.html +++ b/web/test/comcastdrm/widevine.html @@ -63,8 +63,8 @@

Comcast DRM Widevine

fluid: true }, mutedAutoplay: true, - libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/', - license: '' // enter your license from your SDK at portal.theoplayer.com + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/' }); let configureStream = function (src, token, releasePid, account, region, useRawWidevine) { diff --git a/web/test/ezdrm/fairplay.html b/web/test/ezdrm/fairplay.html index 48ebc749..9fa9ebe7 100644 --- a/web/test/ezdrm/fairplay.html +++ b/web/test/ezdrm/fairplay.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/web/test/irdetocontrol/fairplay.html b/web/test/irdetocontrol/fairplay.html index 1092a724..5e97cd6a 100644 --- a/web/test/irdetocontrol/fairplay.html +++ b/web/test/irdetocontrol/fairplay.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/web/test/irdetocontrol/playready.html b/web/test/irdetocontrol/playready.html index cabeab56..357e6b04 100644 --- a/web/test/irdetocontrol/playready.html +++ b/web/test/irdetocontrol/playready.html @@ -14,7 +14,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); const streamSrc = '.mpd'; diff --git a/web/test/irdetocontrol/widevine.html b/web/test/irdetocontrol/widevine.html index 58aaef08..b3085b35 100644 --- a/web/test/irdetocontrol/widevine.html +++ b/web/test/irdetocontrol/widevine.html @@ -14,7 +14,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); const streamSrc = '.mpd'; diff --git a/web/test/keyos/fairplay.html b/web/test/keyos/fairplay.html index 8dbd9836..2a674a16 100644 --- a/web/test/keyos/fairplay.html +++ b/web/test/keyos/fairplay.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( @@ -27,17 +28,17 @@ player.source = { sources: [ { - src: 'insert manifest url here', + src: 'https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-19.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/hls-fp/master.m3u8', type: 'application/x-mpegurl', contentProtection: { integration: 'keyos_buydrm', fairplay: { - certificateURL: 'insert certificate url here', - licenseAcquisitionURL: 'insert license url here' + certificateURL: 'https://fp-keyos.licensekeyserver.com/cert/7e11400c7dccd29d0174c674397d99dd.der', + licenseAcquisitionURL: 'https://fp-keyos.licensekeyserver.com/getkey/' }, preferredKeySystems: ['fairplay', 'widevine', 'playready'], integrationParameters: { - customdata: 'insert customdata here', + 'x-keyos-authorization': 'PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg==', } } } diff --git a/web/test/keyos/playready.html b/web/test/keyos/playready.html index 9e5e8489..511d21d3 100644 --- a/web/test/keyos/playready.html +++ b/web/test/keyos/playready.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( @@ -27,16 +28,16 @@ player.source = { sources: [ { - src: 'insert manifest url here', + src: 'https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd', type: 'application/dash+xml', contentProtection: { integration: 'keyos_buydrm', playready: { - licenseAcquisitionURL: 'insert license url here', + licenseAcquisitionURL: 'https://pr-keyos.licensekeyserver.com/core/rightsmanager.asmx', }, preferredKeySystems: ['playready', 'widevine', 'fairplay'], integrationParameters: { - customdata: 'insert customdata here' + 'x-keyos-authorization': 'PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg==' } } } diff --git a/web/test/keyos/widevine.html b/web/test/keyos/widevine.html index cfab8f92..ce94d4a7 100644 --- a/web/test/keyos/widevine.html +++ b/web/test/keyos/widevine.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( @@ -27,16 +28,16 @@ player.source = { sources: [ { - src: 'insert manifest url here', + src: 'https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd', type: 'application/dash+xml', contentProtection: { integration: 'keyos_buydrm', widevine: { - licenseAcquisitionURL: 'insert license url here' + licenseAcquisitionURL: 'https://wv-keyos.licensekeyserver.com/' }, preferredKeySystems: ['widevine', 'playready', 'fairplay'], integrationParameters: { - customdata: 'insert customdata here' + 'x-keyos-authorization': 'PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg==' } } } diff --git a/web/test/nagradrm/fairplay.html b/web/test/nagradrm/fairplay.html index a230b836..33e3385e 100644 --- a/web/test/nagradrm/fairplay.html +++ b/web/test/nagradrm/fairplay.html @@ -55,6 +55,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: "/THEOplayer/" }); diff --git a/web/test/nagradrm/playready.html b/web/test/nagradrm/playready.html index c6b47334..922182e5 100644 --- a/web/test/nagradrm/playready.html +++ b/web/test/nagradrm/playready.html @@ -47,6 +47,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: "/THEOplayer/" }); diff --git a/web/test/nagradrm/widevine.html b/web/test/nagradrm/widevine.html index bb00cba5..a6a0bd91 100644 --- a/web/test/nagradrm/widevine.html +++ b/web/test/nagradrm/widevine.html @@ -47,6 +47,7 @@ ui: { fluid: true }, + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, libraryLocation: "/THEOplayer/" }); diff --git a/web/test/verimatrixcoredrm/fairplay.html b/web/test/verimatrixcoredrm/fairplay.html index beaefc56..0b868dd9 100644 --- a/web/test/verimatrixcoredrm/fairplay.html +++ b/web/test/verimatrixcoredrm/fairplay.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/web/test/verimatrixcoredrm/playready.html b/web/test/verimatrixcoredrm/playready.html index 604ee032..1a365edd 100644 --- a/web/test/verimatrixcoredrm/playready.html +++ b/web/test/verimatrixcoredrm/playready.html @@ -14,7 +14,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); const src = ''; diff --git a/web/test/verimatrixcoredrm/widevine.html b/web/test/verimatrixcoredrm/widevine.html index 326f82a4..b138b557 100644 --- a/web/test/verimatrixcoredrm/widevine.html +++ b/web/test/verimatrixcoredrm/widevine.html @@ -14,7 +14,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); const src = ''; diff --git a/web/test/vudrm/fairplay.html b/web/test/vudrm/fairplay.html index 436baba2..10cb0718 100644 --- a/web/test/vudrm/fairplay.html +++ b/web/test/vudrm/fairplay.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/web/test/vudrm/playready.html b/web/test/vudrm/playready.html index c79dda4e..442d3f83 100644 --- a/web/test/vudrm/playready.html +++ b/web/test/vudrm/playready.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/web/test/vudrm/widevine.html b/web/test/vudrm/widevine.html index a4d65d0e..da94dfb8 100644 --- a/web/test/vudrm/widevine.html +++ b/web/test/vudrm/widevine.html @@ -15,7 +15,8 @@ ui: { fluid: true }, - libraryLocation: '/THEOplayer/', + license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( From 67d5913ede59ea971413aecfe3b73b8b5df2107d Mon Sep 17 00:00:00 2001 From: Thijs Date: Thu, 3 Mar 2022 14:18:23 -0500 Subject: [PATCH 31/85] Add placeholder example for Verimatrix Multi-DRM Core. (#16) Co-authored-by: thijsl --- android/README.md | 4 +++ .../SourceManager.java | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/android/README.md b/android/README.md index 1dfaf519..95b6fcec 100644 --- a/android/README.md +++ b/android/README.md @@ -264,6 +264,10 @@ The repository already contains a few integration examples that could be used as - Microsoft Azure DRM - KeyOS +The repository also contains the following integration examples that use the default Widevine integration: + +- Verimatrix Core + ### Testing an integration Make sure to apply the following steps before testing your custom integration. If a problem persists, please diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java index 9d684760..771438b4 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java @@ -57,6 +57,24 @@ private SourceDescription buildWidevineSourceDescription( ).build(); } + private SourceDescription buildDefaultWidevineSourceDescription( + String manifestUrl, + String licenseUrl, + HashMap headers) { + return sourceDescription( + typedSource(manifestUrl) + .drm(new DRMConfiguration.Builder() + .widevine( + keySystemConfiguration(licenseUrl) + .headers(headers) + .build() + ) + .build()) + .build() + ).build(); + } + + private void initSources(Context context) { // Vualto VUDRM Widevine content protect integration String VUDRM_ID = "VUDRM"; @@ -116,6 +134,18 @@ private void initSources(Context context) { ) ); + // Verimatrix Multi-DRM Core + sources.put( + "Verimatrix Multi-DRM Core", + buildDefaultWidevineSourceDescription( + "https://example.com/stream.mpd", + "https://multidrm.vsaas.verimatrixcloud.net/widevine", + new HashMap() {{ + put("authorization", "ey..."); + }} + ) + ); + // add other registrations & sources here ... } } From f5d5af71e572bce50c5d58bfd1231edfe07dcde3 Mon Sep 17 00:00:00 2001 From: Thijs Date: Wed, 9 Mar 2022 13:55:38 -0500 Subject: [PATCH 32/85] Add initial Verimatrix Core integration for the THEOplayer iOS SDK. (#17) Co-authored-by: thijsl --- .../project.pbxproj | 4 + .../AppDelegate.swift | 3 + .../VerimatrixCoreDRMIntegration.swift | 82 +++++++++++++++++++ ios/README.md | 1 + 4 files changed, 90 insertions(+) create mode 100644 ios/ContentProtectionIntegration/integration/VerimatrixCoreDRMIntegration.swift diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj index e6fbf660..030788d8 100644 --- a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj +++ b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 620E3EA0267CF4910049F3FF /* KeyOsDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */; }; 765B351C27B44D520001270E /* TypeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 765B351B27B44D520001270E /* TypeUtils.swift */; }; + 76B2A70027D150CF009480EB /* VerimatrixCoreDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */; }; 8FF28873064ABFF844CA8F8B /* Pods_ContentProtectionIntegration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7E0E5387344C04F3BAFF4A8 /* Pods_ContentProtectionIntegration.framework */; }; D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */; }; D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */; }; @@ -25,6 +26,7 @@ /* Begin PBXFileReference section */ 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyOsDRMIntegration.swift; sourceTree = ""; }; 765B351B27B44D520001270E /* TypeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeUtils.swift; sourceTree = ""; }; + 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerimatrixCoreDRMIntegration.swift; sourceTree = ""; }; 9579374696DA3C9C1AC37A64 /* Pods-ContentProtectionIntegration.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentProtectionIntegration.debug.xcconfig"; path = "Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration.debug.xcconfig"; sourceTree = ""; }; CD6ABAD3AD9CFA4F41C8F0E5 /* Pods-ContentProtectionIntegration.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentProtectionIntegration.release.xcconfig"; path = "Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration.release.xcconfig"; sourceTree = ""; }; D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VuDRMIntegration.swift; sourceTree = ""; }; @@ -113,6 +115,7 @@ D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */, D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */, D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */, + 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */, ); path = integration; sourceTree = ""; @@ -232,6 +235,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 76B2A70027D150CF009480EB /* VerimatrixCoreDRMIntegration.swift in Sources */, D99BC03525A4679200AE24B0 /* EzdrmDRMIntegration.swift in Sources */, D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */, E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */, diff --git a/ios/ContentProtectionIntegration/AppDelegate.swift b/ios/ContentProtectionIntegration/AppDelegate.swift index 65e88528..1819a223 100644 --- a/ios/ContentProtectionIntegration/AppDelegate.swift +++ b/ios/ContentProtectionIntegration/AppDelegate.swift @@ -23,6 +23,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { THEOplayer.registerContentProtectionIntegration(integrationId: EzdrmDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: EzdrmDRMIntegrationFactory()) THEOplayer.registerContentProtectionIntegration(integrationId: KeyOsDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: KeyOsDRMIntegrationFactory()) + + THEOplayer.registerContentProtectionIntegration(integrationId: VerimatrixCoreDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: VerimatrixCoreDRMIntegrationFactory()) + return true } diff --git a/ios/ContentProtectionIntegration/integration/VerimatrixCoreDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/VerimatrixCoreDRMIntegration.swift new file mode 100644 index 00000000..844e7076 --- /dev/null +++ b/ios/ContentProtectionIntegration/integration/VerimatrixCoreDRMIntegration.swift @@ -0,0 +1,82 @@ +// +// VerimatrixCoreDRMIntegration.swift +// ContentProtectionIntegration +// +// Created by Wonne Joosen on 09/03/2022. +// Copyright © 2022 THEOplayer. All rights reserved. +// + +import Foundation +import THEOplayerSDK + +class VerimatrixCoreDRMIntegration: ContentProtectionIntegration { + static let integrationID = "verimatrix" + var configuration: DRMConfiguration + + var contentId: String? + + init(configuration: DRMConfiguration) { + self.configuration = configuration + } + + func extractFairplayContentId(skdUrl: String) -> String { + let components = skdUrl.components(separatedBy: "?") + let skd = components.first! + self.contentId = skd.replacingOccurrences(of: "skd://", with: "") + return self.contentId! + } + + func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { + callback.request(request: request) + + } + + func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { + callback.respond(certificate: response.body) + } + + + func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { + if let body64 = request.body?.base64EncodedString() { + let body = "{\"spc\":\"\(body64)\"}" + request.url = request.url + "?Authorization=" + getAuthorizationFromDrmConfiguration() + request.headers = [ + "Content-Type":"application/json", + "User-Agent": "ContentProtectionIntegration/0.0.1" + ] + request.body = body.data(using: .utf8) + callback.request(request: request) + } else { + fatalError("RequestBody was nil.") + } + } + + struct LicResp: Decodable { + let ckc: String + } + + func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { + guard let licenseBody = String(data: response.body, encoding: .utf8) else { + fatalError("Could not create a string from the reponseBody provided.") + } + let jsonResponse: LicResp = try! JSONDecoder().decode(LicResp.self, from: licenseBody.data(using: .utf8)!) + if let data = Data(base64Encoded: jsonResponse.ckc) { + callback.respond(license: data) + } else { + fatalError("Could not create a Data Object from the responseBody provided.") + } + } + + private func getAuthorizationFromDrmConfiguration() -> String { + guard let authorization = self.configuration.integrationParameters?["authorization"] as? String else { + fatalError("Could not find the authorization value in the integrationParameters.") + } + return authorization + } +} + +class VerimatrixCoreDRMIntegrationFactory: ContentProtectionIntegrationFactory { + func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { + return VerimatrixCoreDRMIntegration(configuration: configuration) + } +} diff --git a/ios/README.md b/ios/README.md index a0acf9f7..6fad35e7 100644 --- a/ios/README.md +++ b/ios/README.md @@ -237,6 +237,7 @@ or needs to be transformed or unwrapped first in a way similar to the request bo - Microsoft Azure DRM - Verizon Uplynk DRM - EZ DRM +- Verimatrix Core DRM ### Testing an integration From 6b150138984c28ec1773a7176c5d46444075d61c Mon Sep 17 00:00:00 2001 From: Thijs Date: Mon, 14 Mar 2022 08:43:09 -0400 Subject: [PATCH 33/85] Include bundle.js to access ContentProtectionIntegrations.THEOPLAYER_LICENSE. (#18) Co-authored-by: thijsl --- web/test/castlabs/playready.html | 1 + web/test/castlabs/widevine.html | 1 + web/test/irdetocontrol/playready.html | 1 + web/test/irdetocontrol/widevine.html | 1 + web/test/verimatrixcoredrm/playready.html | 1 + web/test/verimatrixcoredrm/widevine.html | 1 + 6 files changed, 6 insertions(+) diff --git a/web/test/castlabs/playready.html b/web/test/castlabs/playready.html index 7db8b3d6..73f994ac 100644 --- a/web/test/castlabs/playready.html +++ b/web/test/castlabs/playready.html @@ -5,6 +5,7 @@ CastLabs PlayReady Test +

This example uses the integration documented at https://docs.theoplayer.com/how-to-guides/04-drm/02-castlabs-drmtoday/00-introduction.md.

diff --git a/web/test/castlabs/widevine.html b/web/test/castlabs/widevine.html index f35e79bb..9db2f7bf 100644 --- a/web/test/castlabs/widevine.html +++ b/web/test/castlabs/widevine.html @@ -5,6 +5,7 @@ CastLabs Widevine Test +

This example uses the integration documented at https://docs.theoplayer.com/how-to-guides/04-drm/02-castlabs-drmtoday/00-introduction.md.

diff --git a/web/test/irdetocontrol/playready.html b/web/test/irdetocontrol/playready.html index 357e6b04..26935b85 100644 --- a/web/test/irdetocontrol/playready.html +++ b/web/test/irdetocontrol/playready.html @@ -5,6 +5,7 @@ Irdeto Control PlayReady Test +
diff --git a/web/test/irdetocontrol/widevine.html b/web/test/irdetocontrol/widevine.html index b3085b35..94bcf430 100644 --- a/web/test/irdetocontrol/widevine.html +++ b/web/test/irdetocontrol/widevine.html @@ -5,6 +5,7 @@ Irdeto Control Widevine Test +
diff --git a/web/test/verimatrixcoredrm/playready.html b/web/test/verimatrixcoredrm/playready.html index 1a365edd..6cfafac0 100644 --- a/web/test/verimatrixcoredrm/playready.html +++ b/web/test/verimatrixcoredrm/playready.html @@ -5,6 +5,7 @@ Verimatrix Core DRM PlayReady Test +
diff --git a/web/test/verimatrixcoredrm/widevine.html b/web/test/verimatrixcoredrm/widevine.html index b138b557..61fd3ae2 100644 --- a/web/test/verimatrixcoredrm/widevine.html +++ b/web/test/verimatrixcoredrm/widevine.html @@ -5,6 +5,7 @@ Verimatrix Core DRM Widevine Test +
From b3f5dca7770faa3c9d5f43307edbd8e40058d9f6 Mon Sep 17 00:00:00 2001 From: Thijs Date: Tue, 22 Mar 2022 16:25:45 +0100 Subject: [PATCH 34/85] Add Verimatrix MultiDRM Standard connector for the THEOplayer Web SDK and THEOplayer Android SDK. (#19) * Add Verimatrix MultiDRM Standard for the THEOplayer Web SDK. * Adjust widevine to playready in PlayReady test example of Verimatrix Core DRM. * Add Verimatrix MultiDRM Standard for the THEOplayer Android SDK. Co-authored-by: thijsl --- android/README.md | 3 +- .../SourceManager.java | 10 ++++ web/src/index.ts | 5 +- ...VerimatrixMultiDRMStandardConfiguration.ts | 17 ++++++ ...ardFairPlayContentProtectionIntegration.ts | 52 +++++++++++++++++++ ...PlayContentProtectionIntegrationFactory.ts | 12 +++++ web/test/verimatrixcoredrm/playready.html | 2 +- .../verimatrixmultidrmstandard/fairplay.html | 51 ++++++++++++++++++ .../verimatrixmultidrmstandard/playready.html | 42 +++++++++++++++ .../verimatrixmultidrmstandard/widevine.html | 42 +++++++++++++++ 10 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardConfiguration.ts create mode 100644 web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts create mode 100644 web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory.ts create mode 100644 web/test/verimatrixmultidrmstandard/fairplay.html create mode 100644 web/test/verimatrixmultidrmstandard/playready.html create mode 100644 web/test/verimatrixmultidrmstandard/widevine.html diff --git a/android/README.md b/android/README.md index 95b6fcec..c08507fa 100644 --- a/android/README.md +++ b/android/README.md @@ -264,9 +264,10 @@ The repository already contains a few integration examples that could be used as - Microsoft Azure DRM - KeyOS -The repository also contains the following integration examples that use the default Widevine integration: +The repository also lists some examples with placeholder data (in `SourceManager.java`) that can use the default Widevine integration: - Verimatrix Core +- Verimatrix MultiDRM Standard ### Testing an integration diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java index 771438b4..f1f72672 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java @@ -146,6 +146,16 @@ private void initSources(Context context) { ) ); + // Verimatrix MultiDRM Standard + sources.put( + "Verimatrix MultiDRM Standard", + buildDefaultWidevineSourceDescription( + "https://example.com/stream.mpd", + "https://vcas4-gc.emea.vmxdemos.net/widevine?deviceId=...", + new HashMap() {{}} + ) + ); + // add other registrations & sources here ... } } diff --git a/web/src/index.ts b/web/src/index.ts index 546c9989..d91cb642 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -40,6 +40,8 @@ import {KeyOSDrmPlayReadyContentProtectionIntegrationFactory} from "./integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory"; import { VerimatrixDrmFairPlayContentProtectionIntegrationFactory } from './integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory'; +import { VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory} from + "./integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory"; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -62,7 +64,8 @@ export { KeyOSDrmFairplayContentProtectionIntegrationFactory, KeyOSDrmPlayReadyContentProtectionIntegrationFactory, VerimatrixDrmFairPlayContentProtectionIntegrationFactory, - CastLabsDrmFairPlayContentProtectionIntegrationFactory + CastLabsDrmFairPlayContentProtectionIntegrationFactory, + VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory }; export const THEOPLAYER_LICENSE = "YOUR_LICENSE_HERE"; \ No newline at end of file diff --git a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardConfiguration.ts b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardConfiguration.ts new file mode 100644 index 00000000..1b944890 --- /dev/null +++ b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardConfiguration.ts @@ -0,0 +1,17 @@ +import { DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Verimatrix Core DRM integration. + */ +export type VerimatrixIntegrationID = 'verimatrixmultidrmstandard'; + +/** + * Describes the configuration of the Verimatrix Core DRM integration. + */ +export interface VerimatrixMultiDRMStandardConfiguration extends DRMConfiguration { + + /** + * The identifier of the DRM integration. + */ + integration: VerimatrixIntegrationID; +} diff --git a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts new file mode 100644 index 00000000..8897d537 --- /dev/null +++ b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts @@ -0,0 +1,52 @@ +import { + BufferSource, + ContentProtectionIntegration, + LicenseRequest, + LicenseResponse, + MaybeAsync, +} from 'THEOplayer'; +import { VerimatrixMultiDRMStandardConfiguration } from './VerimatrixMultiDRMStandardConfiguration'; +import { + fromBase64StringToArrayBuffer, + fromBase64StringToString, + fromObjectToUint8Array, fromStringToUint8Array, + fromUint8ArrayToBase64String, fromUint8ArrayToObject, + fromUint8ArrayToString +} from '../../utils/TypeUtils'; +import { extractContentId } from '../../utils/FairplayUtils'; + +export class VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: VerimatrixMultiDRMStandardConfiguration; + private contentId: string | undefined = undefined; + + constructor(configuration: VerimatrixMultiDRMStandardConfiguration) { + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + let spcMessage = fromUint8ArrayToBase64String(request.body!); + let url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; + if (!this.contentId) { + throw new Error('The FairPlay Verimatrix Multi-DRM Standard content ID has not been correctly configured.'); + } + const licenseParameters = `spc=${encodeURIComponent(spcMessage)}&assetId=${encodeURIComponent(this.contentId)}`; + let newBody = fromStringToUint8Array(licenseParameters); + const newRequest = { + ...request, + url: url, + body: newBody + }; + return newRequest; + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + const responseObject = fromUint8ArrayToObject(response.body); + return fromBase64StringToArrayBuffer(responseObject.ckc); + } + + extractFairplayContentId(skdUrl: string): string { + this.contentId = extractContentId(skdUrl); + return this.contentId; + } + +} diff --git a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory.ts b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..bfd8c2bc --- /dev/null +++ b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { VerimatrixMultiDRMStandardConfiguration } from './VerimatrixMultiDRMStandardConfiguration'; +import { VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration } from './VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration'; + +export class VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: VerimatrixMultiDRMStandardConfiguration): ContentProtectionIntegration { + return new VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration(configuration); + } +} diff --git a/web/test/verimatrixcoredrm/playready.html b/web/test/verimatrixcoredrm/playready.html index 6cfafac0..903be415 100644 --- a/web/test/verimatrixcoredrm/playready.html +++ b/web/test/verimatrixcoredrm/playready.html @@ -29,7 +29,7 @@ src: src, type: 'application/dash+xml', contentProtection: { - widevine: { + playready: { licenseAcquisitionURL: licenseAcquisitionURL, headers: { 'Authorization': token diff --git a/web/test/verimatrixmultidrmstandard/fairplay.html b/web/test/verimatrixmultidrmstandard/fairplay.html new file mode 100644 index 00000000..74f47a07 --- /dev/null +++ b/web/test/verimatrixmultidrmstandard/fairplay.html @@ -0,0 +1,51 @@ + + + + + Verimatrix MultiDRM Standard FairPlay Test + + + + + +
+ + + diff --git a/web/test/verimatrixmultidrmstandard/playready.html b/web/test/verimatrixmultidrmstandard/playready.html new file mode 100644 index 00000000..41c1544d --- /dev/null +++ b/web/test/verimatrixmultidrmstandard/playready.html @@ -0,0 +1,42 @@ + + + + + Verimatrix MultiDRM Standard PlayReady Test + + + + + +
+ + + diff --git a/web/test/verimatrixmultidrmstandard/widevine.html b/web/test/verimatrixmultidrmstandard/widevine.html new file mode 100644 index 00000000..1094853e --- /dev/null +++ b/web/test/verimatrixmultidrmstandard/widevine.html @@ -0,0 +1,42 @@ + + + + + Verimatrix MultiDRM Standard Widevine Test + + + + + +
+ + + From 83f9c30fb36dded30bcb8d2081a2fe2780c27e8a Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Thu, 28 Apr 2022 10:45:28 +0200 Subject: [PATCH 35/85] Add Titanium Widevine & PlayReady integrations --- web/src/index.ts | 10 +- .../titaniumdrm/TitaniumBaseRegistration.ts | 146 ++++++++++++++++++ .../TitaniumDrmIntegrationConfiguration.ts | 13 ++ ...umPlayReadyContentProtectionIntegration.ts | 27 ++++ ...eadyContentProtectionIntegrationFactory.ts | 9 ++ .../integration/titaniumdrm/TitaniumUtils.ts | 19 +++ ...iumWidevineContentProtectionIntegration.ts | 51 ++++++ ...vineContentProtectionIntegrationFactory.ts | 12 ++ .../TitaniumWidevineLicenseResponse.ts | 4 + web/test/titaniumdrm/playready.html | 48 ++++++ web/test/titaniumdrm/widevine.html | 49 ++++++ 11 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumDrmIntegrationConfiguration.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumUtils.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumWidevineLicenseResponse.ts create mode 100644 web/test/titaniumdrm/playready.html create mode 100644 web/test/titaniumdrm/widevine.html diff --git a/web/src/index.ts b/web/src/index.ts index d91cb642..47dd8ae8 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -36,12 +36,16 @@ import { KeyOSDrmFairplayContentProtectionIntegrationFactory } from './integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory'; import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from "./integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory"; -import {KeyOSDrmPlayReadyContentProtectionIntegrationFactory} from +import { KeyOSDrmPlayReadyContentProtectionIntegrationFactory} from "./integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory"; import { VerimatrixDrmFairPlayContentProtectionIntegrationFactory } from './integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory'; import { VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory} from "./integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory"; +import { TitaniumWidevineContentProtectionIntegrationFactory } from + "./integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory"; +import { TitaniumPlayReadyContentProtectionIntegrationFactory} from + "./integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory"; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -65,7 +69,9 @@ export { KeyOSDrmPlayReadyContentProtectionIntegrationFactory, VerimatrixDrmFairPlayContentProtectionIntegrationFactory, CastLabsDrmFairPlayContentProtectionIntegrationFactory, - VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory + VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory, + TitaniumWidevineContentProtectionIntegrationFactory, + TitaniumPlayReadyContentProtectionIntegrationFactory, }; export const THEOPLAYER_LICENSE = "YOUR_LICENSE_HERE"; \ No newline at end of file diff --git a/web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts b/web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts new file mode 100644 index 00000000..6c6ade6e --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts @@ -0,0 +1,146 @@ +/* eslint-disable no-unused-vars */ +import { ContentProtectionError, ErrorCode } from "THEOplayer"; +import { + fromObjectToBase64String, + fromUint8ArrayToBase64String +} from "../../utils/TypeUtils"; +import { isDeviceBasedTitaniumDRMConfiguration, isTokenBasedTitaniumDRMConfiguration } from "./TitaniumUtils"; +import { TitaniumDRMConfiguration, DeviceBasedTitaniumDRMConfiguration } from 'THEOplayer'; + +export interface TitaniumRequestData { + AuthToken?: string; + LatensRegistration?: TitaniumBaseRegistration; + Payload: string; +} + +export interface TitaniumBaseRegistration { + CustomerName: string; + AccountName: string; + PortalId: string; + FriendlyName: string; + DeviceInfo: TitaniumDeviceInfo; +} + +export interface TitaniumDeviceInfo extends TitaniumCDMDescription { + FormatVersion: string; + DeviceType: string; + OSType: string | undefined; + OSVersion: string | undefined; + DeviceVendor: string | undefined; + DeviceModel: string | undefined; +} + +export interface TitaniumCDMDescription { + DRMProvider: string; + DRMVersion: string; + DRMType: string; +} + +export enum TitaniumCDMType { + WIDEVINE = 'Widevine', + PLAYREADY = 'PlayreadyV2', + PLAYREADY_v2 = 'PlayreadyV2', + PLAYREADY_v3 = 'PlayreadyV3', + FAIRPLAY = 'Fairplay' +} + +export const TITANIUM_CDM_DESCRIPTIONS: { [cdmType: string /* TitaniumCDMType_*/]: TitaniumCDMDescription } = { + Widevine: { + DRMProvider: 'Google', + DRMVersion: '1.4.8.86', + DRMType: 'Widevine' + }, + PlayreadyV2: { + DRMProvider: 'Microsoft', + DRMVersion: '2.9', + DRMType: 'Playready' + }, + PlayreadyV3: { + DRMProvider: 'Microsoft', + DRMVersion: '3', + DRMType: 'Playready' + }, + Fairplay: { + DRMProvider: 'Apple', + DRMType: 'FairPlay', + DRMVersion: '1.0' + } +}; + +export function getTitaniumLicenseBaseRegistration( + configuration: DeviceBasedTitaniumDRMConfiguration, + cdmType: TitaniumCDMType +): TitaniumBaseRegistration { + const cdmDescription: TitaniumCDMDescription = TITANIUM_CDM_DESCRIPTIONS[cdmType]; + + const accountName = configuration.accountName; + const customerName = configuration.customerName; + const portalId = configuration.portalId; + const friendlyName = configuration.friendlyName; + + return { + CustomerName: customerName, + AccountName: accountName, + PortalId: portalId, + FriendlyName: friendlyName, + DeviceInfo: { + FormatVersion: '1', + DeviceType: 'PC', + OSType: navigator.platform, + OSVersion: '', + DRMProvider: cdmDescription.DRMProvider, + DRMVersion: cdmDescription.DRMVersion, + DRMType: cdmDescription.DRMType, + DeviceVendor: navigator.vendor, + DeviceModel: navigator.vendorSub + } + }; +} + +export function createErrorForMalformedTitaniumDRMConfiguration( + configuration: TitaniumDRMConfiguration, + cdmType: TitaniumCDMType): ContentProtectionError { + let message = `Invalid Titanium ${cdmType} DRM configuration.`; + if (!configuration.accountName) { + message = `Invalid Titanium ${cdmType} DRM configuration, accountName is not set.`; + } else if (!configuration.customerName) { + message = `Invalid Titanium ${cdmType} DRM configuration, customerName is not set.`; + } else if (!configuration.portalId) { + message = `Invalid Titanium ${cdmType} DRM configuration, portalId is not set.`; + } + throw { + code: ErrorCode.CONTENT_PROTECTION_CONFIGURATION_INVALID, + message: message + } as ContentProtectionError; +} + +export function createTitaniumCustomData( + body: Uint8Array, + configuration: TitaniumDRMConfiguration, + cdmType: TitaniumCDMType): string { + if (isTokenBasedTitaniumDRMConfiguration(configuration)) { + return fromObjectToBase64String({ + AuthToken: configuration.authToken, + Payload: fromUint8ArrayToBase64String(body) + } as TitaniumRequestData); + } else if (isDeviceBasedTitaniumDRMConfiguration(configuration)) { + return fromObjectToBase64String({ + LatensRegistration: getTitaniumLicenseBaseRegistration(configuration, cdmType), + Payload: fromUint8ArrayToBase64String(body) + } as TitaniumRequestData); + } else { + throw createErrorForMalformedTitaniumDRMConfiguration(configuration, cdmType); + } +} + +export function createTitaniumCDataHeader( + configuration: TitaniumDRMConfiguration, + cdmType: TitaniumCDMType): string { + if (isTokenBasedTitaniumDRMConfiguration(configuration)) { + return fromObjectToBase64String({AuthToken: configuration.authToken}); + } else if (isDeviceBasedTitaniumDRMConfiguration(configuration)) { + return fromObjectToBase64String({LatensRegistration: getTitaniumLicenseBaseRegistration(configuration, cdmType) }); + } else { + throw createErrorForMalformedTitaniumDRMConfiguration(configuration, cdmType); + } +} diff --git a/web/src/integration/titaniumdrm/TitaniumDrmIntegrationConfiguration.ts b/web/src/integration/titaniumdrm/TitaniumDrmIntegrationConfiguration.ts new file mode 100644 index 00000000..bc8d3e94 --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumDrmIntegrationConfiguration.ts @@ -0,0 +1,13 @@ +import { TitaniumDRMConfiguration, DRMConfiguration } from 'THEOplayer'; + +/** + * The identifier of the Titanium integration. + */ +export type TitaniumIntegrationID = 'titaniumdrm'; + +export interface TitaniumDrmIntegrationConfiguration extends DRMConfiguration { + + integration: TitaniumIntegrationID; + + integrationParameters: TitaniumDRMConfiguration; +} diff --git a/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts b/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts new file mode 100644 index 00000000..a93f7feb --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts @@ -0,0 +1,27 @@ +import { BufferSource, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import { isTitaniumDRMConfiguration } from './TitaniumUtils'; +import { TitaniumDrmIntegrationConfiguration } from './TitaniumDrmIntegrationConfiguration'; +import { createTitaniumCDataHeader, TitaniumCDMType } from './TitaniumBaseRegistration'; + +export class TitaniumPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: TitaniumDrmIntegrationConfiguration; + + constructor(drmConfiguration: TitaniumDrmIntegrationConfiguration) { + if (!isTitaniumDRMConfiguration(drmConfiguration.integrationParameters)) { + throw new Error('The PlayReady Titanium authToken has not been correctly configured.'); + } + this.contentProtectionConfiguration = drmConfiguration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + const { version } = this.contentProtectionConfiguration.integrationParameters; + const cdmType = version === '2' ? TitaniumCDMType.PLAYREADY_v2 : TitaniumCDMType.PLAYREADY_v3; + request.headers = { + ...request.headers, + 'Content-Type': 'text/xml; charset=utf-8', + 'X-TITANIUM-DRM-CDATA': createTitaniumCDataHeader(this.contentProtectionConfiguration.integrationParameters, cdmType) + } + return request; + } +} diff --git a/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts b/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..5bbc0d9c --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts @@ -0,0 +1,9 @@ +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { TitaniumPlayReadyContentProtectionIntegration } from './TitaniumPlayReadyContentProtectionIntegration'; +import { TitaniumDrmIntegrationConfiguration } from './TitaniumDrmIntegrationConfiguration'; + +export class TitaniumPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: TitaniumDrmIntegrationConfiguration): ContentProtectionIntegration { + return new TitaniumPlayReadyContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/titaniumdrm/TitaniumUtils.ts b/web/src/integration/titaniumdrm/TitaniumUtils.ts new file mode 100644 index 00000000..23849910 --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumUtils.ts @@ -0,0 +1,19 @@ +import { TitaniumDRMConfiguration, DeviceBasedTitaniumDRMConfiguration, TokenBasedTitaniumDRMConfiguration } from 'THEOplayer'; + +export function isTitaniumDRMConfiguration(configuration: TitaniumDRMConfiguration): boolean { + return isTokenBasedTitaniumDRMConfiguration(configuration) || isDeviceBasedTitaniumDRMConfiguration((configuration)); +} + +// eslint-disable-next-line no-undef +export function isTokenBasedTitaniumDRMConfiguration(configuration: TitaniumDRMConfiguration): configuration is TokenBasedTitaniumDRMConfiguration { + return configuration.authToken !== undefined; +} + +// eslint-disable-next-line no-undef +export function isDeviceBasedTitaniumDRMConfiguration(configuration: TitaniumDRMConfiguration): configuration is DeviceBasedTitaniumDRMConfiguration { + return ( + configuration.accountName !== undefined && + configuration.customerName !== undefined && + configuration.portalId !== undefined + ); +} diff --git a/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts b/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts new file mode 100644 index 00000000..c7375dc7 --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts @@ -0,0 +1,51 @@ +import { + ContentProtectionIntegration, + LicenseRequest, + MaybeAsync, + BufferSource, + CertificateRequest, + LicenseResponse +} from 'THEOplayer'; +import { TitaniumDrmIntegrationConfiguration } from './TitaniumDrmIntegrationConfiguration'; +import { isTitaniumDRMConfiguration } from './TitaniumUtils'; +import { + fromBase64StringToUint8Array, + fromStringToUint8Array, + fromUint8ArrayToObject, +} from '../../utils/TypeUtils'; +import TitaniumWidevineLicenseResponse from './TitaniumWidevineLicenseResponse'; +import { + createTitaniumCustomData, + TitaniumCDMType +} from './TitaniumBaseRegistration'; + +export class TitaniumWidevineContentProtectionIntegration implements ContentProtectionIntegration { + + private readonly contentProtectionConfiguration: TitaniumDrmIntegrationConfiguration; + + constructor(configuration: TitaniumDrmIntegrationConfiguration) { + if (!isTitaniumDRMConfiguration(configuration.integrationParameters)) { + throw new Error('The Widevine Titanium authToken has not been correctly configured.'); + } + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + const { integrationParameters } = this.contentProtectionConfiguration; + const customData = createTitaniumCustomData(request.body!, integrationParameters, TitaniumCDMType.WIDEVINE); + request.body = fromStringToUint8Array(customData); + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + const { integrationParameters } = this.contentProtectionConfiguration; + const customData = createTitaniumCustomData(request.body!, integrationParameters, TitaniumCDMType.WIDEVINE); + request.body = fromStringToUint8Array(customData); + return request; + } + + onLicenseResponse(response: LicenseResponse): MaybeAsync { + const responseObject = fromUint8ArrayToObject(response.body) as TitaniumWidevineLicenseResponse; + return fromBase64StringToUint8Array(responseObject.license); + } +} diff --git a/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..765403b5 --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts @@ -0,0 +1,12 @@ +import { + ContentProtectionIntegration, + ContentProtectionIntegrationFactory +} from 'THEOplayer'; +import { TitaniumWidevineContentProtectionIntegration } from './TitaniumWidevineContentProtectionIntegration'; +import { TitaniumDrmIntegrationConfiguration } from './TitaniumDrmIntegrationConfiguration'; + +export class TitaniumWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: TitaniumDrmIntegrationConfiguration): ContentProtectionIntegration { + return new TitaniumWidevineContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/titaniumdrm/TitaniumWidevineLicenseResponse.ts b/web/src/integration/titaniumdrm/TitaniumWidevineLicenseResponse.ts new file mode 100644 index 00000000..7097d6a5 --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumWidevineLicenseResponse.ts @@ -0,0 +1,4 @@ +export default interface TitaniumWidevineLicenseResponse { + can_play: boolean; + license: string; +} diff --git a/web/test/titaniumdrm/playready.html b/web/test/titaniumdrm/playready.html new file mode 100644 index 00000000..dc995b21 --- /dev/null +++ b/web/test/titaniumdrm/playready.html @@ -0,0 +1,48 @@ + + + + + Titanium DRM PlayReady Test using AuthToken + + + + + + +
+ + + diff --git a/web/test/titaniumdrm/widevine.html b/web/test/titaniumdrm/widevine.html new file mode 100644 index 00000000..186ea8aa --- /dev/null +++ b/web/test/titaniumdrm/widevine.html @@ -0,0 +1,49 @@ + + + + + Titanium DRM Widevine Test Using AuthToken + + + + + + +
+ + + From c6c37bc394ded76be65889e9ce95e7fad9d02eb0 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Thu, 28 Apr 2022 10:46:13 +0200 Subject: [PATCH 36/85] Update README --- web/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/web/README.md b/web/README.md index ed9373b2..27da39b1 100644 --- a/web/README.md +++ b/web/README.md @@ -279,6 +279,7 @@ For the `onCertificateResponse()` and `onLicenseResponse()` hooks the return typ - Nagra DRM - Vualto VuDRM - Verimatrix MultiDRM Core DRM +- Titanium DRM ### Testing an integration From 966e20f601eae27f55a979d8433d648efd69daea Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Thu, 28 Apr 2022 10:51:01 +0200 Subject: [PATCH 37/85] Update package description --- web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/package.json b/web/package.json index 5493c48f..2097e8a1 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "drm-api-plugins", "version": "1.0.0", - "description": "**Edit a file, create a new file, and clone from Bitbucket in under 2 minutes**", + "description": "THEOplayer samples for DRM integrations", "main": "index.js", "scripts": { "server": "http-server", From e5029d693ce9cde76611519918727c5dbea3aa52 Mon Sep 17 00:00:00 2001 From: Daniel Dallos Date: Tue, 15 Nov 2022 15:44:52 +0100 Subject: [PATCH 38/85] added Arris Titanium DRM Custom Connector --- .../project.pbxproj | 4 + .../ArrisTitaniumDrmIntegration.swift | 242 ++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 ios/ContentProtectionIntegration/integration/ArrisTitaniumDrmIntegration.swift diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj index 030788d8..4e06607f 100644 --- a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj +++ b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 620E3EA0267CF4910049F3FF /* KeyOsDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */; }; + 657D888E2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657D888D2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift */; }; 765B351C27B44D520001270E /* TypeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 765B351B27B44D520001270E /* TypeUtils.swift */; }; 76B2A70027D150CF009480EB /* VerimatrixCoreDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */; }; 8FF28873064ABFF844CA8F8B /* Pods_ContentProtectionIntegration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7E0E5387344C04F3BAFF4A8 /* Pods_ContentProtectionIntegration.framework */; }; @@ -25,6 +26,7 @@ /* Begin PBXFileReference section */ 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyOsDRMIntegration.swift; sourceTree = ""; }; + 657D888D2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrisTitaniumDrmIntegration.swift; sourceTree = ""; }; 765B351B27B44D520001270E /* TypeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeUtils.swift; sourceTree = ""; }; 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerimatrixCoreDRMIntegration.swift; sourceTree = ""; }; 9579374696DA3C9C1AC37A64 /* Pods-ContentProtectionIntegration.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentProtectionIntegration.debug.xcconfig"; path = "Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration.debug.xcconfig"; sourceTree = ""; }; @@ -116,6 +118,7 @@ D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */, D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */, 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */, + 657D888D2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift */, ); path = integration; sourceTree = ""; @@ -235,6 +238,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 657D888E2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift in Sources */, 76B2A70027D150CF009480EB /* VerimatrixCoreDRMIntegration.swift in Sources */, D99BC03525A4679200AE24B0 /* EzdrmDRMIntegration.swift in Sources */, D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */, diff --git a/ios/ContentProtectionIntegration/integration/ArrisTitaniumDrmIntegration.swift b/ios/ContentProtectionIntegration/integration/ArrisTitaniumDrmIntegration.swift new file mode 100644 index 00000000..753de57e --- /dev/null +++ b/ios/ContentProtectionIntegration/integration/ArrisTitaniumDrmIntegration.swift @@ -0,0 +1,242 @@ +// +// ArrisTitaniumDrmIntegration.swift +// ContentProtectionIntegration +// +// Created by Daniel on 15/11/2022. +// Copyright © 2022 THEOplayer. All rights reserved. +// + +import Foundation +import THEOplayerSDK + +/// Sample source usage: +/// +/// - Token-based authorization with Cetificate URL +/// +/// var integrationParameters: [String:Any] = [:] +/// integrationParameters["authToken"] = "___JWT_AUTH_TOKEN___" +/// +/// let drmConfig = FairPlayDRMConfiguration( +/// customIntegrationId: TitaniumDRMIntegration.integrationID, +/// licenseAcquisitionURL: "___LICENSE_SERVER_URL___", +/// certificateURL: "___CERTIFICATE_URL___", +/// integrationParameters: integrationParameters +/// ) +/// +/// let source = SourceDescription( +/// sources: [TypedSource( +/// src: "___SOURCE_URL___", +/// type: "application/x-mpegurl", +/// drm: drmConfig)] +/// ) +/// +/// theoplayer.source = source +/// +/// +/// - Token-based authorization with base64 encoded Certificate data +/// +/// var integrationParameters: [String:Any] = [:] +/// integrationParameters["authToken"] = "___JWT_AUTH_TOKEN___" +/// integrationParameters["certificateData"] = "___BASE64_ENCODED_CERT___" // passing base64 encoded certificate data instead of loading it from a URL (useful, if the certificate is inside the app) +/// +/// let drmConfig = FairPlayDRMConfiguration( +/// customIntegrationId: TitaniumDRMIntegration.integrationID, +/// licenseAcquisitionURL: "___LICENSE_SERVER_URL___", +/// certificateURL: "https://dummyurl.com", // you can use any dummy URL to trigger and intercept the flow (request will be not executed) +/// integrationParameters: integrationParameters +/// ) +/// +/// let source = SourceDescription( +/// sources: [TypedSource( +/// src: "___SOURCE_URL___", +/// type: "application/x-mpegurl", +/// drm: drmConfig)] +/// ) +/// +/// theoplayer.source = source +/// +/// - Device-based authorization with Cetificate URL +/// +/// var integrationParameters: [String:Any] = [:] +/// integrationParameters["accountName"] = "___ACCOUNT_NAME___" // mandatory parameter for device-based authorization +/// integrationParameters["customerName"] = "___CUSTOMER_NAME___" // mandatory parameter for device-based authorization +/// integrationParameters["portalId"] = "___PORTAL_ID_NAME___" // mandatory parameter for device-based authorization +/// integrationParameters["friendlyName"] = "___FRIENDLY_NAME___" // mandatory parameter for device-based authorization +/// +/// let drmConfig = FairPlayDRMConfiguration( +/// customIntegrationId: TitaniumDRMIntegration.integrationID, +/// licenseAcquisitionURL: "___LICENSE_SERVER_URL___", +/// certificateURL: "___CERTIFICATE_URL___", +/// integrationParameters: integrationParameters +/// ) +/// +/// let source = SourceDescription( +/// sources: [TypedSource( +/// src: "___SOURCE_URL___", +/// type: "application/x-mpegurl", +/// drm: drmConfig)] +/// ) +/// +/// theoplayer.source = source + +class TitaniumDRMIntegration: ContentProtectionIntegration { + static let integrationID = "titanium" + + let fairplayKeySystemConfiguration: KeySystemConfiguration + var drmConfiguration: DRMConfiguration + + init(drmConfiguration: FairPlayDRMConfiguration) { + self.drmConfiguration = drmConfiguration + self.fairplayKeySystemConfiguration = drmConfiguration.fairplay + } + + init(drmConfiguration: MultiplatformDRMConfiguration) { + self.drmConfiguration = drmConfiguration + self.fairplayKeySystemConfiguration = drmConfiguration.keySystemConfigurations.fairplay! + } + + func extractFairplayContentId(skdUrl: String) -> String { + print("[TitaniumDRMIntegration] <- \(#function): \(skdUrl)") + let arr = skdUrl.components(separatedBy: "/") + let skd = arr[arr.count - 1] + print("[TitaniumDRMIntegration] -> \(#function): \(skd)") + return skd + } + + func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { + let requestString = String(data: try! JSONEncoder().encode(request), encoding: .utf8)! + print("[TitaniumDRMIntegration] <- \(#function): \(requestString)") + + if let certificateData = drmConfiguration.integrationParameters?["certificateData"] as? String { + callback.respond(certificate: Data(base64Encoded: certificateData, options: .ignoreUnknownCharacters)!) + } else if let certificateURL = fairplayKeySystemConfiguration.certificateURL { + var newRequest = URLRequest(url: certificateURL) + newRequest.httpMethod = "GET" + URLSession.shared.dataTask(with: newRequest) { data, response, error in + if let error = error { + callback.error(error: error) + print("[TitaniumDRMIntegration] error", error) + return + } + + if let certData = data { + print("[TitaniumDRMIntegration] -> \(#function): respond with data") + callback.respond(certificate: certData) + } else { + print("[TitaniumDRMIntegration] -> \(#function): error", error) + callback.error(error: URLError.init(URLError.badServerResponse)) + } + } + .resume() + } else { + print("[TitaniumDRMIntegration] -> \(#function): error clientCertificateRequired") + callback.error(error: URLError.init(URLError.clientCertificateRequired)) + } + + } + + func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { + let requestString = String(data: try! JSONEncoder().encode(request), encoding: .utf8)! + print("[TitaniumDRMIntegration] <- \(#function): \(requestString)") + + guard let serviceUrl = fairplayKeySystemConfiguration.licenseAcquisitionURL else { + fatalError("[TitaniumDRMIntegration] LA is not a valid URL") + } + var urlRequest = URLRequest(url: serviceUrl) + + // support for token-based authorization + if let authToken = drmConfiguration.integrationParameters?["authToken"] as? String { + urlRequest.setValue("Bearer " + authToken, forHTTPHeaderField: "Authorization") + + // support for device specific authorization + } else if let accountName = drmConfiguration.integrationParameters?["accountName"] as? String, + let customerName = drmConfiguration.integrationParameters?["customerName"] as? String, + let portalId = drmConfiguration.integrationParameters?["portalId"] as? String, + let friendlyName = drmConfiguration.integrationParameters?["friendlyName"] as? String { + + let lr = DeviceSpecificAuth(LatensRegistration: LatensRegistration(CustomerName: customerName, AccountName: accountName, PortalId: portalId, FriendlyName: friendlyName, DeviceInfo: DeviceInfo())) + + urlRequest.setValue(try! JSONEncoder().encode(lr).base64EncodedString(), forHTTPHeaderField: "X-TITANIUM-DRM-CDATA") + + } else { + print("[TitaniumDRMIntegration] -> \(#function): error userAuthenticationRequired") + callback.error(error: URLError.init(URLError.userAuthenticationRequired)) + return + } + + urlRequest.httpMethod = "POST" + urlRequest.httpBody = request.body + urlRequest.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type") + + URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in + if let data = data { + print("[TitaniumDRMIntegration] -> \(#function): respond with license") + callback.respond(license: data) + } else { + print("[TitaniumDRMIntegration] -> \(#function): error", error) + callback.error(error: error!) + } + }.resume() + + } + + func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { + print("[TitaniumDRMIntegration] <- \(#function): response") + callback.respond(license: response.body) + } + +} + +class TitaniumDRMIntegrationFactory: ContentProtectionIntegrationFactory { + func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { + if let fairplayConfiguration = configuration as? FairPlayDRMConfiguration { + return TitaniumDRMIntegration(drmConfiguration: fairplayConfiguration) + } else if let multiDrm = configuration as? MultiplatformDRMConfiguration, multiDrm.keySystemConfigurations.fairplay != nil { + return TitaniumDRMIntegration(drmConfiguration: multiDrm) + } else { + fatalError("DRMConfiguration must contain a FairPlay Keysystem configuration") + } + } +} + +struct DeviceSpecificAuth: Encodable { + var LatensRegistration: LatensRegistration +} + +struct LatensRegistration: Encodable { + var CustomerName: String + var AccountName: String + var PortalId: String + var FriendlyName: String + var AppVersion: String = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" + var DeviceInfo: DeviceInfo +} + +struct DeviceInfo: Encodable { + var FormatVersion: String = "1" + var varDeviceType: String = DeviceInfo.getDeviceType() + var OSType: String = UIDevice.current.systemName + var OSVersion: String = UIDevice.current.systemVersion + var DRMProvider: String = "Apple" + var DRMVersion: String = "1.0" + var DRMType: String = "Fairplay" + var DeviceVendor: String = "Apple" + var DeviceModel: String = UIDevice.current.model + + static func getDeviceType() -> String { + switch UIDevice.current.userInterfaceIdiom { + case .carPlay: + return "CarPlay" + case .mac: + return "Mac" + case .pad: + return "iPad" + case .phone: + return "iPhone" + case .tv: + return "AppleTV" + default: + return "Unknown" + } + } +} From 9170efb195c33c602e00b7b90e37e198fa2b8619 Mon Sep 17 00:00:00 2001 From: Daniel Dallos Date: Tue, 15 Nov 2022 15:45:42 +0100 Subject: [PATCH 39/85] updated readme --- ios/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/README.md b/ios/README.md index 6fad35e7..4f5c6d7a 100644 --- a/ios/README.md +++ b/ios/README.md @@ -238,6 +238,7 @@ or needs to be transformed or unwrapped first in a way similar to the request bo - Verizon Uplynk DRM - EZ DRM - Verimatrix Core DRM +- Arris Titanium DRM (supported from THEOplayer 4.4.0) ### Testing an integration @@ -253,3 +254,4 @@ or needs to be transformed or unwrapped first in a way similar to the request bo This document showed how to create a custom DRM integration for iOS using THEOplayer's Content Integration API, and register it with THEOplayer. The iOS integration API can slightly differ on other platforms, so it is best to check the platform's specific document. + \ No newline at end of file From f6f746edaa4de219929eb487385bfe0737250d40 Mon Sep 17 00:00:00 2001 From: Daniel Dallos Date: Tue, 15 Nov 2022 15:54:58 +0100 Subject: [PATCH 40/85] updated AppDelegate --- ios/ContentProtectionIntegration/AppDelegate.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/ContentProtectionIntegration/AppDelegate.swift b/ios/ContentProtectionIntegration/AppDelegate.swift index 1819a223..54ba9f0e 100644 --- a/ios/ContentProtectionIntegration/AppDelegate.swift +++ b/ios/ContentProtectionIntegration/AppDelegate.swift @@ -26,6 +26,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { THEOplayer.registerContentProtectionIntegration(integrationId: VerimatrixCoreDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: VerimatrixCoreDRMIntegrationFactory()) + THEOplayer.registerContentProtectionIntegration(integrationId: TitaniumDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: TitaniumDRMIntegrationFactory()) + return true } From 39755f0c4f98610a9345fdb34b1a4e14e83bac54 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 16 Nov 2022 16:25:00 +0100 Subject: [PATCH 41/85] Update Titanium DRM connector --- .../titaniumdrm/TitaniumBaseRegistration.ts | 156 ++++++++++-------- .../titaniumdrm/TitaniumDrmConfiguration.ts | 10 ++ .../TitaniumDrmIntegrationConfiguration.ts | 13 -- ...iumFairplayContentProtectionIntegration.ts | 28 ++++ ...playContentProtectionIntegrationFactory.ts | 9 + .../TitaniumIntegrationParameters.ts | 107 ++++++++++++ ...umPlayReadyContentProtectionIntegration.ts | 31 ++-- ...eadyContentProtectionIntegrationFactory.ts | 6 +- .../integration/titaniumdrm/TitaniumUtils.ts | 31 ++-- ...iumWidevineContentProtectionIntegration.ts | 53 ++---- ...vineContentProtectionIntegrationFactory.ts | 9 +- .../TitaniumWidevineLicenseResponse.ts | 4 - 12 files changed, 300 insertions(+), 157 deletions(-) create mode 100644 web/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts delete mode 100644 web/src/integration/titaniumdrm/TitaniumDrmIntegrationConfiguration.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts delete mode 100644 web/src/integration/titaniumdrm/TitaniumWidevineLicenseResponse.ts diff --git a/web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts b/web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts index 6c6ade6e..32b8588f 100644 --- a/web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts +++ b/web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts @@ -1,33 +1,31 @@ /* eslint-disable no-unused-vars */ -import { ContentProtectionError, ErrorCode } from "THEOplayer"; -import { - fromObjectToBase64String, - fromUint8ArrayToBase64String -} from "../../utils/TypeUtils"; -import { isDeviceBasedTitaniumDRMConfiguration, isTokenBasedTitaniumDRMConfiguration } from "./TitaniumUtils"; -import { TitaniumDRMConfiguration, DeviceBasedTitaniumDRMConfiguration } from 'THEOplayer'; +import { isDeviceBasedTitaniumDRMConfiguration, isTokenBasedTitaniumDRMConfiguration } from './TitaniumUtils'; +import type { DeviceBasedTitaniumIntegrationParameters } from './TitaniumIntegrationParameters'; +import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; +import type { ContentProtectionError } from 'THEOplayer'; +import { ErrorCode } from 'THEOplayer'; +import { fromObjectToBase64String } from "../../utils/TypeUtils"; -export interface TitaniumRequestData { - AuthToken?: string; - LatensRegistration?: TitaniumBaseRegistration; - Payload: string; +export interface TitaniumDeviceAuthorizationData { + LatensRegistration: TitaniumLatensRegistration; } -export interface TitaniumBaseRegistration { +export interface TitaniumLatensRegistration { CustomerName: string; AccountName: string; PortalId: string; FriendlyName: string; + AppVersion: string | undefined; DeviceInfo: TitaniumDeviceInfo; } export interface TitaniumDeviceInfo extends TitaniumCDMDescription { FormatVersion: string; DeviceType: string; - OSType: string | undefined; - OSVersion: string | undefined; - DeviceVendor: string | undefined; - DeviceModel: string | undefined; + OSType: string; + OSVersion: string; + DeviceVendor: string; + DeviceModel: string; } export interface TitaniumCDMDescription { @@ -64,83 +62,99 @@ export const TITANIUM_CDM_DESCRIPTIONS: { [cdmType: string /* TitaniumCDMType_*/ DRMProvider: 'Apple', DRMType: 'FairPlay', DRMVersion: '1.0' - } + }, }; -export function getTitaniumLicenseBaseRegistration( - configuration: DeviceBasedTitaniumDRMConfiguration, - cdmType: TitaniumCDMType -): TitaniumBaseRegistration { +export function getTitaniumDeviceAuthorizationData( + integrationParameters: DeviceBasedTitaniumIntegrationParameters, + cdmType: TitaniumCDMType, +): TitaniumDeviceAuthorizationData { const cdmDescription: TitaniumCDMDescription = TITANIUM_CDM_DESCRIPTIONS[cdmType]; - - const accountName = configuration.accountName; - const customerName = configuration.customerName; - const portalId = configuration.portalId; - const friendlyName = configuration.friendlyName; + const accountName = integrationParameters.accountName; + const customerName = integrationParameters.customerName; + const portalId = integrationParameters.portalId; + const friendlyName = integrationParameters.friendlyName; return { - CustomerName: customerName, - AccountName: accountName, - PortalId: portalId, - FriendlyName: friendlyName, - DeviceInfo: { - FormatVersion: '1', - DeviceType: 'PC', - OSType: navigator.platform, - OSVersion: '', - DRMProvider: cdmDescription.DRMProvider, - DRMVersion: cdmDescription.DRMVersion, - DRMType: cdmDescription.DRMType, - DeviceVendor: navigator.vendor, - DeviceModel: navigator.vendorSub - } + LatensRegistration: { + CustomerName: customerName, + AccountName: accountName, + PortalId: portalId, + FriendlyName: friendlyName, + AppVersion: '1.0', + DeviceInfo: { + FormatVersion: '1', + DeviceType: 'PC', + OSType: navigator.platform, + OSVersion: '', + DRMProvider: cdmDescription.DRMProvider, + DRMVersion: cdmDescription.DRMVersion, + DRMType: cdmDescription.DRMType, + DeviceVendor: navigator.vendor, + DeviceModel: navigator.vendorSub + }, + }, }; } -export function createErrorForMalformedTitaniumDRMConfiguration( - configuration: TitaniumDRMConfiguration, - cdmType: TitaniumCDMType): ContentProtectionError { +export function createErrorForMalformedDeviceInfoConfiguration( + configuration: TitaniumDrmConfiguration, + cdmType: TitaniumCDMType, +): ContentProtectionError { let message = `Invalid Titanium ${cdmType} DRM configuration.`; - if (!configuration.accountName) { + if (!configuration.integrationParameters.accountName) { message = `Invalid Titanium ${cdmType} DRM configuration, accountName is not set.`; - } else if (!configuration.customerName) { + } else if (!configuration.integrationParameters.customerName) { message = `Invalid Titanium ${cdmType} DRM configuration, customerName is not set.`; - } else if (!configuration.portalId) { + } else if (!configuration.integrationParameters.portalId) { message = `Invalid Titanium ${cdmType} DRM configuration, portalId is not set.`; } throw { code: ErrorCode.CONTENT_PROTECTION_CONFIGURATION_INVALID, - message: message + message: message, + } as ContentProtectionError; +} + +export function createErrorForMalformedTokenConfiguration(configuration: TitaniumDrmConfiguration, cdmType: TitaniumCDMType): ContentProtectionError { + let message = `Invalid Titanium ${cdmType} DRM configuration.`; + if (!configuration.integrationParameters.authToken) { + message = `Invalid Titanium ${cdmType} DRM configuration, authToken is not set.`; + } + throw { + code: ErrorCode.CONTENT_PROTECTION_CONFIGURATION_INVALID, + message: message, } as ContentProtectionError; } -export function createTitaniumCustomData( - body: Uint8Array, - configuration: TitaniumDRMConfiguration, - cdmType: TitaniumCDMType): string { - if (isTokenBasedTitaniumDRMConfiguration(configuration)) { - return fromObjectToBase64String({ - AuthToken: configuration.authToken, - Payload: fromUint8ArrayToBase64String(body) - } as TitaniumRequestData); - } else if (isDeviceBasedTitaniumDRMConfiguration(configuration)) { - return fromObjectToBase64String({ - LatensRegistration: getTitaniumLicenseBaseRegistration(configuration, cdmType), - Payload: fromUint8ArrayToBase64String(body) - } as TitaniumRequestData); +export function createTitaniumAuthHeader(configuration: TitaniumDrmConfiguration, cdmType: TitaniumCDMType): string { + if (isTokenBasedTitaniumDRMConfiguration(configuration.integrationParameters)) { + return `Bearer ${configuration.integrationParameters.authToken}`; + } else { + throw createErrorForMalformedTokenConfiguration(configuration, cdmType); + } +} + +export function createTitaniumDeviceHeader(configuration: TitaniumDrmConfiguration, cdmType: TitaniumCDMType): string { + if (isDeviceBasedTitaniumDRMConfiguration(configuration.integrationParameters)) { + const conf = configuration.integrationParameters as DeviceBasedTitaniumIntegrationParameters; + const deviceAuthorizationData = getTitaniumDeviceAuthorizationData(conf, cdmType); + return fromObjectToBase64String(deviceAuthorizationData); } else { - throw createErrorForMalformedTitaniumDRMConfiguration(configuration, cdmType); + throw createErrorForMalformedDeviceInfoConfiguration(configuration, cdmType); } } -export function createTitaniumCDataHeader( - configuration: TitaniumDRMConfiguration, - cdmType: TitaniumCDMType): string { - if (isTokenBasedTitaniumDRMConfiguration(configuration)) { - return fromObjectToBase64String({AuthToken: configuration.authToken}); - } else if (isDeviceBasedTitaniumDRMConfiguration(configuration)) { - return fromObjectToBase64String({LatensRegistration: getTitaniumLicenseBaseRegistration(configuration, cdmType) }); +export function createTitaniumHeaders(configuration: TitaniumDrmConfiguration, cdmType: TitaniumCDMType): { [key: string]: string } { + const hasAuthToken = isTokenBasedTitaniumDRMConfiguration(configuration.integrationParameters); + if (hasAuthToken) { + return { + 'content-type': 'application/octet-stream', + Authorization: createTitaniumAuthHeader(configuration, cdmType), + }; } else { - throw createErrorForMalformedTitaniumDRMConfiguration(configuration, cdmType); + return { + 'content-type': 'application/octet-stream', + 'X-TITANIUM-DRM-CDATA': createTitaniumDeviceHeader(configuration, cdmType), + }; } } diff --git a/web/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts b/web/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts new file mode 100644 index 00000000..f4a2d1f4 --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts @@ -0,0 +1,10 @@ +import type { DRMConfiguration } from 'THEOplayer'; +import type { TitaniumIntegrationParameters } from './TitaniumIntegrationParameters'; + +export type TitaniumIntegrationID = 'titaniumdrm'; + +export interface TitaniumDrmConfiguration extends DRMConfiguration { + integration: TitaniumIntegrationID; + + integrationParameters: TitaniumIntegrationParameters; +} diff --git a/web/src/integration/titaniumdrm/TitaniumDrmIntegrationConfiguration.ts b/web/src/integration/titaniumdrm/TitaniumDrmIntegrationConfiguration.ts deleted file mode 100644 index bc8d3e94..00000000 --- a/web/src/integration/titaniumdrm/TitaniumDrmIntegrationConfiguration.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { TitaniumDRMConfiguration, DRMConfiguration } from 'THEOplayer'; - -/** - * The identifier of the Titanium integration. - */ -export type TitaniumIntegrationID = 'titaniumdrm'; - -export interface TitaniumDrmIntegrationConfiguration extends DRMConfiguration { - - integration: TitaniumIntegrationID; - - integrationParameters: TitaniumDRMConfiguration; -} diff --git a/web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts b/web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts new file mode 100644 index 00000000..341aa9bc --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts @@ -0,0 +1,28 @@ +import { isTitaniumDRMConfiguration } from './TitaniumUtils'; +import { createTitaniumHeaders, TitaniumCDMType } from './TitaniumBaseRegistration'; +import type { ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; + +export class TitaniumFairplayContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: TitaniumDrmConfiguration; + + constructor(drmConfiguration: TitaniumDrmConfiguration) { + if (!isTitaniumDRMConfiguration(drmConfiguration)) { + throw new Error('Titanium DRM has not been correctly configured.'); + } + this.contentProtectionConfiguration = drmConfiguration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.FAIRPLAY), + }; + return request; + } + + extractFairplayContentId(skdUrl: string): MaybeAsync { + // drop the 'skd://' part + return skdUrl.substring(6, skdUrl.length); + } +} diff --git a/web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts b/web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..2214924b --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts @@ -0,0 +1,9 @@ +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { TitaniumFairplayContentProtectionIntegration } from './TitaniumFairplayContentProtectionIntegration'; +import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; + +export class TitaniumFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: TitaniumDrmConfiguration): ContentProtectionIntegration { + return new TitaniumFairplayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts b/web/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts new file mode 100644 index 00000000..f27b9be5 --- /dev/null +++ b/web/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts @@ -0,0 +1,107 @@ +export interface TitaniumIntegrationParameters { + /** + * The account name. + * + * @remarks + *
- Required when doing device-based authentication. + */ + accountName?: string; + + /** + * The customer name. + * + * @remarks + *
- Required when doing device-based authentication. + */ + customerName?: string; + + /** + * The friendly name of the customer. + * + * @remarks + *
- Required when doing device-based authentication. + */ + friendlyName?: string; + + /** + * The identifier of the portal. + * + * @remarks + *
- Required when doing device-based authentication. + */ + portalId?: string; + + /** + * The authentication token. + * + * @remarks + *
- This is a JSON web token provided by the Titanium Secure Token Server. + *
- Required when doing token-based authentication. + */ + authToken?: string; +} + +export interface DeviceBasedTitaniumIntegrationParameters extends TitaniumIntegrationParameters { + /** + * The account name. + */ + accountName: string; + + /** + * The customer name. + */ + customerName: string; + + /** + * The friendly name of this customer. + */ + friendlyName: string; + + /** + * The identifier of the portal. + */ + portalId: string; + + /** + * The authentication token. + * + * @remarks + *
- This is a JSON web token provided by the Titanium Secure Token Server. + */ + authToken?: undefined; +} + +/** + * Describes the configuration of the Titanium DRM integration with token-based authentication. + * + * @public + */ +export interface TokenBasedTitaniumIntegrationParameters extends TitaniumIntegrationParameters { + /** + * The account name. + */ + accountName?: undefined; + + /** + * The customer name. + */ + customerName?: undefined; + + /** + * The friendly name of this customer. + */ + friendlyName?: undefined; + + /** + * The identifier of the portal. + */ + portalId?: undefined; + + /** + * The authentication token. + * + * @remarks + *
- This is a JSON web token provided by the Titanium Secure Token Server. + */ + authToken: string; +} diff --git a/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts b/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts index a93f7feb..890a0957 100644 --- a/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts +++ b/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts @@ -1,27 +1,32 @@ -import { BufferSource, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; import { isTitaniumDRMConfiguration } from './TitaniumUtils'; -import { TitaniumDrmIntegrationConfiguration } from './TitaniumDrmIntegrationConfiguration'; -import { createTitaniumCDataHeader, TitaniumCDMType } from './TitaniumBaseRegistration'; +import { createTitaniumHeaders, TitaniumCDMType } from './TitaniumBaseRegistration'; +import type { BufferSource, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; +import { CertificateRequest } from 'THEOplayer'; export class TitaniumPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: TitaniumDrmConfiguration; - private readonly contentProtectionConfiguration: TitaniumDrmIntegrationConfiguration; - - constructor(drmConfiguration: TitaniumDrmIntegrationConfiguration) { - if (!isTitaniumDRMConfiguration(drmConfiguration.integrationParameters)) { - throw new Error('The PlayReady Titanium authToken has not been correctly configured.'); + constructor(drmConfiguration: TitaniumDrmConfiguration) { + if (!isTitaniumDRMConfiguration(drmConfiguration)) { + throw new Error('Titanium DRM has not been correctly configured.'); } this.contentProtectionConfiguration = drmConfiguration; } + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE), + }; + return request; + } + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - const { version } = this.contentProtectionConfiguration.integrationParameters; - const cdmType = version === '2' ? TitaniumCDMType.PLAYREADY_v2 : TitaniumCDMType.PLAYREADY_v3; request.headers = { ...request.headers, - 'Content-Type': 'text/xml; charset=utf-8', - 'X-TITANIUM-DRM-CDATA': createTitaniumCDataHeader(this.contentProtectionConfiguration.integrationParameters, cdmType) - } + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE), + }; return request; } } diff --git a/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts b/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts index 5bbc0d9c..2c27f66d 100644 --- a/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts +++ b/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts @@ -1,9 +1,9 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; import { TitaniumPlayReadyContentProtectionIntegration } from './TitaniumPlayReadyContentProtectionIntegration'; -import { TitaniumDrmIntegrationConfiguration } from './TitaniumDrmIntegrationConfiguration'; export class TitaniumPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - build(configuration: TitaniumDrmIntegrationConfiguration): ContentProtectionIntegration { + build(configuration: TitaniumDrmConfiguration): ContentProtectionIntegration { return new TitaniumPlayReadyContentProtectionIntegration(configuration); } } diff --git a/web/src/integration/titaniumdrm/TitaniumUtils.ts b/web/src/integration/titaniumdrm/TitaniumUtils.ts index 23849910..8e4eea16 100644 --- a/web/src/integration/titaniumdrm/TitaniumUtils.ts +++ b/web/src/integration/titaniumdrm/TitaniumUtils.ts @@ -1,19 +1,28 @@ -import { TitaniumDRMConfiguration, DeviceBasedTitaniumDRMConfiguration, TokenBasedTitaniumDRMConfiguration } from 'THEOplayer'; +/* eslint-disable no-undef */ +import type { + DeviceBasedTitaniumIntegrationParameters, + TitaniumIntegrationParameters, + TokenBasedTitaniumIntegrationParameters, +} from './TitaniumIntegrationParameters'; +import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; -export function isTitaniumDRMConfiguration(configuration: TitaniumDRMConfiguration): boolean { - return isTokenBasedTitaniumDRMConfiguration(configuration) || isDeviceBasedTitaniumDRMConfiguration((configuration)); +export function isTitaniumDRMConfiguration(configuration: TitaniumDrmConfiguration): boolean { + const integrationParameters = configuration.integrationParameters; + return isTokenBasedTitaniumDRMConfiguration(integrationParameters) || isDeviceBasedTitaniumDRMConfiguration(integrationParameters); } -// eslint-disable-next-line no-undef -export function isTokenBasedTitaniumDRMConfiguration(configuration: TitaniumDRMConfiguration): configuration is TokenBasedTitaniumDRMConfiguration { - return configuration.authToken !== undefined; +export function isTokenBasedTitaniumDRMConfiguration( + integrationParameters: TitaniumIntegrationParameters, +): integrationParameters is TokenBasedTitaniumIntegrationParameters { + return integrationParameters.authToken !== undefined; } -// eslint-disable-next-line no-undef -export function isDeviceBasedTitaniumDRMConfiguration(configuration: TitaniumDRMConfiguration): configuration is DeviceBasedTitaniumDRMConfiguration { +export function isDeviceBasedTitaniumDRMConfiguration( + integrationParameters: TitaniumIntegrationParameters, +): integrationParameters is DeviceBasedTitaniumIntegrationParameters { return ( - configuration.accountName !== undefined && - configuration.customerName !== undefined && - configuration.portalId !== undefined + integrationParameters.accountName !== undefined && + integrationParameters.customerName !== undefined && + integrationParameters.portalId !== undefined ); } diff --git a/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts b/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts index c7375dc7..4e385e63 100644 --- a/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts +++ b/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts @@ -1,51 +1,32 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource, - CertificateRequest, - LicenseResponse -} from 'THEOplayer'; -import { TitaniumDrmIntegrationConfiguration } from './TitaniumDrmIntegrationConfiguration'; import { isTitaniumDRMConfiguration } from './TitaniumUtils'; -import { - fromBase64StringToUint8Array, - fromStringToUint8Array, - fromUint8ArrayToObject, -} from '../../utils/TypeUtils'; -import TitaniumWidevineLicenseResponse from './TitaniumWidevineLicenseResponse'; -import { - createTitaniumCustomData, - TitaniumCDMType -} from './TitaniumBaseRegistration'; +import { createTitaniumHeaders, TitaniumCDMType } from './TitaniumBaseRegistration'; +import type { BufferSource, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; +import type { CertificateRequest } from 'THEOplayer'; export class TitaniumWidevineContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: TitaniumDrmConfiguration; - private readonly contentProtectionConfiguration: TitaniumDrmIntegrationConfiguration; - - constructor(configuration: TitaniumDrmIntegrationConfiguration) { - if (!isTitaniumDRMConfiguration(configuration.integrationParameters)) { - throw new Error('The Widevine Titanium authToken has not been correctly configured.'); + constructor(drmConfiguration: TitaniumDrmConfiguration) { + if (!isTitaniumDRMConfiguration(drmConfiguration)) { + throw new Error('Titanium DRM has not been correctly configured.'); } - this.contentProtectionConfiguration = configuration; + this.contentProtectionConfiguration = drmConfiguration; } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - const { integrationParameters } = this.contentProtectionConfiguration; - const customData = createTitaniumCustomData(request.body!, integrationParameters, TitaniumCDMType.WIDEVINE); - request.body = fromStringToUint8Array(customData); + request.headers = { + ...request.headers, + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE), + }; return request; } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - const { integrationParameters } = this.contentProtectionConfiguration; - const customData = createTitaniumCustomData(request.body!, integrationParameters, TitaniumCDMType.WIDEVINE); - request.body = fromStringToUint8Array(customData); + request.headers = { + ...request.headers, + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE), + }; return request; } - - onLicenseResponse(response: LicenseResponse): MaybeAsync { - const responseObject = fromUint8ArrayToObject(response.body) as TitaniumWidevineLicenseResponse; - return fromBase64StringToUint8Array(responseObject.license); - } } diff --git a/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts index 765403b5..f34c01d1 100644 --- a/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts +++ b/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts @@ -1,12 +1,9 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; import { TitaniumWidevineContentProtectionIntegration } from './TitaniumWidevineContentProtectionIntegration'; -import { TitaniumDrmIntegrationConfiguration } from './TitaniumDrmIntegrationConfiguration'; export class TitaniumWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - build(configuration: TitaniumDrmIntegrationConfiguration): ContentProtectionIntegration { + build(configuration: TitaniumDrmConfiguration): ContentProtectionIntegration { return new TitaniumWidevineContentProtectionIntegration(configuration); } } diff --git a/web/src/integration/titaniumdrm/TitaniumWidevineLicenseResponse.ts b/web/src/integration/titaniumdrm/TitaniumWidevineLicenseResponse.ts deleted file mode 100644 index 7097d6a5..00000000 --- a/web/src/integration/titaniumdrm/TitaniumWidevineLicenseResponse.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default interface TitaniumWidevineLicenseResponse { - can_play: boolean; - license: string; -} From 2cd44d48765256cd37e681fc54b24d52b931f4de Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 16 Nov 2022 16:25:32 +0100 Subject: [PATCH 42/85] Update lint rules and tsconfig --- web/.eslintrc.json | 11 ++++++++--- web/tsconfig.json | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/web/.eslintrc.json b/web/.eslintrc.json index 46894b75..1a794348 100644 --- a/web/.eslintrc.json +++ b/web/.eslintrc.json @@ -4,7 +4,9 @@ "es2021": true }, "extends": [ - "eslint:recommended" + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" ], "parser": "@typescript-eslint/parser", "parserOptions": { @@ -14,5 +16,8 @@ "plugins": [ "@typescript-eslint" ], - "rules": {} -} \ No newline at end of file + "rules": { + "max-len": ["error", { "code": 150, "ignoreComments": true, "ignoreStrings": true, "ignoreTemplateLiterals": true }], + "@typescript-eslint/explicit-module-boundary-types": "off" + } +} diff --git a/web/tsconfig.json b/web/tsconfig.json index c0f4632a..5f846b79 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -6,7 +6,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ + "lib": ["es6", "dom"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ From 05616912fdc5d5072906fda411b0bc44dab7f24a Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 16 Nov 2022 16:25:54 +0100 Subject: [PATCH 43/85] Fix trivial lint warnings --- .../ComcastDrmFairPlayContentProtectionIntegration.ts | 6 +++--- .../ComcastDrmWidevineContentProtectionIntegration.ts | 8 ++++---- .../IrdetoControlFairplayContentProtectionIntegration.ts | 4 ++-- .../keyos/KeyOSDrmFairplayContentProtectionIntegration.ts | 2 +- web/src/integration/keyos/KeyOSDrmUtils.ts | 2 +- .../VerimatrixDrmFairPlayContentProtectionIntegration.ts | 6 +++--- ...ultiDRMStandardFairPlayContentProtectionIntegration.ts | 6 +++--- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts index 05a03b5f..891c0215 100644 --- a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -33,15 +33,15 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr throw new Error('The FairPlay ComcastDRM license url has not been correctly configured.'); } const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; - let spcMessage = fromUint8ArrayToBase64String(request.body!); - let body = { + const spcMessage = fromUint8ArrayToBase64String(request.body!); + const body = { "getFairplayLicense": { "releasePid": releasePid, "spcMessage": spcMessage } }; - let newBody = fromObjectToUint8Array(body); + const newBody = fromObjectToUint8Array(body); return { ...request, url: request.url + `&token=${token}&account=${account}&form=json`, diff --git a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts index 8b0b674a..5f59e182 100644 --- a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts +++ b/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts @@ -21,8 +21,8 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; - let widevineChallenge = fromUint8ArrayToBase64String(request.body!); - let body = { + const widevineChallenge = fromUint8ArrayToBase64String(request.body!); + const body = { "getWidevineLicense": { "releasePid": releasePid, "widevineChallenge": widevineChallenge @@ -47,8 +47,8 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr throw new Error('The Widevine AzureDRM license url has not been correctly configured.'); } const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; - let widevineChallenge = fromUint8ArrayToBase64String(request.body!); - let body = { + const widevineChallenge = fromUint8ArrayToBase64String(request.body!); + const body = { "getWidevineLicense": { "releasePid": releasePid, "widevineChallenge": widevineChallenge diff --git a/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts b/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts index bcbc8c91..c78ec3e1 100644 --- a/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts +++ b/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts @@ -55,7 +55,7 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten } extractFairplayContentId(skdUrl: string): string { - let parameters = skdUrl.split("?")[1].split("&"); + const parameters = skdUrl.split("?")[1].split("&"); for (let i = 0; i < parameters.length; i++) { const pair = parameters[i].split("="); if (pair[0] == "contentId") { @@ -67,7 +67,7 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten return skdUrl; } - hasQueryParameter(url: string, parameter: string): Boolean { + hasQueryParameter(url: string, parameter: string): boolean { const queryParameters = url.split("?"); if (!queryParameters || !queryParameters[1]) { return false; diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts index c6f835aa..e5852e0e 100644 --- a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts +++ b/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -54,7 +54,7 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - let bodyAsString = fromUint8ArrayToUtf8String(response.body) + const bodyAsString = fromUint8ArrayToUtf8String(response.body) let keyText = bodyAsString.trim() if (keyText.substr(0, 5) === '' && keyText.substr(-6) === '') { keyText = keyText.slice(5, -6) diff --git a/web/src/integration/keyos/KeyOSDrmUtils.ts b/web/src/integration/keyos/KeyOSDrmUtils.ts index 785d977f..afc951ee 100644 --- a/web/src/integration/keyos/KeyOSDrmUtils.ts +++ b/web/src/integration/keyos/KeyOSDrmUtils.ts @@ -8,7 +8,7 @@ export function extractContentId(skdUrl: string): string { if (skdUrl.indexOf("skd") > 0 || skdUrl.indexOf("http") > 0) { skdUrl = skdUrl.substring(1); } - var link = document.createElement('a'); + const link = document.createElement('a'); link.href = skdUrl; return link.hostname; } \ No newline at end of file diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts index 18e634a3..3af505b3 100644 --- a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts @@ -25,11 +25,11 @@ export class VerimatrixDrmFairPlayContentProtectionIntegration implements Conten } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - let spcMessage = fromUint8ArrayToBase64String(request.body!); - let body = { + const spcMessage = fromUint8ArrayToBase64String(request.body!); + const body = { "spc": spcMessage }; - let newBody = fromObjectToUint8Array(body); + const newBody = fromObjectToUint8Array(body); const newRequest = { ...request, url: this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? diff --git a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts index 8897d537..cb362bc4 100644 --- a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts +++ b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts @@ -24,13 +24,13 @@ export class VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration impl } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - let spcMessage = fromUint8ArrayToBase64String(request.body!); - let url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; + const spcMessage = fromUint8ArrayToBase64String(request.body!); + const url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; if (!this.contentId) { throw new Error('The FairPlay Verimatrix Multi-DRM Standard content ID has not been correctly configured.'); } const licenseParameters = `spc=${encodeURIComponent(spcMessage)}&assetId=${encodeURIComponent(this.contentId)}`; - let newBody = fromStringToUint8Array(licenseParameters); + const newBody = fromStringToUint8Array(licenseParameters); const newRequest = { ...request, url: url, From 51c143591f99d8c623da0bb640804d9c143ee71d Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 16 Nov 2022 16:57:04 +0100 Subject: [PATCH 44/85] Update titanium test pages --- web/src/index.ts | 3 ++ web/test/titaniumdrm/fairplay.html | 46 +++++++++++++++++++++++++++++ web/test/titaniumdrm/playready.html | 1 - web/test/titaniumdrm/widevine.html | 1 - 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 web/test/titaniumdrm/fairplay.html diff --git a/web/src/index.ts b/web/src/index.ts index 47dd8ae8..d5fed2bd 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -46,6 +46,8 @@ import { TitaniumWidevineContentProtectionIntegrationFactory } from "./integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory"; import { TitaniumPlayReadyContentProtectionIntegrationFactory} from "./integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory"; +import { TitaniumFairplayContentProtectionIntegrationFactory} from + "./integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory"; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -72,6 +74,7 @@ export { VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory, TitaniumWidevineContentProtectionIntegrationFactory, TitaniumPlayReadyContentProtectionIntegrationFactory, + TitaniumFairplayContentProtectionIntegrationFactory, }; export const THEOPLAYER_LICENSE = "YOUR_LICENSE_HERE"; \ No newline at end of file diff --git a/web/test/titaniumdrm/fairplay.html b/web/test/titaniumdrm/fairplay.html new file mode 100644 index 00000000..1bdfffb6 --- /dev/null +++ b/web/test/titaniumdrm/fairplay.html @@ -0,0 +1,46 @@ + + + + + Titanium DRM Fairplay Test Using AuthToken + + + + + +
+ + + diff --git a/web/test/titaniumdrm/playready.html b/web/test/titaniumdrm/playready.html index dc995b21..50e544db 100644 --- a/web/test/titaniumdrm/playready.html +++ b/web/test/titaniumdrm/playready.html @@ -6,7 +6,6 @@ -
diff --git a/web/test/titaniumdrm/widevine.html b/web/test/titaniumdrm/widevine.html index 186ea8aa..b955aa2e 100644 --- a/web/test/titaniumdrm/widevine.html +++ b/web/test/titaniumdrm/widevine.html @@ -6,7 +6,6 @@ -
From d77a4fc0b57972a1ed495d7cf607d19ef3ecbfdb Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 16 Nov 2022 16:57:19 +0100 Subject: [PATCH 45/85] Remove start script --- web/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/web/package.json b/web/package.json index 2097e8a1..2adf048c 100644 --- a/web/package.json +++ b/web/package.json @@ -5,7 +5,6 @@ "main": "index.js", "scripts": { "server": "http-server", - "start": "ts-node src/index.ts", "build": "rollup -c ./rollup.config.js", "eslint": "eslint 'src/**/*.ts'" }, From 88fff85787c45b2e1c6f04ee51a353c3a9725587 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 16 Nov 2022 16:57:46 +0100 Subject: [PATCH 46/85] Update package-lock --- web/package-lock.json | 2984 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 2982 insertions(+), 2 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 2a36f565..38021daa 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,8 +1,2987 @@ { "name": "drm-api-plugins", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "drm-api-plugins", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@types/long": "^4.0.1", + "conditional-type-checks": "^1.0.5", + "lodash": "^4.17.20", + "long": "^4.0.0" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^15.0.0", + "@rollup/plugin-node-resolve": "^9.0.0", + "@rollup/plugin-typescript": "^5.0.2", + "@types/lodash": "^4.14.161", + "@types/node": "^14.6.3", + "@typescript-eslint/eslint-plugin": "^4.0.1", + "@typescript-eslint/parser": "^4.0.1", + "eslint": "^7.8.1", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-plugin-import": "^2.22.0", + "http-server": "^0.12.3", + "rollup": "^2.26.9", + "rollup-plugin-copy": "^3.4.0", + "theoplayer": "latest", + "ts-node": "^9.0.0", + "tslib": "^2.0.1", + "typescript": "^4.0.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", + "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz", + "integrity": "sha512-8uAdikHqVyrT32w1zB9VhW6uGwGjhKgnDNP4pQJsjdnyF4FgCj6/bmv24c7v2CuKhq32CcyCwRzMPEElaKkn0w==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^2.22.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz", + "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-5.0.2.tgz", + "integrity": "sha512-CkS028Itwjqm1uLbFVfpJgtVtnNvZ+og/m6UlNRR5wOOnNTWPcVQzOu5xGdEX+WWJxdvWIqUq2uR/RBt2ZipWg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.1", + "resolve": "^1.14.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0", + "tslib": "*", + "typescript": ">=3.4.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/@types/fs-extra": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", + "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.161", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", + "integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA==", + "dev": true + }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz", + "integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww==", + "dev": true + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz", + "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.0.1", + "@typescript-eslint/scope-manager": "4.0.1", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz", + "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.0.1", + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/typescript-estree": "4.0.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz", + "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "4.0.1", + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/typescript-estree": "4.0.1", + "debug": "^4.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz", + "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/visitor-keys": "4.0.1" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz", + "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz", + "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/visitor-keys": "4.0.1", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz", + "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.0.1", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/conditional-type-checks": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/conditional-type-checks/-/conditional-type-checks-1.0.5.tgz", + "integrity": "sha512-DkfkvmjXVe4ye4llJ1JADtO3dNvqqcQM08cA9BhNt9Oe8pyRW8X1CZyBg9Qst05bDV9BJM01KLmnFh78NcJgNg==" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", + "dev": true + }, + "node_modules/contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "deprecated": "This package is unmaintained and deprecated. See the GH Issue 259.", + "dev": true, + "dependencies": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + }, + "bin": { + "ecstatic": "lib/ecstatic.js" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", + "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.1.3", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", + "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.9", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", + "eslint-plugin-import": "^2.21.2" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", + "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", + "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-server": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", + "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", + "dev": true, + "dependencies": { + "basic-auth": "^1.0.3", + "colors": "^1.4.0", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.18.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.25", + "secure-compare": "3.0.1", + "union": "~0.5.0" + }, + "bin": { + "hs": "bin/http-server", + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.entries": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", + "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "dev": true, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "dependencies": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "dependencies": { + "pify": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rollup": { + "version": "2.26.9", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.9.tgz", + "integrity": "sha512-XIiWYLayLqV+oY4S2Lub/shJq4uk/QQLwWToYCL4LjZbYHbFK3czea4UDVRUJu+zNmKmxq5Zb/OG7c5HSvH2TQ==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/rollup-plugin-copy": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", + "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", + "dev": true, + "dependencies": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "engines": { + "node": ">=8.3" + } + }, + "node_modules/rollup-plugin-copy/node_modules/globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, + "node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/theoplayer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-3.0.0.tgz", + "integrity": "sha512-tYeFmEAgMYEBQENfK5/7MRsMM1CecOrsvuoFrfPC0hvWTA26nr2anog9xqEN8z9RVBFLso7UPzybDIVOg2Dw/w==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", + "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", + "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.10.4", @@ -321,7 +3300,8 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true + "dev": true, + "requires": {} }, "ajv": { "version": "6.12.4", From a4c1071ad89ad4ba90652e411380f7a838ab28b5 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Thu, 17 Nov 2022 09:38:30 +0100 Subject: [PATCH 47/85] Add Titanium device-base example for web --- web/README.md | 2 +- web/test/titaniumdrm/fairplay.html | 31 +++++++++++++++++++++++++---- web/test/titaniumdrm/playready.html | 24 +++++++++++++++++++++- web/test/titaniumdrm/widevine.html | 25 ++++++++++++++++++++++- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/web/README.md b/web/README.md index 27da39b1..858d2cc4 100644 --- a/web/README.md +++ b/web/README.md @@ -279,7 +279,7 @@ For the `onCertificateResponse()` and `onLicenseResponse()` hooks the return typ - Nagra DRM - Vualto VuDRM - Verimatrix MultiDRM Core DRM -- Titanium DRM +- Arris Titanium DRM ### Testing an integration diff --git a/web/test/titaniumdrm/fairplay.html b/web/test/titaniumdrm/fairplay.html index 1bdfffb6..cdd1701d 100644 --- a/web/test/titaniumdrm/fairplay.html +++ b/web/test/titaniumdrm/fairplay.html @@ -2,7 +2,7 @@ - Titanium DRM Fairplay Test Using AuthToken + Titanium DRM Fairplay Test Using AuthToken or device parameters @@ -20,7 +20,7 @@ }); THEOplayer.registerContentProtectionIntegration( - 'titanium', + 'titaniumdrm', 'fairplay', new ContentProtectionIntegrations.TitaniumFairplayContentProtectionIntegrationFactory() ); @@ -31,16 +31,39 @@ contentProtection: { fairplay: { certificate: 'insert raw certificate', - certificateUrl: 'or optional certificateUrl>', + certificateUrl: 'or optional certificateUrl', licenseAcquisitionURL: 'insert license url here' }, - integration: 'titanium', + integration: 'titaniumdrm', integrationParameters: { authToken: 'insert auth token' } } } }; + + // // Alternatively, use device parameters instead of an authToken + // player.source = { + // sources: [ + // { + // src: 'insert manifest url here', + // contentProtection: { + // fairplay: { + // certificate: 'insert raw certificate', + // certificateUrl: 'or optional certificateUrl', + // licenseAcquisitionURL: 'insert license url here' + // }, + // integration: 'titaniumdrm', + // integrationParameters: { + // accountName: 'replace with accountName', + // customerName: 'replace with customerName', + // friendlyName: 'replace with friendlyName', + // portalId: 'replace with portalId' + // } + // } + // } + // ], + // }; diff --git a/web/test/titaniumdrm/playready.html b/web/test/titaniumdrm/playready.html index 50e544db..2573d98a 100644 --- a/web/test/titaniumdrm/playready.html +++ b/web/test/titaniumdrm/playready.html @@ -2,7 +2,7 @@ - Titanium DRM PlayReady Test using AuthToken + Titanium DRM PlayReady Test using AuthToken or device parameters @@ -42,6 +42,28 @@ } ], }; + + // // Alternatively, use device parameters instead of an authToken + // player.source = { + // sources: [ + // { + // src: 'insert manifest url here', + // contentProtection: { + // widevine: { + // licenseAcquisitionURL: 'insert license url here' + // }, + // preferredKeySystems: ['playready'], + // integration: 'titaniumdrm', + // integrationParameters: { + // accountName: 'replace with accountName', + // customerName: 'replace with customerName', + // friendlyName: 'replace with friendlyName', + // portalId: 'replace with portalId' + // } + // } + // } + // ], + // }; diff --git a/web/test/titaniumdrm/widevine.html b/web/test/titaniumdrm/widevine.html index b955aa2e..fb94b276 100644 --- a/web/test/titaniumdrm/widevine.html +++ b/web/test/titaniumdrm/widevine.html @@ -2,7 +2,7 @@ - Titanium DRM Widevine Test Using AuthToken + Titanium DRM Widevine Test Using AuthToken or device parameters @@ -43,6 +43,29 @@ } ], }; + + // // Alternatively, use device parameters instead of an authToken + // player.source = { + // sources: [ + // { + // src: 'insert manifest url here', + // contentProtection: { + // widevine: { + // persistentState: 'required', + // licenseAcquisitionURL: 'insert license url here' + // }, + // preferredKeySystems: ['widevine'], + // integration: 'titaniumdrm', + // integrationParameters: { + // accountName: 'replace with accountName', + // customerName: 'replace with customerName', + // friendlyName: 'replace with friendlyName', + // portalId: 'replace with portalId' + // } + // } + // } + // ], + // }; From 564b88a9873c9edc0d2230affa36ddd0b4c237e2 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Mon, 14 Nov 2022 16:14:40 +0100 Subject: [PATCH 48/85] Upgrade dependencies and convert to Kotlin --- android/app/build.gradle | 26 ++- android/app/src/main/AndroidManifest.xml | 11 +- .../MainActivity.java | 20 --- .../MainActivity.kt | 40 +++++ .../PlayerActivity.java | 54 ------ .../PlayerActivity.kt | 53 ++++++ .../SourceListFragment.java | 36 ---- .../SourceManager.java | 161 ----------------- .../SourceManager.kt | 142 +++++++++++++++ .../TypeUtils.java | 24 --- .../contentprotectionintegration/TypeUtils.kt | 24 +++ ...eWidevineContentProtectionIntegration.java | 36 ---- ...ureWidevineContentProtectionIntegration.kt | 29 +++ ...neContentProtectionIntegrationFactory.java | 12 -- ...vineContentProtectionIntegrationFactory.kt | 11 ++ ...sWidevineContentProtectionIntegration.java | 29 --- ...yOsWidevineContentProtectionIntegration.kt | 20 +++ ...neContentProtectionIntegrationFactory.java | 15 -- ...vineContentProtectionIntegrationFactory.kt | 11 ++ ...mWidevineContentProtectionIntegration.java | 67 ------- ...drmWidevineContentProtectionIntegration.kt | 61 +++++++ ...neContentProtectionIntegrationFactory.java | 12 -- ...vineContentProtectionIntegrationFactory.kt | 11 ++ .../main/res/drawable-hdpi/ic_theo_logo.png | Bin 0 -> 4073 bytes .../main/res/drawable-mdpi/ic_theo_logo.png | Bin 0 -> 2731 bytes .../drawable-v24/ic_launcher_foreground.xml | 30 ---- .../main/res/drawable-xhdpi/ic_theo_logo.png | Bin 0 -> 6067 bytes .../main/res/drawable-xxhdpi/ic_theo_logo.png | Bin 0 -> 8193 bytes .../res/drawable-xxxhdpi/ic_theo_logo.png | Bin 0 -> 10983 bytes .../res/drawable/ic_launcher_background.xml | 170 ------------------ .../res/drawable/ic_launcher_foreground.xml | 30 ++++ .../src/main/res/drawable/splash_screen.xml | 10 ++ .../app/src/main/res/layout/activity_main.xml | 16 +- .../src/main/res/layout/activity_player.xml | 12 ++ android/app/src/main/res/layout/list_item.xml | 14 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 10 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 10 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3593 -> 4068 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 2101 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 5339 -> 4068 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2636 -> 2653 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 1394 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 3388 -> 2653 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4926 -> 5761 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 2859 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 7472 -> 5761 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7909 -> 8884 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 4312 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 11873 -> 8884 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 10652 -> 12447 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 5893 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 16570 -> 12447 bytes android/app/src/main/res/values/colors.xml | 6 - android/app/src/main/res/values/strings.xml | 3 - android/app/src/main/res/values/styles.xml | 29 ++- android/app/src/main/res/values/values.xml | 14 ++ android/build.gradle | 13 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 58 files changed, 559 insertions(+), 715 deletions(-) delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceListFragment.java delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.java create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.kt create mode 100644 android/app/src/main/res/drawable-hdpi/ic_theo_logo.png create mode 100644 android/app/src/main/res/drawable-mdpi/ic_theo_logo.png delete mode 100644 android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 android/app/src/main/res/drawable-xhdpi/ic_theo_logo.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/ic_theo_logo.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/ic_theo_logo.png delete mode 100644 android/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 android/app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 android/app/src/main/res/drawable/splash_screen.xml create mode 100644 android/app/src/main/res/layout/list_item.xml create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/values/colors.xml delete mode 100644 android/app/src/main/res/values/strings.xml create mode 100644 android/app/src/main/res/values/values.xml diff --git a/android/app/build.gradle b/android/app/build.gradle index 4f7977be..2c02cf88 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,21 +1,31 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' android { - compileSdkVersion 30 - buildToolsVersion "30.0.1" + compileSdkVersion 33 + buildToolsVersion "30.0.2" defaultConfig { applicationId "com.theoplayer.contentprotectionintegration" - minSdkVersion 21 - targetSdkVersion 30 + minSdkVersion 24 + targetSdkVersion 33 multiDexEnabled true + versionCode 1 + versionName "1.0" + } + + buildFeatures { + viewBinding = true } } dependencies { - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.1' - implementation 'com.google.code.gson:gson:2.8.6' - implementation 'com.theoplayer.theoplayer-sdk-android:basic-minapi21:+' + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'com.google.android.material:material:1.6.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'com.theoplayer.theoplayer-sdk-android:unified:+' implementation 'com.android.support:multidex:1.0.3' + implementation 'androidx.core:core-ktx:1.9.0' } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 47e6ca60..dba4f363 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,15 +7,18 @@ + android:theme="@style/TheoTheme.Base"> + - + android:value="@string/theoplayer_license" /> + + diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.java deleted file mode 100644 index 69497e69..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.theoplayer.contentprotectionintegration; - -import android.os.Bundle; - -import androidx.appcompat.app.AppCompatActivity; - -public class MainActivity extends AppCompatActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - getSupportFragmentManager() - .beginTransaction() - .add(R.id.frame_container, new SourceListFragment(), SourceListFragment.TAG) - .disallowAddToBackStack() - .commit(); - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt new file mode 100644 index 00000000..ec4f545f --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt @@ -0,0 +1,40 @@ +package com.theoplayer.contentprotectionintegration + +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.widget.AdapterView +import android.widget.AdapterView.OnItemClickListener +import android.widget.ArrayAdapter +import androidx.appcompat.app.AppCompatActivity +import com.theoplayer.contentprotectionintegration.databinding.ActivityMainBinding + +const val EXTRA_SOURCE_NAME = "sourceName" + +class MainActivity : AppCompatActivity() { + private lateinit var viewBinding: ActivityMainBinding + + override fun onCreate(savedInstanceState: Bundle?) { + setTheme(R.style.TheoTheme_Base) + super.onCreate(savedInstanceState) + + // Inflating view and obtaining an instance of the binding class. + viewBinding = ActivityMainBinding.inflate(layoutInflater) + val view = viewBinding.root + setContentView(view) + + populateSources() + } + + private fun populateSources() { + val listView = viewBinding.sourceList + val adapter = ArrayAdapter(this, R.layout.list_item, R.id.list_item_name, SourceManager.getInstance(this).sourcesNames) + listView.adapter = adapter + listView.onItemClickListener = + OnItemClickListener { _: AdapterView<*>?, _: View?, position: Int, _: Long -> + val intent = Intent(this, PlayerActivity::class.java) + intent.putExtra(EXTRA_SOURCE_NAME, adapter.getItem(position)) + startActivity(intent) + } + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java deleted file mode 100644 index 06d3a3be..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.theoplayer.contentprotectionintegration; - -import android.os.Bundle; - -import androidx.appcompat.app.AppCompatActivity; - -import com.theoplayer.android.api.THEOplayerView; -import com.theoplayer.android.api.source.SourceDescription; - -public class PlayerActivity extends AppCompatActivity { - - public final static String EXTRA_SOURCENAME = "sourceName"; - - private THEOplayerView playerView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_player); - - Bundle extras = getIntent().getExtras(); - if (extras != null) { - String sourceName = extras.getString(EXTRA_SOURCENAME); - playerView = findViewById(R.id.theoplayer); - SourceDescription sourceDescription = SourceManager.getInstance(this).getSource(sourceName); - playerView.getPlayer().setSource(sourceDescription); - playerView.getPlayer().play(); - } - } - - @Override - protected void onPause() { - super.onPause(); - if (playerView != null) { - playerView.onPause(); - } - } - - @Override - protected void onResume() { - super.onResume(); - if (playerView != null) { - playerView.onResume(); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - if (playerView != null) { - playerView.onDestroy(); - } - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.kt new file mode 100644 index 00000000..0fbac665 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.kt @@ -0,0 +1,53 @@ +package com.theoplayer.contentprotectionintegration + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.theoplayer.android.api.THEOplayerView +import com.theoplayer.android.api.event.player.PlayerEventTypes +import com.theoplayer.contentprotectionintegration.databinding.ActivityPlayerBinding + +class PlayerActivity : AppCompatActivity() { + private lateinit var playerView: THEOplayerView + private lateinit var viewBinding: ActivityPlayerBinding + + override fun onCreate(savedInstanceState: Bundle?) { + setTheme(R.style.TheoTheme_Base) + super.onCreate(savedInstanceState) + + viewBinding = ActivityPlayerBinding.inflate(layoutInflater) + val view = viewBinding.root + setContentView(view) + + playerView = viewBinding.theoplayer + playerView.player.addEventListener(PlayerEventTypes.ERROR) { error -> + viewBinding.message.text = error.errorObject.message + } + + // Get source description from the extras bundle + val extras = intent.extras + if (extras != null) { + val sourceName = extras.getString(EXTRA_SOURCE_NAME) + val sourceDescription = SourceManager.getInstance(this).getSource(sourceName) + + playerView.player.apply { + source = sourceDescription + play() + } + } + } + + override fun onPause() { + super.onPause() + playerView.onPause() + } + + override fun onResume() { + super.onResume() + playerView.onResume() + } + + override fun onDestroy() { + super.onDestroy() + playerView.onDestroy() + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceListFragment.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceListFragment.java deleted file mode 100644 index 2450f78e..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceListFragment.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.theoplayer.contentprotectionintegration; - -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -import androidx.annotation.NonNull; -import androidx.fragment.app.ListFragment; - -public class SourceListFragment extends ListFragment { - - public final static String TAG = "SourceList"; - - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - if (getActivity() != null) { - String[] sourceNames = SourceManager.getInstance(getActivity()).getSourcesNames(); - ArrayAdapter adapter = - new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, sourceNames); - setListAdapter(adapter); - } - } - - @Override - public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) { - if (getListAdapter() == null) { - return; - } - String item = (String) getListAdapter().getItem(position); - Intent intent = new Intent(getActivity(), PlayerActivity.class); - intent.putExtra(PlayerActivity.EXTRA_SOURCENAME, item); - startActivity(intent); - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java deleted file mode 100644 index f1f72672..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.theoplayer.contentprotectionintegration; - -import android.content.Context; - -import com.theoplayer.android.api.THEOplayerGlobal; -import com.theoplayer.android.api.contentprotection.KeySystemId; -import com.theoplayer.android.api.source.SourceDescription; -import com.theoplayer.android.api.source.drm.DRMConfiguration; -import com.theoplayer.contentprotectionintegration.integration.azuredrm.AzureWidevineContentProtectionIntegrationFactory; -import com.theoplayer.contentprotectionintegration.integration.keyos.KeyOsWidevineContentProtectionIntegrationFactory; -import com.theoplayer.contentprotectionintegration.integration.vudrm.VudrmWidevineContentProtectionIntegrationFactory; - -import java.util.HashMap; - -import static com.theoplayer.android.api.source.SourceDescription.Builder.sourceDescription; -import static com.theoplayer.android.api.source.TypedSource.Builder.typedSource; -import static com.theoplayer.android.api.source.drm.KeySystemConfiguration.Builder.keySystemConfiguration; - -public class SourceManager { - - private static SourceManager instance = null; - - private HashMap sources = new HashMap<>(); - - private SourceManager(Context context) { - initSources(context); - } - - public static SourceManager getInstance(Context context) { - if (SourceManager.instance == null) { - instance = new SourceManager(context); - } - return instance; - } - - public SourceDescription getSource(String name) { - return sources.get(name); - } - - public String[] getSourcesNames() { - return sources.keySet().toArray(new String[0]); - } - - private SourceDescription buildWidevineSourceDescription( - String integrationId, - String manifestUrl, - String licenseUrl, - HashMap integrationParams) { - return sourceDescription( - typedSource(manifestUrl) - .drm(new DRMConfiguration.Builder() - .customIntegrationId(integrationId) - .integrationParameters(integrationParams) - .widevine(keySystemConfiguration(licenseUrl).build()) - .build()) - .build() - ).build(); - } - - private SourceDescription buildDefaultWidevineSourceDescription( - String manifestUrl, - String licenseUrl, - HashMap headers) { - return sourceDescription( - typedSource(manifestUrl) - .drm(new DRMConfiguration.Builder() - .widevine( - keySystemConfiguration(licenseUrl) - .headers(headers) - .build() - ) - .build()) - .build() - ).build(); - } - - - private void initSources(Context context) { - // Vualto VUDRM Widevine content protect integration - String VUDRM_ID = "VUDRM"; - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - VUDRM_ID, - KeySystemId.WIDEVINE, - new VudrmWidevineContentProtectionIntegrationFactory() - ); - sources.put( - "Vualto VUDRM Widevine", - buildWidevineSourceDescription( - VUDRM_ID, - "", - "", - new HashMap() {{ - put("token", ""); - put("keyId", ""); - }} - ) - ); - - // Microsoft Azure Widevine content protect integration - String AZURE_ID = "AZURE"; - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - AZURE_ID, - KeySystemId.WIDEVINE, - new AzureWidevineContentProtectionIntegrationFactory() - ); - sources.put( - "Microsoft Azure Widevine", - buildWidevineSourceDescription( - AZURE_ID, - "", - "", - new HashMap() {{ - put("token", ""); - }} - ) - ); - - // BuyDRM KeyOS Widevine content protect integration - String KEYOS_ID = "buydrm-keyos"; - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - KEYOS_ID, - KeySystemId.WIDEVINE, - new KeyOsWidevineContentProtectionIntegrationFactory() - ); - sources.put( - "BuyDRM KeyOs Widevine", - buildWidevineSourceDescription( - KEYOS_ID, - "https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd", - "https://wv-keyos.licensekeyserver.com", - new HashMap() {{ - put("x-keyos-authorization", "PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg=="); - }} - ) - ); - - // Verimatrix Multi-DRM Core - sources.put( - "Verimatrix Multi-DRM Core", - buildDefaultWidevineSourceDescription( - "https://example.com/stream.mpd", - "https://multidrm.vsaas.verimatrixcloud.net/widevine", - new HashMap() {{ - put("authorization", "ey..."); - }} - ) - ); - - // Verimatrix MultiDRM Standard - sources.put( - "Verimatrix MultiDRM Standard", - buildDefaultWidevineSourceDescription( - "https://example.com/stream.mpd", - "https://vcas4-gc.emea.vmxdemos.net/widevine?deviceId=...", - new HashMap() {{}} - ) - ); - - // add other registrations & sources here ... - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt new file mode 100644 index 00000000..59a3f7b0 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt @@ -0,0 +1,142 @@ +package com.theoplayer.contentprotectionintegration + +import android.content.Context +import com.theoplayer.android.api.source.SourceDescription +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.android.api.THEOplayerGlobal +import com.theoplayer.android.api.contentprotection.KeySystemId +import com.theoplayer.android.api.source.TypedSource +import com.theoplayer.android.api.source.drm.KeySystemConfiguration +import com.theoplayer.contentprotectionintegration.integration.vudrm.VudrmWidevineContentProtectionIntegrationFactory +import com.theoplayer.contentprotectionintegration.integration.azuredrm.AzureWidevineContentProtectionIntegrationFactory +import com.theoplayer.contentprotectionintegration.integration.keyos.KeyOsWidevineContentProtectionIntegrationFactory +import com.theoplayer.contentprotectionintegration.integration.titanium.TitaniumWidevineContentProtectionIntegrationFactory +import java.util.HashMap + +@Suppress("SameParameterValue") +class SourceManager private constructor(context: Context) { + companion object { + private var instance: SourceManager? = null + fun getInstance(context: Context): SourceManager { + if (instance == null) { + instance = SourceManager(context) + } + return instance!! + } + } + + private val sources = HashMap() + + init { + initSources(context) + } + + fun getSource(name: String?): SourceDescription? { + return sources[name] + } + + val sourcesNames: Array + get() = sources.keys.toTypedArray() + + private fun buildWidevineSourceDescription( + integrationId: String, + manifestUrl: String, + licenseUrl: String, + integrationParams: HashMap + ): SourceDescription { + return SourceDescription.Builder( + TypedSource.Builder(manifestUrl) + .drm(DRMConfiguration.Builder() + .customIntegrationId(integrationId) + .integrationParameters(integrationParams) + .widevine(KeySystemConfiguration.Builder(licenseUrl).build()) + .build()) + .build() + ).build() + } + + private fun buildDefaultWidevineSourceDescription( + manifestUrl: String, + licenseUrl: String, + headers: HashMap + ): SourceDescription { + return SourceDescription.Builder( + TypedSource.Builder(manifestUrl) + .drm(DRMConfiguration.Builder() + .widevine(KeySystemConfiguration.Builder(licenseUrl) + .headers(headers) + .build()) + .build()) + .build() + ).build() + } + + private fun initSources(context: Context) { + // Vualto VUDRM Widevine content protect integration + val VUDRM_ID = "VUDRM" + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + VUDRM_ID, + KeySystemId.WIDEVINE, + VudrmWidevineContentProtectionIntegrationFactory() + ) + sources["Vualto VUDRM Widevine"] = buildWidevineSourceDescription( + VUDRM_ID, + "", + "", + hashMapOf( + "token" to "", + "keyId" to "" + ) + ) + + // Microsoft Azure Widevine content protect integration + val AZURE_ID = "AZURE" + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + AZURE_ID, + KeySystemId.WIDEVINE, + AzureWidevineContentProtectionIntegrationFactory() + ) + sources["Microsoft Azure Widevine"] = buildWidevineSourceDescription( + AZURE_ID, + "", + "", + hashMapOf( + "token" to "", + ) + ) + + // BuyDRM KeyOS Widevine content protect integration + val KEYOS_ID = "buydrm-keyos" + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + KEYOS_ID, + KeySystemId.WIDEVINE, + KeyOsWidevineContentProtectionIntegrationFactory() + ) + sources["BuyDRM KeyOs Widevine"] = buildWidevineSourceDescription( + KEYOS_ID, + "https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd", + "https://wv-keyos.licensekeyserver.com", + hashMapOf( + "x-keyos-authorization" to "PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg==", + ) + ) + + // Verimatrix Multi-DRM Core + sources["Verimatrix Multi-DRM Core"] = buildDefaultWidevineSourceDescription( + "", + "https://multidrm.vsaas.verimatrixcloud.net/widevine", + hashMapOf( + "authorization" to "", + ) + ) + + // Verimatrix MultiDRM Standard + sources["Verimatrix MultiDRM Standard"] = buildDefaultWidevineSourceDescription( + "", + "https://vcas4-gc.emea.vmxdemos.net/widevine?deviceId=", + hashMapOf() + ) + + // add other registrations & sources here ... + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.java deleted file mode 100644 index 6cb41b29..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.theoplayer.contentprotectionintegration; - -import org.json.JSONArray; -import org.json.JSONObject; - -public class TypeUtils { - /** - * Convert an array of bytes to a JSONArray object. - */ - public static JSONArray fromByteArrayToUint8JsonArray(final byte[] bytes) { - JSONArray jsonArray = new JSONArray(); - for (byte aByte : bytes) { - jsonArray.put(aByte & 0xff); - } - return jsonArray; - } - - /** - * Convert a JSON object to an array of bytes. - */ - public static byte[] fromJsonToByteArray(final JSONObject jsonObject) { - return jsonObject.toString().getBytes(); - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.kt new file mode 100644 index 00000000..2498a1be --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.kt @@ -0,0 +1,24 @@ +package com.theoplayer.contentprotectionintegration + +import org.json.JSONArray +import org.json.JSONObject + +object TypeUtils { + /** + * Convert an array of bytes to a JSONArray object. + */ + fun fromByteArrayToUint8JsonArray(bytes: ByteArray): JSONArray { + val jsonArray = JSONArray() + for (aByte in bytes) { + jsonArray.put((aByte.toInt() and 0xff).toByte()) + } + return jsonArray + } + + /** + * Convert a JSON object to an array of bytes. + */ + fun fromJsonToByteArray(jsonObject: JSONObject): ByteArray { + return jsonObject.toString().toByteArray() + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.java deleted file mode 100644 index 224d789c..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.azuredrm; - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; -import com.theoplayer.android.api.contentprotection.Request; -import com.theoplayer.android.api.source.drm.DRMConfiguration; - -public class AzureWidevineContentProtectionIntegration extends ContentProtectionIntegration { - - private final DRMConfiguration contentProtectionConfiguration; - - public AzureWidevineContentProtectionIntegration(DRMConfiguration configuration) { - this.contentProtectionConfiguration = configuration; - } - - public void onLicenseRequest(final Request request, LicenseRequestCallback callback) { - Object token = contentProtectionConfiguration.getIntegrationParameters().get("token"); - if (token == null) { - callback.error(new NullPointerException("The Azure drm token can not be null")); - return; - } - String licenseUrl = null; - if (contentProtectionConfiguration.getWidevine() != null) { - licenseUrl = contentProtectionConfiguration.getWidevine().getLicenseAcquisitionURL(); - } - if (licenseUrl == null) { - callback.error(new NullPointerException("The Azure licenseAcquisitionURL can not be null")); - return; - } - request.setUrl(licenseUrl); - request.getHeaders().put( - "Authorization", - "Bearer " + token.toString()); - callback.request(request); - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.kt new file mode 100644 index 00000000..b28f26c4 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.kt @@ -0,0 +1,29 @@ +package com.theoplayer.contentprotectionintegration.integration.azuredrm + +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback +import com.theoplayer.android.api.contentprotection.Request +import java.lang.NullPointerException + +class AzureWidevineContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : + ContentProtectionIntegration() { + override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { + val token = contentProtectionConfiguration.integrationParameters["token"] + if (token == null) { + callback.error(NullPointerException("The Azure drm token can not be null")) + return + } + var licenseUrl: String? = null + if (contentProtectionConfiguration.widevine != null) { + licenseUrl = contentProtectionConfiguration.widevine!!.licenseAcquisitionURL + } + if (licenseUrl == null) { + callback.error(NullPointerException("The Azure licenseAcquisitionURL can not be null")) + return + } + request.url = licenseUrl + request.headers["Authorization"] = "Bearer $token" + callback.request(request) + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.java deleted file mode 100644 index a270afbb..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.azuredrm; - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; -import com.theoplayer.android.api.source.drm.DRMConfiguration; - -public class AzureWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - @Override - public ContentProtectionIntegration build(DRMConfiguration configuration) { - return new AzureWidevineContentProtectionIntegration(configuration); - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.kt new file mode 100644 index 00000000..15d77760 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.kt @@ -0,0 +1,11 @@ +package com.theoplayer.contentprotectionintegration.integration.azuredrm + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration + +class AzureWidevineContentProtectionIntegrationFactory : ContentProtectionIntegrationFactory { + override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { + return AzureWidevineContentProtectionIntegration(configuration) + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java deleted file mode 100644 index 03c92c67..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.keyos; - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; -import com.theoplayer.android.api.contentprotection.Request; -import com.theoplayer.android.api.source.drm.DRMConfiguration; - -public class KeyOsWidevineContentProtectionIntegration extends ContentProtectionIntegration { - private final DRMConfiguration contentProtectionConfiguration; - - public KeyOsWidevineContentProtectionIntegration(DRMConfiguration configuration) { - this.contentProtectionConfiguration = configuration; - } - - @Override - public void onLicenseRequest(Request request, LicenseRequestCallback callback) { - - if (this.contentProtectionConfiguration.getWidevine() == null) { - throw new NullPointerException("The license acquisition URL can not be null"); - } - - request.setUrl(contentProtectionConfiguration.getWidevine().getLicenseAcquisitionURL()); - request.getHeaders().put( - "x-keyos-authorization", - contentProtectionConfiguration.getIntegrationParameters().get("x-keyos-authorization").toString() - ); - callback.request(request); - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.kt new file mode 100644 index 00000000..cd09387e --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.kt @@ -0,0 +1,20 @@ +package com.theoplayer.contentprotectionintegration.integration.keyos + +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback +import com.theoplayer.android.api.contentprotection.Request +import java.lang.NullPointerException + +class KeyOsWidevineContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : + ContentProtectionIntegration() { + override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { + if (contentProtectionConfiguration.widevine == null) { + throw NullPointerException("The license acquisition URL can not be null") + } + request.url = contentProtectionConfiguration.widevine!!.licenseAcquisitionURL + request.headers["x-keyos-authorization"] = + contentProtectionConfiguration.integrationParameters["x-keyos-authorization"].toString() + callback.request(request) + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.java deleted file mode 100644 index 0f7c049b..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.keyos; - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; -import com.theoplayer.android.api.source.drm.DRMConfiguration; -import com.theoplayer.contentprotectionintegration.integration.keyos.KeyOsWidevineContentProtectionIntegration; - -public class KeyOsWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - @Override - public ContentProtectionIntegration build(DRMConfiguration configuration) { - return new KeyOsWidevineContentProtectionIntegration(configuration); - } -} - - diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.kt new file mode 100644 index 00000000..6a12bfde --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.kt @@ -0,0 +1,11 @@ +package com.theoplayer.contentprotectionintegration.integration.keyos + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory +import com.theoplayer.android.api.source.drm.DRMConfiguration + +class KeyOsWidevineContentProtectionIntegrationFactory : ContentProtectionIntegrationFactory { + override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { + return KeyOsWidevineContentProtectionIntegration(configuration) + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java deleted file mode 100644 index b37cb690..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.vudrm; - -import com.theoplayer.android.api.contentprotection.CertificateRequestCallback; -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; -import com.theoplayer.android.api.contentprotection.Request; -import com.theoplayer.android.api.source.drm.DRMConfiguration; -import com.theoplayer.contentprotectionintegration.TypeUtils; - -import org.json.JSONException; -import org.json.JSONObject; - -public class VudrmWidevineContentProtectionIntegration extends ContentProtectionIntegration { - - static final String DEFAULT_LICENSE_URL = "https://widevine-proxy.drm.technology/proxy"; - - private final DRMConfiguration contentProtectionConfiguration; - - public VudrmWidevineContentProtectionIntegration(DRMConfiguration configuration) { - this.contentProtectionConfiguration = configuration; - } - - private Request wrapRequest(Request request) { - if (request.getBody() == null) { - throw new NullPointerException("The request body can not be null"); - } - final Object token = this.contentProtectionConfiguration.getIntegrationParameters().get("token"); - if (token == null) { - throw new NullPointerException("The Widevine vuDRM token can not be null"); - } - - String licenseUrl = DEFAULT_LICENSE_URL; - if (contentProtectionConfiguration.getWidevine() != null) { - licenseUrl = contentProtectionConfiguration.getWidevine().getLicenseAcquisitionURL(); - } - request.setUrl(licenseUrl); - request.getHeaders().put("Content-Type", "text/plain"); - - final Object kid = contentProtectionConfiguration.getIntegrationParameters().get("keyId"); - JSONObject jsonBody = new JSONObject(); - try { - jsonBody.put("token", token); - jsonBody.put("drm_info", TypeUtils.fromByteArrayToUint8JsonArray(request.getBody())); - jsonBody.put("kid", kid); - } catch (JSONException e) { - e.printStackTrace(); - } - request.setBody(TypeUtils.fromJsonToByteArray(jsonBody)); - return request; - } - - public void onCertificateRequest(Request request, final CertificateRequestCallback callback) { - try { - callback.request(wrapRequest(request)); - } catch (Throwable error) { - callback.error(error); - } - } - - public void onLicenseRequest(final Request request, LicenseRequestCallback callback) { - try { - callback.request(wrapRequest(request)); - } catch (Throwable error) { - callback.error(error); - } - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.kt new file mode 100644 index 00000000..e2a0af95 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.kt @@ -0,0 +1,61 @@ +package com.theoplayer.contentprotectionintegration.integration.vudrm + +import com.theoplayer.contentprotectionintegration.TypeUtils.fromByteArrayToUint8JsonArray +import com.theoplayer.contentprotectionintegration.TypeUtils.fromJsonToByteArray +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration +import org.json.JSONObject +import org.json.JSONException +import com.theoplayer.android.api.contentprotection.CertificateRequestCallback +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback +import com.theoplayer.android.api.contentprotection.Request +import java.lang.NullPointerException + +class VudrmWidevineContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : + ContentProtectionIntegration() { + + companion object { + const val DEFAULT_LICENSE_URL = "https://widevine-proxy.drm.technology/proxy" + } + + private fun wrapRequest(request: Request): Request { + if (request.body == null) { + throw NullPointerException("The request body can not be null") + } + val token = contentProtectionConfiguration.integrationParameters["token"] + ?: throw NullPointerException("The Widevine vuDRM token can not be null") + var licenseUrl = DEFAULT_LICENSE_URL + if (contentProtectionConfiguration.widevine != null) { + licenseUrl = contentProtectionConfiguration.widevine!!.licenseAcquisitionURL + } + request.url = licenseUrl + request.headers["Content-Type"] = "text/plain" + val kid = contentProtectionConfiguration.integrationParameters["keyId"] + val jsonBody = JSONObject() + try { + jsonBody.put("token", token) + jsonBody.put("drm_info", fromByteArrayToUint8JsonArray(request.body!!)) + jsonBody.put("kid", kid) + } catch (e: JSONException) { + e.printStackTrace() + } + request.body = fromJsonToByteArray(jsonBody) + return request + } + + override fun onCertificateRequest(request: Request, callback: CertificateRequestCallback) { + try { + callback.request(wrapRequest(request)) + } catch (error: Throwable) { + callback.error(error) + } + } + + override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { + try { + callback.request(wrapRequest(request)) + } catch (error: Throwable) { + callback.error(error) + } + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.java deleted file mode 100644 index d12475ec..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.vudrm; - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; -import com.theoplayer.android.api.source.drm.DRMConfiguration; - -public class VudrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - @Override - public ContentProtectionIntegration build(DRMConfiguration configuration) { - return new VudrmWidevineContentProtectionIntegration(configuration); - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.kt new file mode 100644 index 00000000..4baace10 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.kt @@ -0,0 +1,11 @@ +package com.theoplayer.contentprotectionintegration.integration.vudrm + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration + +class VudrmWidevineContentProtectionIntegrationFactory : ContentProtectionIntegrationFactory { + override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { + return VudrmWidevineContentProtectionIntegration(configuration) + } +} \ No newline at end of file diff --git a/android/app/src/main/res/drawable-hdpi/ic_theo_logo.png b/android/app/src/main/res/drawable-hdpi/ic_theo_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..23546968f7f930ae0d72e50f046fdb7591f3d867 GIT binary patch literal 4073 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 - - - - - - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/drawable-xhdpi/ic_theo_logo.png b/android/app/src/main/res/drawable-xhdpi/ic_theo_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7a0e45734db5e1e01a58b76b53a02781c0904e15 GIT binary patch literal 6067 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_theo_logo.png b/android/app/src/main/res/drawable-xxxhdpi/ic_theo_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1b1745bbadb9021f77b5158107a594ec2a3e33 GIT binary patch literal 10983 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9c..00000000 --- a/android/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 00000000..359e690c --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/splash_screen.xml b/android/app/src/main/res/drawable/splash_screen.xml new file mode 100644 index 00000000..06175b14 --- /dev/null +++ b/android/app/src/main/res/drawable/splash_screen.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml index 10437a11..b3c2e9d1 100644 --- a/android/app/src/main/res/layout/activity_main.xml +++ b/android/app/src/main/res/layout/activity_main.xml @@ -1,11 +1,21 @@ - + android:layout_height="match_parent"> + + + + + diff --git a/android/app/src/main/res/layout/activity_player.xml b/android/app/src/main/res/layout/activity_player.xml index 3634111d..c7b19b6e 100644 --- a/android/app/src/main/res/layout/activity_player.xml +++ b/android/app/src/main/res/layout/activity_player.xml @@ -13,4 +13,16 @@ android:layout_height="match_parent" app:layout_constraintTop_toTopOf="parent" /> + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/list_item.xml b/android/app/src/main/res/layout/list_item.xml new file mode 100644 index 00000000..28723653 --- /dev/null +++ b/android/app/src/main/res/layout/list_item.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index eca70cfe..5aa3d53c 100644 --- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - - - - - \ No newline at end of file + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index eca70cfe..5aa3d53c 100644 --- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - - - - \ No newline at end of file + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a571e60098c92c2baca8a5df62f2929cbff01b52..2ed0ffec66e189cfbaa60c0a6d5ebb59e293f590 100644 GIT binary patch literal 4068 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 P00000NkvXXu0mjfP=x?Y diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..8109e8d779f83f59b8fd53d2dd75363dcdb33f74 GIT binary patch literal 2101 zcmbW2`#;l-7r-mMJh>YSEthXIFVb8_Vwg&sOSC<%kGbY9_gq)=*rSY(Ya(Kihlu7< zt6^bC+LVoNU-xU}37Kh{Sgw8bFFfb+J4l>$t?PwpY& zo0X!X_3qy`iU?hCfhPKx3OdiW^Hsfsj=IyU3t-nIqPPd*=-OX^O27#4TixO7(U+kduzm#W0g(SMVy7>MN!zBah__>?*VW&vx zH-5@&A#EC>D|Y0LiHY3tUz>W(`6E$*rODj|l|$({o`XHWO)0a`FuyHfWdZ*gJ)$^6(T!Rpu$JEr%O>Nx?s^W-RGsNg~-AjEuu#eVr`Mq$xlaY zCUGlOrtG@O4pXuX&NH0=@V-%hvyfPJUOZYIp6C^I*(R5!9Wcnzf{5PfVxIU4+Kiwj z&)wsgHFw^h(--1O%=gK_r1H0>qZl=3OmA3MiFXjAqDUSw4ULwHzj8?doS2^h)N+bd zgKH{Q_pO}AD?x|`sQA}-iJbORWI%U1TN}A2O;1#XhPd=K$I^(Az16HbFzudOp>afb zgkgWNc?_nHpT)3yRIeNkcB*v{b_T_6Z;mBJfdU~;eLWpskLr_U02Ne+m4(mKFMhWH zyrNSKnp-E1aozGVa;r9}f%CtMF7-ubF??o+M|F7duMZF$MI29Fmn`Uo=DaSq+8wXp z6kHT^&*s5->%K-ng`iUj(40ZU{ERr5=3-P6{$PF10Vu8TS&!pZmw18K z4Bn!(KM`1-4}ZKaWhq{F_>nPu0D;XJ2ibhszwO}Wifig4%i#9p3w4aWdEfSi=-U=!xYi%D#Sa)2+vaPwhS;a0o6A-E7dEE#ZS*2&xU+VxI@j?5VO)l zay)n1mwNF1j&gbW0dspJA6*lSsT?w6Y)cf~AEnSH`!fvppj-e7Y|Q$?3?T4Y*%+2@ zaP~<(BrTu0$IJ*7+mSrjlE$8n$=+Q6Hx^McA*nDITIKUJAh$_oY%b+lt;9?yS;|v< zjEN%KFV8MDaa2wc?)&G?&IPvD%CtdWP10W`!G)RjWe#v|71KGM4*C+)^QWbvGI0R+ zzt87u7J04iB&3(Yz4xdaoq6XXW!Lv(9iI&7PklHqJu?LFg3f35Vitmu{R>C&D7Xeg zuC#Qa!Mf|d5tdzW^PNs;$Mc8|*RI_*t!~d1pOIbTG*feLzIqL*L?CxR*X_;=3MJ*m z(koT6sbcPvxF|3W8f@#;@ck+~U5(2w#tqn0*>=TAemmI9{+r|U1viIGQ>e6O2DQ!8 z|KK3xH8S&OW4m+7^=4%i2q zRE-9Fsyu%4ZvRqpUE|Qe@pnS4Hit!rb7m;qQR0)%GCb@s$?)cptTV zGVShvjfXBPZ5G4?oDB9a%cb51ymaqr;8K*l5=}pEsKcf`;lzxf_F>ecRi64jmKntZ zpPjssn;%thx#RRSbj*mi@XEs?wRi@0I{D8v!dnYka4P)k*kO=M74||aX6ywvj?f#d zjr>_j1j!?g7X?O{IRxTOa+^>|1Vec}d4$aS6a7;zaMDG-1w&O&-bvZO{ilU<<0YS> z8C5(xh(3{sc2(5e7`3xX1N+xGN+AzPCA5Z<;mdld&STteVNv3w=$HmFYIdt`==uqe4g|bh8xI zC%8Cw8y1h0^iFVUo7I^7{s<`XTFxlRJ3H~a-X^Oy(ea`b+VM4|-~1MMz)y8Yw%O)a z97sD?-aw1o9n7Xg*GT+=;dKdMgrX!{GHo(FrvHOOZP|^3WW3{ zB(khBhh6^cK~BB6DhF4(OxtL%l?^dRb$kA?$As85JZ8E4qcCc*+a5rwvx!^xHim{T z4H&VB;jpa`ZsL>aJGPIGKq(3|bObGxsy*WovSsqdcf&F>)cs$+(u1_Cq6Lj1fg)N) Rk}~;Dz*(>4GA literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index 61da551c5594a1f9d26193983d2cd69189014603..2ed0ffec66e189cfbaa60c0a6d5ebb59e293f590 100644 GIT binary patch literal 4068 zcmV$Vn4-!8B55w3$MuWR8uBxKAFJW0Ou+M`y}YmO8oQR^~Zr z=87UNgvnyzf`TEdpvWd5n~1{W&i{A0@9Ta0`#xo{dFTAkx83D`fA7EF`@W~1YQl># zW+TYf2=U*a`hU5^g6)Xx@oGUoO`qQ#U_uhGI9nsXI}&vw>Q3Y(sJr;i(V8)z6kzyW z*ZHm^Q2^00qTNI>L>WXyb#-<3h#m;S`y%mMjA*-5^zEoKrbW`&9DuP`ssX)sC7MBW zgs6ZP&OnkRSwwO_j6rl*jOnVQzV^*sVr&(khY;-`D$xN&suh=bD~YR4ha~Y^t)hLM z5-^M{<`|-*es;}HY83DNiB5rg1t_%&B-kU8jB2e8SeVn_5Km2QfNjP5o0ss>Mncx_a0=(R0@5~h%tnnnc0 zAjv!kyLSvcHY!L8aD0fez=&WR zuB@zlwLy)yj6O~J29#W3gjsVYnMZnIrKP1)8bp%h0ZDRRd6K|Uf&^(N{#jvR;rPc2 zk}Q&>$FMooPZ~J7AkjLiZ``=i|FNi>BF1rsu@g4uH*jk1F{$DzlL`+q>GoEl%@z=~ zFFMYo%4;STR!ie2QM+&}#^1uEg1t;CyTGJ}Wm+KJyLT`9>eZ|5m1}$?fN0z>J%jw9 zm`NE+nH2BKq?k@b9o126XC_@9&ZJxGY4KNx`BKw&AHU-!+}=d}Mp1uP^>cxK>BFS! zGnrJCrDeE_i;Kf)X*N~^B#Ym}hYuI(fm2h-q}18OfQx0!{@kk`7;#4}rkV;SuMQ;mq#+G_!N_B zAIf*qN_$enq|#U>T^(oH{E*zjA2e|ioJ~bVMb+iYmwPMMY!N`Th`k15ot*z##@xk$ z^`MIWSg&5a7^ZV`b7RYvEn{Rf8L6{nAl*wP@cq>DlJpmi1PdXm ztE#GENl8h8s#Q%kS`;&!)bm<0;ZCSw2x^$St==0c`bS4cvz9Gea)3ZKHa5)D(~~V; zyqKk?rdkG6!S_r$@1YW)Nd!=}UJ#j=mlvtZV9R1gs1A|?LW2^Nwon~I*Cy9{JDvXD ze*3Kk93=rLFE1~)apOi-R#v9oaHoW*G}Hj-zE%|g>x7zLx^!uzSz9EFSao&vHlxy` z8X$80C6NXf_2Gvf8U#otdwY8}XwV>b`t)f=yqE_GDjeIz8i1H6Ry7M`6=9mOXrp}!^v-jS6kLBj(nvo(3Sg(w=3Lx2|m6Vhe zlVo=@8a&F#m6w-K7t&+Ae4z#)81h=fwj?MhNEJXJTU%Q;aNs}|8ym}WDWk4GYqj}+ z)i6LDByviOT>dMx=S6XZJtT>QUlO=cgmlR83iaHAi!dPK&@J} zV$-HgLq@JYZb=kH>Rwh$5Y&vuEm*g1otqL9E$>D4CqS+%o7DN#d1g`yFQWz;G;-uf zs{oQ|)TmJ`Jw07}+_GQl^DgTE;xQ4tS!8771Yq&wk3ZV$*&i}gOUeO9pzks(MfATr&Y;cP8CA zY_$KFF=MO(r&Fg+j8p*S3jJ}5>4u#5v>G7U-Cw_ceXo`sQXDa{BTIhnu>cfHS$@t& zy$D*Si4!MU1dM}&0}BogX35FP#(B!yWj+=%0}!+)D=RCG=4_$CMK(qx_AN=o(nMp^ zI~1vN%)9xNSz2MelHPjjE!DvE@86&8*s+5rxJLOwIFY`@+BirCh#Mk`xib3n>C;AI zsO6yOn{U49OpOZ6dN5Fm3V?ojR#|`1qIvV?nFXhP`}XYp_uof^Yd(^GSk9yi10D$= zg(oYdu7ORkG2U26~PwJ&%G_1KkgYO-HkD|vB&|sb?a89v$JytEr0|_ttpa@Ruw3M zNo?P!Ep;kOu-B(k-V|S7!?9?~r?NiZ!X6hQbxXm4^q81a4ir;UQ-3BboVCtqi?F&C ziTxhcTgx@%4f6Le>FTTXk+VfA*RS5tV;kt1OQCB@tf9-3o~G#9&UnaQ8bH) zh*%?14ZUR5p4{&QYmVqX=>*Bag^hwun>I}b7P{pQ=$b9%NbZDUt~pOeF%yr5%@H;R z*Q{B?zWeSwqs8~);$lXD85o0$#da|J9ws-GdKE4WoxPhj*^T&@L?=7-H0SD(C($6Bur)J! z^k}}I6)RR~z6VhP%t1qW!xTW>x^-jy`t{>Gt^lZAyLQaO!$WHjeK{~7pd1W7i9;_A zQ>ILLmIAp#RRJRrREPTTyN3-y5hd6=ckURpEffHAX~NF! z?c2AFs#i`_kTMkLaYPfUgE1GJJgV4_-o-aA=`x*RFa1_3hi& zV0#c$1^u8}uw4Mz6ptYxAv`h0CZvw^@B|fxoXo=;Si3>{qr4U@Sb%4=x@2c(pHU-4 zY5;<S*_8~K_Tehe>`TF+TZ?~kEXRcklb{K}v)M4?avOx(634GCN zRBYC)S-kD?<;#`d*9hB#-PC8qn$=xos9=lQy!qyv!%>11QY1AefGA#LJ$v@#anXST z2aL9(?3_y}06KK&ke25nGg3~x1z@cdSXy>Ykvag;E(Z@DT!s1#fmGYv+&pU6uwNra zjDVZgJNJm#29Y=1eDB`9HEpmK?2_!X#*GX^k32OLKv*;uXNVRqT&U@flI`Tllew1!50DnwbAoVm z=IgJ&<~tAybw=PQR`m2 zb}gSbD=UlhSSwQY%*@ORx}lS>Cb70hzot%|>P#=)C~TijA-$vv(v$FefM2Rjwc0{D9AV1gTA&ezx*=(`JiWT zaPY+B$$cj+`bQ2Z2|?bE7>XZZl@g7(7kfmB?rN_U)_5Ta@CCH3d*gV88=~ zB&C}-Z~hPQhKG5(3SJxiUt??r3>e@<0UZuKdItmq1fDu|Dhx;C;8q1twGF9y@?Td7 zugZ_*MMOj#^Y{111H9hg4LmjlILgbOGIi*752EKNZ2x<7bo5zxI@l+1Y5q~-Q6vj} z#TWoZk|hRnVNRNR26zB3f~RKlXD3{mD0#%cv3L^shK7a)QvkV-g2jBf$R%GQuhaZz z3H>ICg=gw*5f))LQh#7(!YwW)I9E63!>*PnMJ+L9brD91&m&^~2deFQUHiew1APf#@YH zdg#!huZ$i&dK?Jv@g4m(5N*&_^g-Wl7z<-!?8bE64GtEmL<`()M6U WW?u)ERM1lZ0000Id|UZ0P}EI-1@)I=X~DGdw1?T_xsK{_uTvL8wG`@xdHSL zi(gOK!kzzrvteWHAo2y%6u%c~FYnJ<{N`T=3@w2g$1Fm|W?3HbvT3QGvT;S=yZYsV z;Ux5#j?uZ!)cIU&lDjT_%=}{Tn4nc%?;kSe8vq_&%eGAXoY=)gfJHN3HRxZ>B(Z_MschsoM6AUCjPu&A03`pU`P@H& z-Hldo)2LhkOv(g+79zsWLK6F$uY^-8!$ow=uuO2jh2SxRvH;PPs;xr%>aSRNI!<*k zq54?efxFGi!}O%x@0qhGX;;FAnHp6DCoZk~0VY&zmNZ7(K!PJ_APP1drc`bP>0_;h z&Qm$bcWJm(}i`WLgp2 zB!Saf;inDgfjrc$$+TEt@mPcR1IsBF%ve$XBbby0fpkyuOahYhptv_F4TPl^cFuY% z?j|wKCAHsATwcEiKD!!=-Rcj*rL{kREWvXSay1%O)$IkoG9;U>9D$AX2iq+}=c!zK zW#~F|y=6S-m(=bSuBh7sp;w||;ji02=~j1>n56y%KZ-d`CU}*Vr4Kbx#$l%nQktf zay7|dPxqqVP#g?4KFBTpC4g94a7d(I?Axdoz50FWHg^b+VQIjj*168V!-BZvwln~A zbKH-RtH}*WGN*#QmN8LoJ=px$01}Vc?i>8J3A9hHnIyNX`EfxD=_YXVIKs{VT3Ndn zW>tOBQlZBH$fP_7=2U+P&b2>w91zzwom{tMxdOJt%p6O<(sru*9vm-yM{=LrGg*A; zdzO^ZUi!GSIH4T8kpm@-mto`OgS_RuFCT{W^#^#*lhAo8$9JBR$l9jsaNtH3yDncj z9=-2VI~SII2{y5Q#*d6e5)(5m5qxJ>5ez6o)AC@Dmht5wuo5#@bKJK+ClNCgSImHK z-n$L4f1hQ)kyUO%%{MT;DuTBj5;{-iWSt||N^Q6Z*Y7p3>zTDvk2$AzYh73y(Ykaq z-S$a`7~Y)6@=WksXsXwxd#=vLpuN{KnDUhFcejffqj+47gj>yxu;Skx*L=&ijF8^lE3`V9ohnj~S&~kFu#to{@S-dohp8hv1H|3H&ftNS7f~Utf0s z-0Ba3@0BRndhI0axt07RCPdAk(OH`c?f>Mvkw)i#6?2gwcRS#Z7G zd>2F_5wA3$3sv9!1Cnl?gV3unFu8II%&++xD(_x{jN2uw{;mRg;AZ(A*EBq*^_OPS zqW3b$^)#DVy#pT1?REno`cCElZvG#G)QHy99*{=~0lSF3y@HHeTsgFs+5^r|WbX5XGTV4F1VJhg!y=hf7Reuqp}5 zpjo-u)jNf=s&|4cp{$jH>RjCOm6?Yz;^2*JxF>3UtZ*dKh{2k!N7v=kX)dSt9Dcop zb81lcyzm@k@zO&sTre7HI`lsiOGC;R*6af7$}J)ahO)%EGMpu4HrV~jI&WLG9e&21 zsJmTC9+#u*QYRowFVdIvCjDi%>vNHH^;Vcw_<5!BNaa2c12vZv4G*(@+qhJ4jaHo2}dFnxWlf-cFM)5Co`@Hf~jXV|1r?XR4QTQ0IB`3a47oVt z|6g6V5B_<=meX43`m1qB(K;T<3&^(kvxbr0HY3{r`e4_B5m;#>1JsFb9^)44eq||r zPuL7M8yn#EKX0t_p#Y8CWhr{I@fJ*t_J%S09bnu6C)j^6u}gryx)1{z z$5(=Sv@^^~4S~O!WMB72Qv<9l`<`YFI~IeALT?Y=U_MF;khm8cvUXB`qZ0oP2Wc83 z#osChA)h-mVaA)Z1=J9Z_Mv4EQKU`0Hs=d~uWLHHTj8F9fi!(vsQuh;Y9yGaXi_p3%9HylQ<{^u|E!Jpr zY4t0U3I+e|NG9!Y>09{qPVF-dsPK9j%*YIZDH(y_R=OYc-^rUv&#w9c?Be_n6N?s8 z9^Am}C9TAD-W?gNlC}N*&tK0ppev0xU{3z$pqt_X^K-X=L7_MAVAb%vKN#(G4ki|| z2CFZAwC7VR2B_UZ-$Otf>JRYdBF~DDeyfUhfnJI$1Eib25%kY`Kj__9fTqtCfnZSN z3+h2LXA+B+vx;J0>)HR4aYLq;ZoMM!gxQvBC!T3I5(z4a1ie%O6wUzYWD+DFsT?SP zO_=Fqx?LS;{=o=h(dLy0j@WC~g~8Fxg5;QT4XloWxSBkOtLCIeEb%q@kX~C136}~W z{!;!!sV!(Bsr5yWTz3}Y>+pMBAtcndmE_Askap!)NVt3&60XRQ-_JnO?`I+V+IdLC z&xu#1<7WJTkCaZW%6ugjd1<_`8UKkBlY z0Le3HPfsN^POO44|8)?{0Y@fde{uqwC=bv&v>e7pE@q z8(`eg?mj^_Z1R%;MZ&a)J+NoLmJOajThV#;*a*1Wppyfh8O(*koU0dg@3+iTmx-3%pq!1D#A~P}?85fI(%ICB387Z+3225a;)w{qpIRI>qdBW1z zFqn4S2W*aeflag*Oo{OpORNt}IpG6SPx^vWVi?R%2m#ypO<Q@c_!eeohr+BJl-$n%^@rJc zVJrtCu`dV*&tLa~{pqb>e+K0&?Y9Z-i?)H~Pa86@&HYs@Enk**Wmz8;Un@HUbREg- z1@g`)8lLw9tyAk@>Tz$-j&g3}R?-3alM`NG7VFx^t)v68d7=kcC;PQ=D@iaWF-&oT zIoY3qPO3`_w|WqasawzTfQ4rwKtIO=-3r|-&;7n`p(ki!T?3by%%?VMEYXl}}eR0u~8-*>a7egC@(77 z0ebnKpj+S})JAty@v{!0HV(4Wd!;iAU3(}SjHJgO!_=c!#v7LSv(=#;ee_JLNvT1y zx^k;{AC~8|mjp6EsR6ujDCRIgc?gIH4#gY;w46o7Xh8+u&ARAjs=MYV(Zd|>5l<)I zq!ydq8;WngK2|GjL#6ng2SIa3pUo2_YEbJuhcaZ!bJ|M+3DA@@K^wP{&U1`1Ji$Jn z0J+J8Lovr7-wPaycQhMdw>~yi0A+MG*48?Xw#eSAWmkVP<>noS@arM=%bUAyX2#;LLWhoZSwe7Dd3P#rU~6 zqIuD8I~kmb8|JQ~HVif#{YH1fk!(F*8$FmR9;Ul?nv-6Z`z>y~#uj9EWSuk(aOv(_ zC;72FM|Kh@4$2eKFze0?lxaBoWI4n7 zst!_O^F5Dg>)A*91N!HK_XgOEvq9IWqHJ6I-g`jDUdcqLQ*%Qw&++2TkjbScru)Lw ztRP-E6myJoykY(s9EfsBAmuqag`OgEwJ`@5SG{TRkuB*wP^|l7e+#rlT(7;8E-aa$zBqnCzNuow4YP46D)HB_>({al(7k>W(V`ap_pTmi-6FrbZPj2 z88Rh-TKHSlukBAMzM`m2y7tw3yq41@CcU9CjNT?5i1N{h&C`OkQeFP0?wq|hUnXc? zTqECW;WlOAY<92p@IexgCuZV676I|WAuBP?^S(d-?6zjTLNCzCaRc>Z&VQ?TTWv<& z=w;r4oUTv&Ut@YGXbkApYlt!}dK{r-q%vvrUWXX!HRzc*`{#wqP@y5u%w&sYz~Yxm zWac@OGI5lj6Cx81rX3=h&oL?Rg#|_1(N)*MhhNNzRZ<^HFYu1&rQEAO>G(9@NN+Fp z`CuUV_F$TGd)LWu(YS+4(mpNPE;7FuBzC=uKoNVag0Q4#2BgKdwz1Fjw1=bRbtuz;rX1c3LE7MhE zk>xL(o*OD8C}=S>MarOPAw;#K&R0K-m=)Q7nkG$G(2|v5z2ENr&a+@OeA^33Ix2lR zwf~Hn)lLp7ENta?tmUvR#BG(^XESLpd z4eagIqL$Z>+GQU%++~u_tHb-5aTYVIm$GtyB^4z~{+^5f5_*9Ky1hSQ7WFPIKcaxy z=iRrAK6D)Kq!YFv%y|FGsF^4IbEc;RmRV)`Uzwa6c*D9N_!fy(j^M_GIFBpi53en= z*uO5v;_H=B8h$gwROT5uQ5~GMP@RLxYL!Q_LG|Pfr5(4%amYp?ni6?hSP#J z>irZI7001yQKOYK-kbQA?r=*I`b@|0oFR%gg(T*#=PML02-9BD1Y|!YeRdfE%hDqt}Yz> zJrp}L?;KIwP`m}9dq*>E?MT-<1&)7DMfn=#oWWrDnK4#|(unu%By>;D=pD5Y+D`q& ziIC}s&2lJ$x{K0{0tnJ(5&GOE9Vj2EjWL?QHKKnD_nQ$!$uQ6cymsvpsyO=T?SVC6|k(SW^|zB{vOzW z{|u}vkKy=iaBvXX+uI}M*sR8R^uN!=1*`9^VXSZ!u(V&Bmn?r^HD`eJHy~KO1sB10 z{f)rt&VK{To^DxZ{$kK;%ZLQIlD@XKcCN)dA@_S^ohdEYwq#%#?&b%|4gl74or9~X zsewn29?=4{?(Z!>0n7QFdA;e*z#6ZKK?6EEIi?LJ4|MC=FFL@1VkA(ZXB#ywF*j0 zOO@96U$j*M91vcZ7rLK3c@iikH!&=se}8==xR0_-ppd7gygJ5&KtMo%MFOHwyNryC zp}w`>*+PKa$UtsXR8$lug;dc3U0q$@%Tl>@0#(OM2uzzc%_?|W6U&w@Q%0zoZ*3wV zl;coYS$T=Fv%I{}^z`(ksuTELUHQvM69Thl&9VsI+1VL(@7@g!4Gqe^6?<$ZK!3mW z_4VnfZzz;v@^S3z>nj@(f&4{SxAZ6mSg>G$S>Ip1dNt(d=c|NL48sM>Y$iZ%-rU?= ze)#a=k0k=A*aH(qgF1m&b>&pIP?napC6IF94h{~S)QuZAD2A)&f{rv}Z8QP`ot>SH zm|wgk0y#N3Q!s(GjfglTefUbEYve+&OmExtNBb!eM|pp)HMPExL(_@ zU%&1r5lBf%@i9w)s!K~nSM5281ZCY7D^>t1hu+>^%Vh-h;Yson^SY~I%o4bC=~AFX z;Le>pzriHds7j#yXRKEynIDA8=-ODm9?-N@`dTmK29aES9J-FLg<{SXSby^msszv- zn@*iNHANz@bLY;FamLgau?}6Jc%x-2WOx`8TVI`Z@O?Gdb{F=UWLalnFqYnRssu0_ zmxqRiek!l$9B}5Is1hI<=rGp%#ec%Izg}I6HW-V$<{ypiO?0#x%kI*x#%0$c`$_qI=jDM|hY6Pf^C4c79(+R!WHc9$>+qv+qB85~gS{Tr20mCvc z7tl3@zFktkzMeMF4-EAg)OF+YR?v2}z(Bv&;(nQQK7aoFKZx0$V;4#ZO+i7yR`GN| zUQRrC@BlV$+-M?UVPSCa;6cE6Op8h}(BsFCrG$0hzyXuKk&%%+tbYn%AUZl4&?R8q zx^=uHzkmNe&{lHzsRdm$A@}ax`@4{dhf0admoEq5YEz^O@bdD4#fum7$vA%e zIILg49y~le;PmO!+<$uV*{5O-UA+s({)3Q!?d0XOBUYrzCgrqD=FFJ`+qP|!{@$}^ zk4*$3A|gz5QGTF(!qTNn`BqeXj(ZYr1wTJOc=6(eNjY6oQj&sLCn&Z8;yOUn|4k@! z4Qhv1Y6NI@pFMj9uU@^9Bqkej7W~B>Bs5W}VoPa-fRmFG1O){F_Laoj+Z%j+eI){} zuC9vr;o;%j&*}NYhYw8%kb4n<*w|RbmJ*{+8SXi}R5$hlqjBh$QM7>gPI{OX)CdrG zOoaS2LKMs^5PujLC=pn@cCF$)Su8CrjjyTOw{M#esH>|3M@L7|I`Y}yOBhwphh&W0 zP(hB`S{ThWP+eWk^=;m~Sy6V-(tiP@?>}R>{)&oK%vvc#RX=}m;t+X?V^QFVbg#cEh@*45+`SQ+1c4Y2$mo~`nP?&PGitmG-i5w`j3cVGGQ_6_f|e|IG{{P zO-)UpnWu{u6-BkT@Lhm^;Gi+cA{Y&6=0770Jb&Z9&Lwmt5?i4i5e!3Ek5(dMC7T5&GEw;{WWS zW)X@MSi8S3tP{~X^#2dz1^GyLW-s`+J@pw4KmR`uMCB^L^j$9XIaP=Oz9`;(x&SS>>u9y+{y;Q4?1| z^+Uo-lgUx>5e@WdRZozbvM0%m8E+E&jRkKC_X0v6qoZ;DkLX5cPgn9y9K?woG4pg) ze7W~$bKAG=@-t=M@-yXF2!W6TfISz6Vv{PbB}zJ_c_+R`3K4e6Xj zpT_wZ)Lf*gh`$#j%DkPE=`-wfVWt8u(3oSVBboGK9e>%8{qQ--5BcMLGY(#cbj)r} zyW_HN<*&tD?LO4;be(o){qKGB**$y!Y%(u>Ita53S%@$dLy!e5WLcH#GwpPtrb0fu zVjan(7wgE5?1#@ue#jr)^BgFEmh|4~dzSx6%=NJWy#47rll=_p?w2uuw+sI|#i0QF z^|?KBjDPu{$4CBTy-Bm3cVk{|L%_rxKxgMW=}E$*G+NC5N%Ue+FPdKJK{0KSI+ zq^yaogge_O~^OwkSt)or543qrFOb^JO7R4*Wb6(kxY6)j$+t- zrwpH1svnt?{E$C>9ODpmeJ2*R?r^+`ef2p#lrfnhgOeLFL7*j%&-RckV14I*Q1i7O z^MBbADd^^zia^V-cpS;37i3z2>if)C$H)$!ll+iBx+e~^jG6Fl$$Wk#w7aVe@88j| zlE{FJ>6WmyowB&;#(xoab3ZoR*oW1fAMtwno`~(URPuH&MGu6q+CG1;75TSL;dE~k zI=<~fPk$f29q0$gakxM50Nwpx^ZH{wT7MMYK88wOzv9U{3K~y# zWIv_>&`zu{6!cJyhMBi>>*@_%zjXi-NeO?cp-{}ZU%}k)PjBxfR1hTWrj;^z|GI?5%J~Wy)KWHmOR`Y)J_20MYZ`{8Ne|^sL4}g}zy==)8lj^kIM!?Y+ ztT>m;2lHJ4^!0y(6;*`@E>q%W-+x`Z?{-};fmdtVvo`T}_W*5J=KHtpOM+#!z4uGp z>a#dhLSOx_8y)vMp}hvV{)|CM+=&F?WH|fqAf&(vH0m$ zp^-{x`|Z-_LS8_={s`t&svx_V1ZivP*!RHBo26*HtsjB`x-K&sy9|T4Lw_(rch`*O zyCyW=HQLZ(F+*o*N0Y@gh;9>_yUn=La~(}RW*fE{jv=@z71F8%c+@4r^IGcI1|Vrs zV*0UFaQfu$JbXUe1m^?)z_ia+V%kA=J@hW*$2PEn_#fH=*MqCza){yZYPcL(joBxn;dO$MI&Z z?eBp|eK7(~Ct$&GB?6Ac!tZ!2{7=Ne|71KON>m6fQ6jK35rJot5OgjX;hHo=m8%h~ zQL?P75X^{&oKMH!Y6_vKPKTl<10feO5qeRL<=SFIG~^gKy%Q7ugf5PvAVXNs!eh_Bv%Q9Q)H~WLpv3OE%ibQ_Xvy zis5TsAWtTDC$|6)+J+R9e?WsZ6fD!DH(DWz#pGS z0DNCuNyCh@8*L5ieL5D>k}Y-(D=TAVrb!wkUq0Bd9u=_&sY$mZKl4I7LbPhg>QmrR zp9uF$Nt|b63gj1(p3f5ye$-1YtN83v+0bg^Rl3DSp2|k9iGyExl8ro-jb~*XLRrI# z$y3>cG^iohDu3b8z{;pGne%K`LVhvXu>hXspSgK$+t??(8iL9=Z5mBGR z8aA2LdFVQLCc6jY!#_hFn4!k29|4Y~3 zP4POq@t9nz>h^9*voiGhx1?Ja=nAbvvJH!LMONRYbUWSrmV9e)i+WJLq_RphaaP~5 zM1SiXjnXP9i?d3ZEUk#Q%FicQ=htLfy{ZzevTBB!B&)18**agFW%a33^~&p&R{4eG zZr1~=kN?8uEh?Y!j=rgUjp4Twye9ihT;Qsh80ySp($G~5$8=7Li9v&SBWQ{Z6X!Z9 zCe3wLyuq%7i9AI13!D`bq?3J#3vqJzT|6-joDwivB>hp4Z{tsy|VDA%M={f)a002ovPDHLkV1f~GE%yKb diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..258b1315158460139d9b5945ddb53ca2bdcf0828 GIT binary patch literal 1394 zcmaJ>`#aMM7+-3XtQzIAIuy>xUO~>}w~?iQ);lmZq_KY8tt2gcKRg zEghGc%T_MqG>I{JFdT#!atTNOK=1Rs@8@|x&*$@e-k)BIo2vsv7A6YoNv%tsj`w$$0VDJQyQHzW0*? z>Nl>C15+UM#TDW5<4sqq%@$@AC8A4ujBJJTRYt2Q*ga-5XPp$8Ql$I-_=?M2q+8dOxP%ARvyK0I%Hf{FQ@mhD5c%GU8MyfX!n;PuA4A148iR|EV>;#@!dRuOG7 ztUO3tLeGP^Y@UXzC3T0Ano9!o`wYMrgVh-)%T5V->z};$Mo+@G=pkJ3f!=N9I@^Pf zMx!n+TG9`MKRuKJhfUnR-Ewk9tIRTk$7PkmNVMy?uxQ6(OuM1)@C!BMc(ugh*$J1e z;eG^!44x4BCM8B?EgMq-wkmC{rqyJspNh}?2VgLXnF{j$*)4k5*xV?CjabtN!<85r za+dO>`FZUYz2v~mHzSUP>hsX11OQIHPLDhar2h@$tr!r|qq5FnigITVOmh_=dyT^~awx2w`Yo7zR#9m7ToSB9rSH){ea=kGv<*SvzHEhLncLo7Qo>qxqAC?=h zy9{GkQiTvh=N{JaIJ}nv(b@4y06sGpz~aU|60x3%?y(;HCRLT^9~RY=U)DQ0Yx$xR zvB80#kpj(dN=F&5@(WW?frI)}Ub>qVV5|Zk)Jc)E&=y7y4JF2=ojJ%$#xsf)SC^2frn^u}N^jGMw4Q9VV}Uy^rdxM2*) zY|mHfA-?K2lgbwfL^kb2i;)E4RRS(et81I{Ee$2ZCoZI)&8ThT<8O8G*L76MKGo6! z!TJqo(%J8o>Eh&qu;MG4+T9_HV*rOa^p*PbwC*2ythext<&KMc-!~HO79l%^lerYTUDM&L9DBHyvom6#YIZfh@+Nc5LRts*2G|rcE5y z5-h^Dx)Jxh3$4LrfLl8V18&pp>nxig*+oSAP`u1fMy@0{ttnclF=)zR-D+KXF;e1& z0lYjvm}~=mT-4A7=+dzIAdU=-k{6$eM`VXRlp`#~*|P<6L#Uwy=+c()ze;km@Ba^sXPL(U literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index db5080a752731b34d38d7c634732b2cd999125d0..44a12f8cb928201dc59de187af8624a497e68bd6 100644 GIT binary patch delta 2645 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 DyJ!d# delta 3386 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 literal 4926 zcmZXY2T&70vw#yMn9vcVN)dzvqy&+o^xl+?0YMU^i3A9ubR_g5AVnZb6;MH{w1Bh# z(z`V2z4uNi^6mR-|nJ ziD!nlM5WpyKdG{c3k2M;jXYyyVo*^yGIoo3`~=S|F7P^2q1SWS$X&WX;`m|lvakY#7qwtaxT_5#?fq+k)xD_wHQ zyOv!iWuFs&s&k8$>66s&pN$6(OHEJH8Iv+e1ce=IQ2k}QWOKrE(R&G&rrwRul5JO? z9Uk8YLMp2>9IqF#Te_G{OqvQMdu+CapwA4T<&Q@QcIv*Lg9wCU@r|C(t0{!0uNy}p2{-c$-u10k!W;Vg~%I&@z+#7Zi7r~hD8!> zpn1}&ANh%cY`4tCA32CA8i#xOs?h4F_7zdAHMab<*W)CuwR|(~gd5`m3bQqKX^YNG z+~{>s$Jk%6cClss$H84jVN#H-lJD2DGwI}SA zu}tz|ZwBc|Pw=EGw^kh`Vk_xMX|KfNCGdbgab3{y-S*BeH0I5?Fmdh355OcbEk&^| zvJH}xPR|SFnmgsUkXAZ4wj<1U04=0TZjaXuYB~;x?~Ljrb98Ioa7$W@Q2QHJmAU3m zqlJ2~r0VR++WqVw;&dIr@dIHqjUh+ASQh@B(NS@~cD1|dsV_-;UPjE8^RNw3E?oOx zSawJ0BrAl>2pdY6WexcT5X1q?^`Am81jG3nOs~fmQ$LhX9bynlAH4$-4lBA9QiYq@ z87)AMgAz(4!fMjm9M<0w0a6v{tIV^NELObpXP3`b)U*@x89Tb^oO+db`gC@e(i|b` ze67ZZ)BB~r(*Qpqoo`Z}T1l_aj#u&OY)!Dzm}f9df7x`HDRr$b;S`>(2aRx?w^7$t zp_L2SLwiLhm-FJ$ZHb+HJ7c0JKl0+sH@!SL|IheR2Of?`TP?pRa8i{~W;*EZeiU;! z5qg1lRW#x}?|K&Fq6|x^H3Q09CRZ14A}?5rOE%fsHgbZ;pRpI;nrtX##M(YnKkkk3 z+~&?#V1fxYR?-#{_;rMDS7${>_1W~iW^pf+R{8V$q~hG zUj~ld*aJ{`0%9kHw*9lEZDL0H32F{V&21_p^|9KQOZ%(tH&iu#-3N2M1Oqu=%QMi) z3a!@quYHxs5mE$*16Q&)2UBmDU*nJw+cVC%T6}3p3y>DMkb|)L)lti?c%_LG1@z1Y z`O0Nc)Qe2`t(A=Nx@S-67lfIMT>Z~C1iCb;(6G!=-@6n{h*4Lbzb@xt6wbJ=GtlqPq%4|UJ~huHD1cmeY)$p=}87X%EjT<#QNXdk!a+04QLozV|jq@$tbmh zpao9vHJHhQpjvywl(1?PE{BS zfR{NBD8e6C^$``kE!T9P9nZe@25vZLg&y^Ao*qb^nTes4#=LOmYXkDsiTF=zn}0jrbE{YJ2QDvE0x2)7y(Ha}6$KtxlNp z;n(;S{ex!!X?=Ij-kdhogzEktXGnH|JzUO_edSyAXRv4nLYTwEfl#KVS+7%bqIYCP z&ur^~ZSZtANr8eUyQne{v(gw++&~%2)9p(*3iM+2oFo6$4_%fmG}($R8Zaq{=*v4` zV!nyJ@5vIXQ1m?j1P)8`sLf>nrc_UlatmZ=)H+st(SRps zxN#&CRCYp(79mnAy*pBRv1>hmJjf?BH^u0slOl&xgTlsm$Om)hVJd^1pw4p?10fzlXzO(| zbC^>xs!xnAKfHePWTo%hPXFv8`7IYqX4gT` zQp(=7i+KlBm-}5**KPuCw9u!rR)J;9#3s|m!}eO2EEDB?Pkw-lW*+C<{DR2Le5qD; zzW@8)0)O3mN~otlX@tuhMxW;eIGuX+$rh3RWDgY7H8H4MMK0V0;bN9|!@w63^l3&5 z&0)q+q@6rD=7qQk$KedGU)PVDaA-g0fo}fn9X~WTc}y8_Lj%CE2dVh@8NOLV10^oF zQI_gsGrQl%rRNcT`SgZzAFOvvC4dF?AeqWY?4l@*#U3O*MGdG^xOm5JV%3;SOATnC z?9tAd{*w^|RtEk`S%@DO?b=lWR>)||^HL+is%@`JzWz^pKeH;4-@qzLS8dlpcx49nHQ47}Z2YEuTDZEA(kW3fYY_p}B6cIFk zMbt8vgs1oug8 zCnR@us&d9lEL~oxDKzSww@MWCZXwy07+^2K-AXe{GvG?+83e%j7Yl=f%Wb4B)huao zbP=@84F{aNVYG1Qhajw~Y1qVPFM1Qkkb`Yy&!y;yTE(C{18v*gn>iwt74810m`a_j zaeX94mEQ@K&M}<#Z@w(hKC*E2WHWD)aW;8Ua;S+nTxrjgc~uYuVX9eNx@n2>nQ}l) z;B1~Sl1qH^^=wCgv3{;zvR7E`t1eGiP7&c2d+p1;-4J!)xm3Fy$-)_obcQRPY%u7? z7XZstD$nFs>PYE%Mk7Z{QrB2riY@bl%aA*O>%{wOH%T-++P~>LC$UivlwLe&{{}*+ zkbH2ug77!!3m_rRpBFHht_jt>Us4q($OqsvHD3?|8t7vwAtJ;_*cvb{S`NuWeEIon zjsj(8M}cyEYQ>V-6XE1Hk4Wp-sts3$%7Mpv9*9VOz!5|H}i>_1X} zG`$FAG#B1$-wY#f-mxdT>FlkZLKBH?LVAFB!E}EpL75H{6wBvM^fdB%R?-j~0d|zFTA*n!Sbq@R7I$sS)Sf>=TgS> z7DkZ`m`^wC_Q@rUNntv|0Ijbf9@edvA$M)+#jMo`0r?s#41#UZ0l`5jQ8RIPkWYkL zLuSnjlMf=nsvrXsbLOTQ^D;=vJ4mu6B%p$6II+3u_iquF#Dv=&_{Ne5M{*;lK;68G zCcB|s+9?b}BBHf%?-TpXD^VR_P2J5myX1qdO&uW~Rc4(W7+B=mt#w&%j7)yuSIH`t zvogKN-ARwD5bj&d;OK|`hx40`q@@8|QhsDpp0fOFB|4a zU1aM=Yf<2ymK zU)xMo{8RuIn0NEhLK+-->qo3hthYqL6fpI~8=Tz!8VDrj z@vG(yaO``ZSJL~M*f_nb>_GJJSMJoZ*88oEkhy(K3iaPYXuH$dX>EnPP{xi--@Dwg z8bG_SeeY6%=g@5Mxo0Doc1WM#-}0nC;rzZU_NEIRnJ6u}J@fBxdZ$f@l{?MD&mg$S z$EPCM$0zZwcWT`FU8Ej^5NG;)p+aG`xn!?$Ve)&}j!{ORq1@*_ZMk}L0Xz(ns0%wv z9I$7!d>;Njr6K{E7`|9mr3TLh#}wtivvU+hRX$+hNoyYhzm|q6NXEYB#;z=!b~YVO zWr0qjXwDrkt-=^PD4HVWGMq`hmTMQky0!3gBy|fkG9WF~kSkw-QzO(sS=AbRuW`op ziGH!+lMV1j#rCixt9)sG6m~TjhW8@qc&IPD{BVWND zE}dlIZ@O6{V18XdiKR=l<6aTB2BC&kpPu^4(Q%5cZf_ImMCN6)=Q;MHw2-oy@2Dq? zBq7jYByn6Ri}-6uueQEcae}Jfz;iW9-@@@%gT6?;;VkD{|RNoav#$0VNE zk286ieB7O8wkeB~4|tO=-Xbmsf3}F4F>ZOgHfk8otsKVsWsAHTSaa8kixa6o-Ri^V z0)MR_rp^PW%$7L2Smf5N&hU;cW4ZGprO>fj*|YxR`_GR&s^#MgsOp7EmAx&@#MrCd zyIaPnnh;UNM5d{7{h@D7*U-~T?d!MX93o|1b~=jXSLmU?qT;fW${(B>2Xkjm*GkNF z&(^d3J)=9>N78NIp1Mp3lsdWVqBKFPu2q<(dE3}t|E*)2wDb9~gCECHE8@~_#Vp&a zzNrs!hW)H{u=fDT_Q!n=TZu}6ReD;sxxz$>nGv(gZ_n&`J4=7#1kVN9bO-Tr$$uWjSQz{di>icvjd{t_-r^BxHJ%Y2_8 z_P$O>b7^K>J$KO}^iafN7KuC&F_R@Dcit-KSrSXumdHOdqh_k=eg4{z@-HstSWq!* zG4$tUZt;9P--9WKB>=;5MSZ+#WgTvo@e7wnA!;2~n#w-93-}TBT*2Fz_3FjkXcf9g zVB^~a4mW{RZ{9GhgkluI30+>=fNW+gV-;0ykvW9CE+FXIidk7*b{E&%rtM)qso8 zG}5y^fB%bY+Zgc83V!2gtX~Yx8RJulF4mrVDhoT7C{3u<`*lrqHD{+O37`5NA4aN9 zZ=?8re6~HHP=PB@k}#{KKZ*gNLspiI2ih?VxSKjc=)i8C0{cqY50Lf&$+OCP&U<0b zR1S%B)k^(n0ngh{DRN2wcISM)dG}^jjHn;`AXoQX zE6g`Do~Fc%*9I%d_MT~@hJk+&gEI{=^5Njs3{CQ zFdya@2`q2_z!R7A^@uE=t7-L-Stvxqlij6ziLH@mru=%3ro5Pq z20{9^a^$8A&Nt|7TvMot(SGJNmCdaB9BR}W-bL{<=`dWZ1j zM)43dT}d9}UXi+9xc7&tlBsYdiK6|9GBzz;Jwj~78>0?>k#W?3)EjcT^{sB(5$qpi zj#A($(`Um>KC6aU90ox^MmTY5hI50fvHBs8f&)aCQ}i>x(ABm& z#CVxvx&CIrVck9*l=&C5iS}>gXLo$>%_{IGQm0}?(u@xX5~462-yZ-?LeRxZ)WA4? z;fBzZ-$I$)OEQ(}BAHRxyD$h5MX z11D`Gzjv;c{28}BJ(bjm?TBHRDF< zBwVoG&nuI^@t17N5y}=-!sxYr*o`~W-!{47FX-Zeu>G{i{&YxAf@#+nmd za!C|wZ!rssxod#7ukCQ{EkvL7ep3{fI0Wl@8a{OS8r`FZ=C6dyXM7+E3(>nm)+2kr zR{t~6^+#D?m?oW8y6F83YUx_>G-RA*7}~eWYp3qILg>_7RzfpbAUDBNCqIosv zo5F|WNG)l&d&O=o9~S}FjonxxaSey&*$j6KicaH3`FS zkl){!Q;lLGno94$MCp9EV;1bDIDCh%O1;s${r6B0-I}R}lP%_Vi<`BCzSB@86z;3R zi?RV;QYLX`VIb(S+vtTi-PRdjM4voQJA|}ERa0t=Nq-v7qo`^%a9zs&f1vtvB=gp^8* zcLtyDsJFEjuDB?h*-A6?PI?)HOKSo$o(z>`KY*c5TAQ0Db=tJcR?66RnWE~)vmU7{ zGM0H)jAI-L%bqu3dN3A0>9_jl_s0-l4R_}`&du{Ma$)5 z&q79Cu%|@Rzj0?NGu|oO8rca%C?u_p0zERHATplvRlPU?_2s)SwdA(8l3oAjgxZA#I;Z>Ucp~OrY~x_oKf|U7J!vULH$Y? zF7}U}_>~Y14RUA*&?k~^wb2>=(FIEh*4gE7qBpSoIf5|o_KxDfer>YzWOO_^x!l^R zcX>IQu(WmKNfQVY(HgGT?zvyM)-thpr7rPki=EZ?NW!`Pg%FKM%L~I7?vAjZ7b%o=}dOct=_kvd4(2WG~{ zVcrpw$3rEP6NT_^kf8+1Hja>KjUrzelXyaqb?E))1I8AUK^v)YL1HA9mz!mpshg%r t%1*6+bWZ#qt26=dU;G?yP;Kp5-$ZE4yLFFzI_EdDqrJ0T=`mvLe*yC*SLFZz literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index da31a871c8dc461a1ea114510bfac640307b0a90..394e36fe105234bf7fbb30c4dfd727800565dba7 100644 GIT binary patch literal 5761 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 literal 7472 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 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..1bcda3160e954e96ebe47cf43fec45d760a715d8 GIT binary patch literal 4312 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index b216f2d313cc673d8b8c4da591c174ebed52795c..a931dd8609e61cd048ae23d2d260bb5053c659e6 100644 GIT binary patch literal 8884 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 P1CYG5id6Lnli>dWd%MS% literal 10652 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�Lt8gc4AtWg7q>t&UtIH5pq3M(h=w z&0i@=7mIm@UJt{ct z2|z>)AsuLq9gyF2xsqNL58YdvAjpg*o`W=%)`h1F+z)=O4;=d|s?4e&b+ivdMJU_-)Z7?!*4K{hB)WLNmK;X;N;4c=&%8aVF&%Kp+k)c`1ocp1)5Gkqq!O zpU@#vYHB@b(wNR0O)QEN&-3%+T21O2D5>@5Po<5|C8c!}GjXVRqt{Y$v zTvc%DAJso!OuNV5{PuGG2K++x++R;`b2Z(&^9i8r%}#gC*?)iTzV5o=w`Xbe|Gp*- zf+;=YJrk2nw~JKoH@3J%#<6(W3%-%&-R$KpY#Kd_u44zM?QpQC+J5~g{0eVU^+7$H zHn>nwUN}*OHZI|-^(EnxuJEle*2(9KmUZM|)5P9iJTvV^1JAJ(@`Uo*i9NIwiO+Es zyz;0cril%-OLFycF7hn2aJ_HFa3|JnCmz*x-Gbwy=Dbhi7%T7F>wO;at_+Oys$}*w zFD2N6W%u5E<%yF-6fZePKGTNF%@PGhbs{4ppQQL0;JZ&ro)BHIOvUr`a*vAe^Uo-8 zrD@k?tZVG;gBHXSZIwujS;_yx;V1e=44Bp7`P6&}7!$?GH6#_TuD8w_%xP1@I=84s z-E))WPN{p)^-7dYYpYAxQOA-)pu8fS{({GW#e?rpfkGog?t|Yp^s9e;OY&A__x$E{ zPg5vMm%XfDIBVgS_OHBqg2h;1f{FSVuL9jinptXPtNR-PN4$kHF_ej&U_a==#kxyL+^$DWAFRq+9vL{cmhujgwD zn$5nCGxg5?ez%nIT?W)63z09~E_yd=mXq%V*4)l-ey*|!?B9jt8y*?|xq;fmK{&l4 zh!e^V=Z`t&zb8kJLc9T~NAA^v`0v)%p(kddT+QkpC$(`$y!y?;-xm)qP4a9n$wzm# z5g#}lD|TT}J*?4}n{x)0Dn85Ewz3j+$dF>n5aAi_JKW$G zyue!L39=r)MAp)G;T9J539-c%MDo{KMVpj8F=>xt6P7NHUknnx+jR z8)4PsTb;dQQ1a=vkcwO;MJ}9I$q@_a%1-BDrXNpFO})c-e5HmBsJ6XKChVq6P1rQ^ z_I~_pm3HlP;Zwh(Me+EWg7liG4BXHO3n}LZL{LPbV^8+slDm>Bndp!a4vSh3seYLB zD7=lmi5cAR0DfgqzDO0twy?6Y$`*9p6O@6eQAhHxf1pUBZ&kWTWyAjS^LS?@DK3=> z+xcRn%dZ2?FQ5k!a7YL4va+x!q!9JJ&sUd#$rO0woZI3hGv^8lwO^{v7WjIgT7aF+ zu$e!3yi}u|Pq1Mgyn)Mz#Aevu7_i#xxS(JG&MwRjL+HG~-k-=3=}Gj^sNFHZW?4BL z#1v6HbE78;rW4bCpSNR4wErGuMEY2G-&*+D9}1%j*ZXj_pNb&9}YLxmL9yjyc)baOxcrofh+&{8{&IKbusViRJgGfTdfbJ(t)c(kg<_C zIK^#lcyHrK+8Y9v5gNF$vdG}wBN^%wG+C}e{7aNjjS>|~RnSUw}Z#-wa9Kr)Z|}HKl_m_bGOc-qrQ=6ZENaBUw~!mA$e?|~^SC?TxETs-EZ-d(>>@UG0S$vk!$C;Ayr zKRdXrEv*o7y{h&^za%>kPaXyaSplEhlOE|Pe9hezGY=Nm3zOohuhN_0NMDXn{@U_@ z-VQimR;j3MV*gPyJ$PBLy|U`WcH1jaN6^aEWkUEruj9s&3G-!QLHnwn!S46L2%K%X zW*u*r#69)Qz2Zr-drLW17O||2GQ!d1dgEh_zt{i8C197CR(=T?u`zCxyG9ts#YQI+ z;t5HBu4XGy#4&4E&*!HKOf+@-C3*CfGe$T1Qjk;XIFY$^6Z%X_SC~7|$_iFjYxb

mo`t>jolY&BQep-#n>9Me+WQlT|ftkyXa)n@c(a9-r+7M?p zgZcFP1*OG4A8qT8-tjTd**a?8LT6z?ZESVL0^_N~}^Ki_xrH|sL&Cnnb=>{5*} zK`g1@B@M@*eih;5^~m_RuWEgjnl1wZZKpwYV_WO|*?yvOU(zhPA*;Ka{zJ$CDaYnN@595J_n|8MdJXi|Xc~Q{UweW{aZMAc3CV-pD~g zLA?=JG*V(RsN> z&QAZ7*xN7U2Jz8WrKh<*ftnX-nCMv#>{xVnLLOm{GhDmH%0o#)_f@Tor&sQ1m@D~&gMfRe3aYhtp^+!^SrxmYRlTN*&$uE z*+I7i3DmPsY1jDmP`wf93mP~+1osNoNdkmruLGBun0R}4I9KxXtO7LF@3sER>q=0w zv0E;1=_WJquX*}crB849zrhQ?iwjRnK&=#tNE85_|o>B+n>D(};SPMUM z+AYKBz67vmlxmjS1SEiJ4z-UqE!;{H5#!a%)C$5lEJtx0k!Mz@x}++^**&NNBicy# zoe&W)$p6Uw-7C;H3S50XJUooM_*SMVn8WkH>o=Mi*J)Xm_;p+N>E^hE2;8bWU!~6v zOaaY?zQS0C=QQB)gi19C1R{k&WcZjfZrEhE@V8w$B&|x5URe0ar-Vk#1IwfkUA~60 z$HgsbZt8cwB!V&$6wY++-`^pW(r+_E1aeE(+=)UE%sP+VQ9RS7YD3o``H2^h(-Q+N zEo2Th%k1}tA7Wr@H}aF`@j^uj3b?h=Zb2a;Hg=K0BIEIM3l*p~-2a0tu+aEj_r~F& zd(lMPznbX9iCp}{6>kO0U4x_ce89ucf;Vk*Q<2~rgSPr=NZ_X`Jx$NIm%AB$S$!A- zJttO-FR(Bd@iuyT8MT&UDV)$^t4R(NzYo7g9t;aIt||z?+r5>JQdzz#7F234W&B`I zY_vTB<$CuDFt)kgor!uJ$Rlg({{DV~M`l+iCceb#cP@{rzL{Z|-DHgs#5oT}O~s}S zZ#0$t92>?N`~Kk}QrcY(zHGygTECXmf5Z_Hgi7t;d$L@YxdSVL9BpR?&xz1?yjZ1g zPF8-`%>WLwH@N1L`{AG6;c<>X`h$6&3r3DcI!^4hwKm|*|K9-6|z~k+yek{BXw`4$7b0td)<#0rJxy%JdI9jOCWd5eA zXo8JKCiH1Mx_q0&B4@gpPtFqNB1_!P?r6g6YR^q=4b^Ofo!y0ReftMSxpcrabs+4` zzDvEu2=7x*m@z_R7+^Say=;>{-XL9+hY@Y66fUq;TxJ2QjZ*|n={Xn# zi}3waFWDoxL;338cYUnDI~?hs&MWnn2`t1re;qDSc;9ruzQbcVrSkV07%(P+Q)9ZS-!2=OW3t4mz+2eE!%VQ0|?J1KBxFR7C?{5|(JVH&30E zL0Mdf;;<}&x@|5+TMAU3KWw7#SwjY*2%=&-vc@2Dc5N*&tJt7(3KEiz7TdXE0gEY9 z81W|`c7s-qG*KOW1RYwaiK8M_wWHRq;8K;owE&FxarZ?pikU2urd^P8Wm!t5S>qM> zOrRGD3CZ^S*OiK-iRb;r)_SZER20}zo@t`j#a2ihY_dG`&^8K9FO}s5nKJlYJ&IL2 z%{37W%PpCOJQt+80@=9r$E|P*?|R=rGudVH+mn^9>!uT+K0H-)z0BZ2#C1M~zCfRD zPr3X3L5&~1t|s`uxO{)?=$rICo`hi1NDL#g>(*O9IGz`@jelqyA-clc8?`!bDQglN zuO)%l?S&7Vk3J!WwtLGGQi~kWhWjBc=T^QN?AVed%%y=?us;RLO<(SgsSzC=V}f5F zrUFu=HP@Q#mx^uF-)i{5?)>;HL>*cFDyWqew~zuVcBc1DV9^Z}XLW$Q_pc#Qrbt!l zHtaE&q?zgxfqyqUqEJB3_a-t?cs&B8VNhpVNxr)EB;FFPH(rh z@oa`%U-c81{8cX)hIQA>F7W}!8ExnLL>wM_H>#hx`Nftm1c3-!mY0_ydhaV>$G(5a zj|N$aJsuQL&WeO9qJrZw`}XdA_nT3Fj*ByI795ibI`#rEa|0`Sj^_O(Qgk0;qXYus zG4FNxJ;f&M#eq_OU_!qQD386~|Bbsj{HAg!83-04i<(yhbcpMbZf?M<*Fp~kCMKo3 ze_t6Vn;;En7ent1W-c9c0f$a5;>pIuRE}3$*^jjcxiAC-vFl^rHMTV98Y;#=R%Y$@ zH-`U{n==g!&44oVqgyar?}PN!CiVxA?|a|-i`}=^yYABwl~kjVcHAP)JwlUT2NeWcFb&l??;;Oi-hO(<%T361_@M2P2#&V zoDdC^ZV&hrGHU4WCVPrPjP_6rW;KYo-1R)9gm16_wPz;QX-f2|a`|b4j-h9G6!Z;lnu*jMH zgQTLOGD#}t@9SaW1>nyv9*)UYZ|L0|g3&@KsDz=z=|jKEVb0>5+KKP_N6`l<&&?o& z{+$J&iuF52v}bMY^4!nqEWV!(HLo(tE#5{HFFv}#5WUZfGJ`=S;*#PC@_+s}lyYsl z?=}K!5be$i-o&82Y4W)e8U6V&SJctqsjF0vf>fq-NUd}Lo+9ksZ3n4*2pv7W5w&Y0 zY;AM{D=to8N?aJ=&M>%9ff{R!(ucR@;_su2#~Q{UooX{dB!ZZ!v7966pBw#+>u`g$ z_8Pt+U^rEzf!_PvN>PuW7o{2@k4#Rg%!Y!@m}AMSb4kuH@my8Vpz+FaW(Ay9Z z%KL--=D^)Ls_#F8WKk>V4BkKMHtjXsWMy?$;4hKBVr^D#fr4wW&oz8KC8YDqUm1sp zGI$nlrB!K=#n`V1&Vyy5pS=8FA!8}MQ7ATAjM5M{}cQ3U{GSH{lN5!bO|yWq2cA4t)VZ$Qy}-Wz|AQPAS= zESGtvlqa9m9J)L2`u(Xby-u~`f-mZQu_vibm*>Cj+#u61OKHeEZWAczq^L3@IhjW< zwfS8$R#f4BjCqSfg&fYK4g(kanE2KNN$~Ea@wLN8!q4LZ_cczlmMot7xFMzcli5-5 zZJIzmI-Z(rtIY*n%j)oz14PywL=)H?Q-|ENuZY7kG&IX)wBd=<-jUz*6;=u}&d5aq zhD9uV@F3ca#C*HKqCAx7a~9^JjMV9GzV}0N4$*GF5W!^{C0$_D{}V@MFkjEt$<*>j z0hVx8&|i-F@(d!8J^Sr$kNELei!4^fxmROR#jYi`)CK#cv&k>aq^&;I;h8hoG5}%8 z>TA?k$;s!>YhJ0@)h#ZV4bX6Ovi5&x9p|EOsDKi03s#5mZ2r7K9tr!VZRAyC>h6Av zv_>rN4F<_jIyU_ zJH&|CI!Q|gyXZ@UjwTInmF0G~<6BJkW0=1D{CszYo-@qAJGh@UytA{j{n`=iF?NSanW(JckT65)%i)D(*LI5V|v1$SUbv2-)>@{9BlIbMD)J{)rL`W^zJyI&9!#7iVL6&2|tSfh6hagSZVK9=@#L2G`6>f zDNz!*abPuemD6D5bx=!;N0#zg499C-t7klb>A?n)pk`MELZPpvo@YS?Wake0z1OF! z+71*2OKtGK=m55~I(2=ra)o8GIDM3QQJ$`mV>;)>g5JDUt&zPYeuF(OU_P zkH=I#qaY_|dwzX7Zx@6D@e!+jGx%1FW9%e=U3NTIIF>``7&{5(&>quk$-H*lMvd?; z_w8Bsq~4jmXA2ilV4?6NVlDgUU+SsFt-r!7KZyGs&y72Pfg~ZwvelYa{1g0sPF!Dz1 znngPtjbsr)#}RN}@FHK%F~Mi|U`Q*ngT3y%bctgFBJ{O7^YD}YeB+YNT#4AkEu_31 zzhq<(+LaV~CE$8s7b~SxZ^jGKpb*pIlXTGPStLI zzZKZG!Dym_9}gPw85vAUnS7^;CdsBvS=_hXRTR)Gumqr~PL;-t+bimO>A_h^K*>Zl zH8rib8tn~5(d5*?XVIbbNoGN`dU~~M5~tEQ9UWuu{zF3OIA5v;ih4`^k^=I$1Z!4k zNekdIoGl1@UG5;;BCsWa&LjgPaTrGJ-qZ?Y%B%|d#Gv~t>##j2wA2gj7;&$8x||O@ znduK2*~2I2O3&TzxJ!K-tS0R81~URLKMIglFVk6JL%;N7H392+y3=l{n$^mG;TJ&$ zq%Xa>Q#)7GF9bl6(u`*X1qE#Sk2%lACP^$mGAfJWQi*@RRXe{^PPTz}JDM-!6(o~& zv(2!_7UvDZVcIXGZY+~#_Q-N$*|#XDDbIKb;B)-_^}jle0h1}U2eR(VmClf$#UtT! zAcSy7@Cr(nECWEh0~5RDe0oT2yyEUnuji+CsaE#RI zswrQU#1r9?lcS4Kre$rB6A=+D-SB-=f)QY|phvVEO=kSc&Km_P3jUYu8pg?Imn>TQ zn#)g3Lz9a@Z>wTo>iCNL9bU6Isu3{_{|i9FY*Mzy<|zO8=lHarle4ABa; zzhHJYi#>fm6hl%H_K*}V_2;K_)FNyYl(x3a>ROhMQAVALhX*%S=HU8p4k1A@sb-%k zj}8p@l8j-93z&lX`bc0^v(51rVfPbH?QJB=fQQ{w%MIO%w%)Qk7wfVZQo&ib~cn&FZz0ZuFNFcHW65rr$gvt0m zum4Iwv_EV@PJ=i{gCbHyZss*Y{V_lbcGapLp&reh)^D#b*^93i`h#&4V(^5~5fP>4 zf1m9>1a@SZnvpU|ed`g|gEP~46xpB+{DKrnX5d{7nx37=-4{2nw*{M3Mfs1K;`4oNO`5$whBW) zYaJdQN3UvXYQ1f)`)8w*+ked3Xw$S@Lp}c61^GVz89wMsFM*J!yK{C**+)Z@xMwn+ z?#rdw2i8%dTl4WgSRNHQx#j-bkUe`MEUp6aSR^eQ2ajatkK#dD_^xo=(oPK%0P`VR ze5Jer9;8|NZOs_RK}pe-zJ(QG$C>;$=@1X4t{D?A4;r$(J6o$K_PW^Y$!O&9x*TCZS&I^{D5d?qH(oRL z@^lw~uhTH|YUCZf!AHxKL#Nf^w8ruHJ6`;nH{)FojZ6)G5@?VL~O@(Q{D zyv>%v@U^&}#h+5Ww1KYF`-pw)fU(Cr#wPl5t+8TgYU6Km4)0}j2~9MTe|>!wxEA_l zw@~h;vm@)VYV3r!X^o6h2#^7gVQO2_u)h zwFz)~%=2~wlH(O%W7L2Zd1P)@a=sc}nIoPWm#Qa+7Te8G@`*Rc5rl1Ma90YqDOjE7wclf`w>m*VVl%(F?OU=`BajD-wUrh~oWbl6`cQ=Xb=$s}Z z-lZA1!G*h@DbwpoQJlG!!1wyyX!`~mMwnv9>0qn(uPj4yJcU`r6UD`>nKJ-tt5MpB zDUK$g-wUwEhGA<6(scdW(2#7>(-UBxJ09ptO*_pYJR#z<8APb>r$8|~WlIxCjeSVX z8db|Ah^2T!b3C^rtATVwB<9R?(mk0QDUTd{FGFMzY}!#F4e?b0q};&!;afZZL$C)A z#y-HH7g3f?3CnvpG#71(jF7^bq$e5ea;oZ|$tk|vsSM|96*fo$5MA}$VcKjq03 z3wR~aSx@8M!9+5dGcymrZp20u%3)-j8#sHnIz_3W%nMU#)Y(40k3qy$sM@D@Jtg5e zee1ChpYz^_DfYCWlj=j9vmOE(F>MayTZaE9x1U8w1SdBGR>UD9YW`@sAfLb=8Lgzx z&f{w351T^HLk@KA+Q>1^XUg0roJ$oO`Gom(1c1o+YM_HD2sK2&yK41#f^H4Pp*S_f9O0+fvTm{=VA}AyPEs2{UhST5FH7*-$pAwNYcY_`Vtu z5l|UyL3Tpv(3mLi*;cr$tgL}3k8*8?fsBfZ`w|op5fMJTxQgHk6>+P-M$R(gX?_IK zT%6wCUZL7}hL)#_W!hhVzJpxw3Vw=-$D%3a7aJZ@X9~lOHOdFiBKZrf&&YL&v_GC@^^cC5(-a`zLO4p$BUpBrCc>kq2zPB zVm-4^Mbsx{7>3o-_;mUY!87V6esgov%GomvgJPYZo}PY!R-$a?*{c*)r_E&-PCXDd zFbL2!Jl#{?wQg=; zEmBNj5qzE3_}H`eS;BQaIH+4oKH^>gkDLz49Cr4nWH`Fv65!clY}Em497db8&*HoH z5P?J_Rb;bCPw=W zd_9{{J}uopNTNy9!yRh^VEh`3{gF7`gQR9`D_Jg?-SgkN-(fos5gK-90I^&It><~? zos8q3)_=IqFfOsm-B9SQDBl3Pe)EYEu3?(+IMrTas8Cy z3Qs&Mz^(4@XNweDR@0>R>`XAL;`IDa9Mgn7oRmsbvb{|w%QY(&ziWcSlfe@y4Hq;I%uYtYY~Fh%1l zDWaY))2biOT?oxXuz;+@PXOyCmh@p17#w?s4Z~48-iTitcCE>u{8l6{Helwbbhxcb zn5h$otV1>R@*mA43s2<>=69JFmeOhmU`FyGsb&j}Mxzi%-D-n2cYyC^C{{?&mm}AW zgs$Y%t2V)Q2@DD#!ZCA@uAO(ky=rGfg>x{Zk&I)ZxGq|`YR?om4?((Nu#+t<>qI_4 zWXr*KD0yFiwTai}`*8U(Eu~#;u=Nz9OkIlVpC$wn6OyNF{*TxWU;vbxb}w-C=}xyJ zFhqg+J>D{D#->L+WEN4)(n|3=J(g{Tl`k)4+ka6D_zWW+NKAW(&$UD0(KH2=Wf{SLLLzP`T?}P z;p z^UMTtwC7-CmK1{|X+mnCH6mjc`%gv{yyJg6mWg#H6MzU8HJzadlWN3USTPD{cy`?6 zIKUUyh>3^ zRv98fp$bJ6;5)Qld2Ze?!_kO9&3x8~TIa1^M+;(0ItGTTY1^QA5hi7eT3*-T9#(NV z9J;a9md{gz%)~qAJwZqhY1+A5<|~WO=iL|t?+pzEP|g9rp@}o zG2;HS4v}3_*b7?FnoTb+7(ec&exi1szS5%2x{t`pADVi+Ij$Mc;I-f7Xipp5pCL;V zR!(cf=^YdZjA<*oF_eQ@b!Lpi)ihV+?)`F;9^g!X<$ZVdGVZbA$8Qd}o3eK&E9OCc z<63ZKk)J5R%JSe&!l{tv@Xu1`ITU1M+0Qpi##2X&Rjb^5(9Z)W&yNl)_6>ErSmdi0 z#Yp}HHSo<=YHpDMl-S@g0eO2BNWC?M*WH@OMmkV+GJuL(luyThVvH}-iSy)6@L|~2 z>ldsMwEZr-ww@tLcAe4aViWV~ZCh$-xto zRTiZd1ieoeu)W%wSQT*k(~1PRNk=p@w^bbYgh@}8*-x#5H8fyG5W62o;CN(VTWGYDa z8Fg6IJGhpZKW#vsS?7|!N>2I$=$Q?pHWy2#^{qa@(h6BWWZawo4jmG1@c7(g_V8!0 z#u4E{`J#gptDI97{h$4OB~M_ItT^TbjXqaMSeU!a=o?@HJm+YIqk$Fx*XVN|3yB(z z!+g+N;Az0P19n@FQk*b-a(^<@ZT*YitKbRu015=Mywz|1dyL`-HY~r6U%&kQpk5)0g-s!^)s1fgUXil`xU!c<%7D!ybTTALj%>U{U-ZUgU z$dqdY8bs{s>n^O#&0)GjaDs%#M0}YH@q&vi0+q)nXi0MOo1_}njVrXOVmUH_LNEHA zrR1MRvC@MnV7vr~lduC0AwjxYfQT zOjaR1tBZ$lNmn9kroZSb)^mk$57lDXPFsQS(y@Lrg5!U%8+SFKGPX8aQaWk_y+E-s z#Jt|m`QhZ=iJ)f#;Ojr$o~?C=K{ozc--|t?`={b%uCdpxt}X|Y-3@Zr9-whGv0g-b zYTb@+VJjO)b?PrrH~JCb+!wLi(Hi27j>hK`b7R?Y3+pN%ehCd63Gu5L?{bpPcz6Z4 z&l6ZFAmELU528kUukQ;lijo^SWhG8<_nS*N$KI21^SIu+dStx^|Ju^Av6E#8NC6E+bM z9&?$5am9zp%k>s@#mK#}XT2!Dza^qN;r_Pr-mcC^%X$jRD}o@>a_FZtotfHT5l;hL zKFZzjlN#2d}mkNT{S4m9O&n6>0a~wWPO*8*a-cC z{$N58k82tGLo99=YVK39JuAoR1WfW=Y`zUZ5k|$ox8|)~0GHqLfH4gB{ P1CYG5id6Lnli>dWd%MS% literal 16570 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 diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml deleted file mode 100644 index 4faecfa8..00000000 --- a/android/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - #6200EE - #3700B3 - #03DAC5 - \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml deleted file mode 100644 index caac14e4..00000000 --- a/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - ContentProtectionIntegration - \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index fac92916..73a7408d 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,10 +1,23 @@ - - - + + - \ No newline at end of file + diff --git a/android/app/src/main/res/values/values.xml b/android/app/src/main/res/values/values.xml new file mode 100644 index 00000000..67165dfa --- /dev/null +++ b/android/app/src/main/res/values/values.xml @@ -0,0 +1,14 @@ + + ConnectorSamples + THEO DRM Connector Samples + + 15dp + + #6200EE + #3700B3 + #03DAC5 + #FFFFFF + + + + diff --git a/android/build.gradle b/android/build.gradle index 29ce391e..7c6f0533 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,10 +1,14 @@ buildscript { + ext { + kotlin_version = '1.7.10' + } repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:4.0.1" + classpath "com.android.tools.build:gradle:4.2.2" + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10' } } @@ -12,11 +16,8 @@ allprojects { repositories { google() mavenCentral() + mavenLocal() maven { url 'https://jitpack.io' } - jcenter() - flatDir { - dirs 'libs' - } } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 221b73f1..9db9e361 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip From 64a9ebc1f7e7ffe79086dceaefaf4393b625c5bf Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Mon, 14 Nov 2022 16:15:05 +0100 Subject: [PATCH 49/85] add DeviceInfo helper --- .../MainActivity.kt | 4 ++ .../device/DeviceInfo.kt | 42 +++++++++++++++++++ .../device/DeviceType.kt | 5 +++ 3 files changed, 51 insertions(+) create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceInfo.kt create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceType.kt diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt index ec4f545f..12604405 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt @@ -8,6 +8,7 @@ import android.widget.AdapterView.OnItemClickListener import android.widget.ArrayAdapter import androidx.appcompat.app.AppCompatActivity import com.theoplayer.contentprotectionintegration.databinding.ActivityMainBinding +import com.theoplayer.contentprotectionintegration.device.DeviceInfo const val EXTRA_SOURCE_NAME = "sourceName" @@ -18,6 +19,9 @@ class MainActivity : AppCompatActivity() { setTheme(R.style.TheoTheme_Base) super.onCreate(savedInstanceState) + // Provide context to DeviceTypeResolver + DeviceInfo.init(this) + // Inflating view and obtaining an instance of the binding class. viewBinding = ActivityMainBinding.inflate(layoutInflater) val view = viewBinding.root diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceInfo.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceInfo.kt new file mode 100644 index 00000000..212dc379 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceInfo.kt @@ -0,0 +1,42 @@ +package com.theoplayer.contentprotectionintegration.device + +import android.annotation.SuppressLint +import android.app.UiModeManager +import android.content.Context +import android.content.res.Configuration +import android.os.Build + +@SuppressLint("StaticFieldLeak") +object DeviceInfo { + fun init(context: Context) { + deviceType = determineDeviceType(context) + } + + lateinit var deviceType: DeviceType + + val deviceTypeAsString: String + get() = deviceType.value + + val model: String + get() = Build.MODEL + + val brand: String + get() = Build.BRAND + + val osVersion: Int + get() = Build.VERSION.SDK_INT + + val osVersionAsString: String + get() = osVersion.toString() + + private fun determineDeviceType(context: Context): DeviceType { + val uiManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager + if (uiManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) { + return DeviceType.TV + } + return if ((context.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) + DeviceType.TABLET + else + DeviceType.PHONE + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceType.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceType.kt new file mode 100644 index 00000000..600ec76c --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceType.kt @@ -0,0 +1,5 @@ +package com.theoplayer.contentprotectionintegration.device + +enum class DeviceType(val value: String) { + PHONE("phone"), TABLET("tablet"), TV("tv"); +} \ No newline at end of file From a5f96525b120012c69a4d2127170f82501bd1e71 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Mon, 14 Nov 2022 16:15:34 +0100 Subject: [PATCH 50/85] Add Titanium integration --- .../titanium/TitaniumBaseRegistration.kt | 69 ++++++++++ .../TitaniumDeviceAuthorizationData.kt | 125 ++++++++++++++++++ ...iumWidevineContentProtectionIntegration.kt | 23 ++++ ...neContentProtectionIntegrationFactory.java | 12 ++ 4 files changed, 229 insertions(+) create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumBaseRegistration.kt create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegration.kt create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegrationFactory.java diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumBaseRegistration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumBaseRegistration.kt new file mode 100644 index 00000000..f0b16fcd --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumBaseRegistration.kt @@ -0,0 +1,69 @@ +package com.theoplayer.contentprotectionintegration.integration.titanium + +import android.util.Base64 +import com.google.gson.Gson +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.contentprotectionintegration.BuildConfig +import com.theoplayer.contentprotectionintegration.device.DeviceInfo +import java.util.HashMap + +object TitaniumBaseRegistration { + + private const val HEADER_CONTENT_TYPE = "Content-Type" + private const val HEADER_AUTHORIZATION = "Authorization" + private const val HEADER_TITANIUM_DRM_CDATA = "X-TITANIUM-DRM-CDATA" + + private const val PROP_AUTH_TOKEN = "authToken" + private const val PROP_CUSTOMER_NAME = "customerName" + private const val PROP_ACCOUNT_NAME = "accountName" + private const val PROP_PORTAL_ID = "portalId" + private const val PROP_FRIENDLY_NAME = "friendlyName" + + fun createTitaniumHeaders(configuration: DRMConfiguration, cdmType: TitaniumCDMDescription): HashMap { + val headers = HashMap() + headers[HEADER_CONTENT_TYPE] = "application/octet-stream" + if (isTokenBasedTitaniumDRMConfiguration(configuration)) { + headers[HEADER_AUTHORIZATION] = createTitaniumAuthHeader(configuration) + } else { + headers[HEADER_TITANIUM_DRM_CDATA] = createTitaniumDeviceHeader(configuration, cdmType) + } + return headers + } + + private fun isTokenBasedTitaniumDRMConfiguration(configuration: DRMConfiguration): Boolean { + return configuration.integrationParameters.containsKey(PROP_AUTH_TOKEN) + } + + private fun createTitaniumAuthHeader(configuration: DRMConfiguration) : String { + return "Bearer ${configuration.integrationParameters[PROP_AUTH_TOKEN]}" + } + + private fun getTitaniumDeviceAuthorizationData(integrationParameters: Map, cdmType: TitaniumCDMDescription) : TitaniumDeviceAuthorizationData { + return TitaniumDeviceAuthorizationData( + TitaniumLatensRegistration( + CustomerName = integrationParameters[PROP_CUSTOMER_NAME] as String, + AccountName = integrationParameters[PROP_ACCOUNT_NAME] as String, + PortalId = integrationParameters[PROP_PORTAL_ID] as String, + FriendlyName = integrationParameters[PROP_FRIENDLY_NAME] as String, + AppVersion = BuildConfig.VERSION_NAME, + DeviceInfo = TitaniumDeviceInfo( + FormatVersion = "1", + DeviceType = DeviceInfo.deviceTypeAsString, + OSType = "Android", + OSVersion = DeviceInfo.osVersionAsString, + DRMProvider = cdmType.DRMProvider, + DRMVersion = cdmType.DRMVersion, + DRMType = cdmType.DRMType, + DeviceVendor = DeviceInfo.brand, + DeviceModel = DeviceInfo.model + ) + ) + ) + } + + private fun createTitaniumDeviceHeader(configuration: DRMConfiguration, cdmType: TitaniumCDMDescription): String { + val deviceAuthorizationData = getTitaniumDeviceAuthorizationData(configuration.integrationParameters, cdmType) + val jsonData = Gson().toJson(deviceAuthorizationData) + return Base64.encodeToString(jsonData.toByteArray(), Base64.NO_WRAP) + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt new file mode 100644 index 00000000..1315c162 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt @@ -0,0 +1,125 @@ +package com.theoplayer.contentprotectionintegration.integration.titanium + +data class TitaniumCDMDescription( + /** + * String denoting the vendor of the underlying Content Decryption Module (CDM) provided by + * the host platform, e.g. “Google” (OPTIONAL) + */ + val DRMProvider: String, + + /** + * String denoting the CDM version (OPTIONAL) + */ + val DRMVersion: String, + + /** + * String denoting the DRM scheme that the CDM implements, e.g. “Widevine” (OPTIONAL) + */ + val DRMType: String, +) + +val TitaniumWidevineCDMDescription = TitaniumCDMDescription( +"Google", +"1.4.8.86", +"Widevine" +) + +val PlayreadyV2CDMDescription = TitaniumCDMDescription( + "Microsoft", + "2.9", + "Playready" +) + +val PlayreadyV3CDMDescription = TitaniumCDMDescription( + "Microsoft", + "3", + "Playready" +) + +data class TitaniumDeviceInfo( + /** + * String that should be set to the value “1” for applications compliant with the latest + * document version. + */ + val FormatVersion: String, + + /** + * String that should be set to the value “PC” for browser-based applications (OPTIONAL). + */ + val DeviceType: String, + + /** + * String denoting the operating system version of the host platform, e.g. “Linux” (OPTIONAL). + */ + val OSType: String, + + /** + * String denoting the operating system version of the host platform, e.g. “8.1” (OPTIONAL). + */ + val OSVersion: String, + + /** + * String denoting the vendor of the underlying Content Decryption Module (CDM) provided by + * the host platform, e.g. “Google” (OPTIONAL). + */ + val DRMProvider: String, + + /** + * String denoting the CDM version (OPTIONAL). + */ + val DRMVersion: String, + + /** + * String denoting the DRM scheme that the CDM implements, e.g. “Widevine” (OPTIONAL). + */ + val DRMType: String, + + /** + * String denoting the OEM vendor of the host hardware platform (OPTIONAL). + */ + val DeviceVendor: String, + + /** + * String denoting the OEM model identifier of the host hardware platform (OPTIONAL). + */ + val DeviceModel: String +) + +data class TitaniumLatensRegistration( + /** + * String denoting the Customer ID attribute as defined in the MultiTrust subscriber management + * system. + */ + val CustomerName: String, + + /** + * String denoting the Account ID attribute as defined in the MultiTrust subscriber management + * system. + */ + val AccountName: String, + + /** + * String denoting a unique identifier derived for this device and provisioned in the + * MultiTrust subscriber management system. + */ + val PortalId: String, + + /** + * String denoting an application defined ‘friendly name’ associated with this device. + */ + val FriendlyName: String, + + /** + * String denoting the versioning information for the application (OPTIONAL). + */ + val AppVersion: String?, + + /** + * Object describing the host platform. + */ + val DeviceInfo: TitaniumDeviceInfo +) + +data class TitaniumDeviceAuthorizationData( + val LatensRegistration: TitaniumLatensRegistration +) diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegration.kt new file mode 100644 index 00000000..04381348 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegration.kt @@ -0,0 +1,23 @@ +package com.theoplayer.contentprotectionintegration.integration.titanium + +import com.theoplayer.android.api.contentprotection.* +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.contentprotectionintegration.integration.titanium.TitaniumBaseRegistration.createTitaniumHeaders + +class TitaniumWidevineContentProtectionIntegration(private val configuration: DRMConfiguration): + ContentProtectionIntegration() { + + override fun onCertificateRequest(request: Request, callback: CertificateRequestCallback) { + request.apply { + headers.putAll(createTitaniumHeaders(configuration, TitaniumWidevineCDMDescription)) + callback.request(this) + } + } + + override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { + request.apply { + headers.putAll(createTitaniumHeaders(configuration, TitaniumWidevineCDMDescription)) + callback.request(this) + } + } +} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegrationFactory.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegrationFactory.java new file mode 100644 index 00000000..73d84419 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegrationFactory.java @@ -0,0 +1,12 @@ +package com.theoplayer.contentprotectionintegration.integration.titanium; + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; +import com.theoplayer.android.api.source.drm.DRMConfiguration; + +public class TitaniumWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + @Override + public ContentProtectionIntegration build(DRMConfiguration configuration) { + return new TitaniumWidevineContentProtectionIntegration(configuration); + } +} From a6af2651d4ec652e19daad9dc48e8bac8a0e133c Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Mon, 14 Nov 2022 16:15:42 +0100 Subject: [PATCH 51/85] Add demo entry --- .../SourceManager.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt index 59a3f7b0..f464c6b7 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt @@ -137,6 +137,41 @@ class SourceManager private constructor(context: Context) { hashMapOf() ) + // Titanium DRM using an authToken + val TITANIUM_AUTH_ID = "custom_titanium_auth" + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + TITANIUM_AUTH_ID, + KeySystemId.WIDEVINE, + TitaniumWidevineContentProtectionIntegrationFactory() + ) + sources["Titanium Widevine (authToken)"] = buildWidevineSourceDescription( + TITANIUM_AUTH_ID, + "", + "", + hashMapOf( + "authToken" to "" + ) + ) + + // Titanium DRM using deviceInfo + val TITANIUM_DEVICE_ID = "custom_titanium_device" + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + TITANIUM_DEVICE_ID, + KeySystemId.WIDEVINE, + TitaniumWidevineContentProtectionIntegrationFactory() + ) + sources["Titanium Widevine (device)"] = buildWidevineSourceDescription( + TITANIUM_DEVICE_ID, + "", + "", + hashMapOf( + "accountName" to "", + "customerName" to "", + "friendlyName" to "", + "portalId" to "", + ) + ) + // add other registrations & sources here ... } } \ No newline at end of file From e33fe7610793c6d0b933292c01dd921e5cb27d89 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Mon, 14 Nov 2022 16:38:03 +0100 Subject: [PATCH 52/85] Update README --- android/README.md | 187 +++++++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 93 deletions(-) diff --git a/android/README.md b/android/README.md index c08507fa..0c08e0c3 100644 --- a/android/README.md +++ b/android/README.md @@ -37,55 +37,57 @@ DRM flow. All methods are optional. They can be omitted if the integration does not require additional action, in which case the default implementation will be used. -```java -package com.theoplayer.contentprotectionintegration.custom; - -import com.theoplayer.android.api.contentprotection.CertificateRequestCallback; -import com.theoplayer.android.api.contentprotection.CertificateResponseCallback; -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback; -import com.theoplayer.android.api.contentprotection.LicenseResponseCallback; -import com.theoplayer.android.api.contentprotection.Request; -import com.theoplayer.android.api.contentprotection.Response; -import com.theoplayer.android.api.source.drm.DRMConfiguration; - -public class CustomContentProtectionIntegration extends ContentProtectionIntegration { - - private final DRMConfiguration contentProtectionConfiguration; - - public CustomContentProtectionIntegration(DRMConfiguration configuration) { - this.contentProtectionConfiguration = configuration; - } - - public void onCertificateRequest(Request request, CertificateRequestCallback callback) { - callback.request(request); +``` +package com.theoplayer.contentprotectionintegration.custom + +import com.theoplayer.android.api.contentprotection.CertificateRequestCallback +import com.theoplayer.android.api.contentprotection.CertificateResponseCallback +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback +import com.theoplayer.android.api.contentprotection.LicenseResponseCallback +import com.theoplayer.android.api.contentprotection.Request +import com.theoplayer.android.api.contentprotection.Response +import com.theoplayer.android.api.source.drm.DRMConfiguration + +class CustomContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : + ContentProtectionIntegration() { + + override fun onCertificateRequest(request: Request, callback: CertificateRequestCallback) { + callback.request(request) } - public void onCertificateResponse(Response response, CertificateResponseCallback callback) { - callback.respond(response.getBody()); + override fun onCertificateResponse(response: Response, callback: CertificateResponseCallback) { + callback.respond(response.body) } - public void onLicenseRequest(Request request, LicenseRequestCallback callback) { - // Optionally apply integration parameters, such as a token, which are passed when setting the source, or - // add additional header fields. - // final Object token = this.contentProtectionConfiguration.getIntegrationParameters().get("token"); - // request.getHeaders().put("x-token", token.toString()); - // request.getHeaders().put("Content-Type", "text/plain"); + override fun onLicenseRequest(Request request, LicenseRequestCallback callback) { + // /** + // * Optionally apply integration parameters, such as a token, which are passed when setting the source, or + // * add additional header fields. + // */ + // val token = contentProtectionConfiguration.integrationParameters["token"] + // request.headers["x-token"] = token + // request.headers["Content-Type"] = "text/plain" - // If required by the DRM provider, wrap or transform the request body. - // JSONObject jsonBody = new JSONObject(); + // /** + // * If required by the DRM provider, wrap or transform the request body. + // */ + // val kid = contentProtectionConfiguration.integrationParameters["keyId"] + // val jsonBody = JSONObject() // try { - // jsonBody.put("drm_info", TypeUtils.fromByteArrayToUint8JsonArray(request.getBody())); - // } catch (JSONException e) { - // e.printStackTrace(); + // jsonBody.put("token", token) + // jsonBody.put("drm_info", fromByteArrayToUint8JsonArray(request.body!!)) + // jsonBody.put("kid", kid) + // } catch (e: JSONException) { + // e.printStackTrace() // } - // request.setBody(TypeUtils.fromJsonToByteArray(jsonBody)); + // request.body = fromJsonToByteArray(jsonBody) - callback.request(request); + callback.request(request) } - public void onLicenseResponse(Response response, LicenseResponseCallback callback) { - callback.respond(response.getBody()); + override fun onLicenseResponse(response: Response, callback: LicenseResponseCallback) { + callback.respond(response.body) } } ``` @@ -102,17 +104,17 @@ THEOplayer will use this factory in its DRM flow whenever it needs a ContentProt matches with the content protected source. How THEOplayer knows which factory to take will be determined in the `registerContentProtectionIntegration` step next. -```java -package com.theoplayer.contentprotectionintegration.custom; +``` +package com.theoplayer.contentprotectionintegration.custom -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; -import com.theoplayer.android.api.source.drm.DRMConfiguration; +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory +import com.theoplayer.android.api.source.drm.DRMConfiguration -public class CustomContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - @Override - public ContentProtectionIntegration build(DRMConfiguration configuration) { - return new CustomContentProtectionIntegration(configuration); +class CustomContentProtectionIntegrationFactory: ContentProtectionIntegrationFactory { + + override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { + return CustomContentProtectionIntegration(configuration) } } ``` @@ -136,48 +138,45 @@ passed during registration, an instance of `CustomContentProtectionIntegration` Also add the source description here, which provides the manifest and license URLs along with any integration parameters. ```java -public class SourceManager { +class SourceManager private constructor(context: Context) { - private void initSources(Context context) { + private fun initSources(context: Context) { // Custom content protect integration - String CUSTOM_ID = "CUSTOM"; + val CUSTOM_ID = "CUSTOM" THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - CUSTOM_ID, - KeySystemId.WIDEVINE, - new CustomContentProtectionIntegrationFactory() - ); - sources.put( - "Custom Widevine", - buildWidevineSourceDescription( - CUSTOM_ID, - "", - "", - new HashMap() {{ - // optional integration parameters - // put("token", ""); - }} - ) - ); + CUSTOM_ID, + KeySystemId.WIDEVINE, + CustomWidevineContentProtectionIntegrationFactory() + ) + sources["Custom Widevine"] = buildWidevineSourceDescription( + CUSTOM_ID, + "", + "", + hashMapOf( + // optional integration parameters + // "token" to "", + // "keyId" to "" + ) + ) // add other registrations & sources here ... } - private SourceDescription buildWidevineSourceDescription( - String integrationId, - String manifestUrl, - String licenseUrl, - HashMap integrationParams) { - return sourceDescription( - typedSource(manifestUrl) - .setNativeRenderingEnabled(true) - .setNativeUiRenderingEnabled(false) - .drm(new DRMConfiguration.Builder() - .customIntegrationId(integrationId) - .integrationParameters(integrationParams) - .widevine(keySystemConfiguration(licenseUrl).build()) - .build()) - .build() - ).build(); + private fun buildWidevineSourceDescription( + integrationId: String, + manifestUrl: String, + licenseUrl: String, + integrationParams: HashMap + ): SourceDescription { + return SourceDescription.Builder( + TypedSource.Builder(manifestUrl) + .drm(DRMConfiguration.Builder() + .customIntegrationId(integrationId) + .integrationParameters(integrationParams) + .widevine(KeySystemConfiguration.Builder(licenseUrl).build()) + .build()) + .build() + ).build() } } ``` @@ -216,17 +215,18 @@ A common way of passing extra data to the server is by wrapping the raw request in a JSON object with some additional properties, which is then transformed back into the required type `byte[]`. The following example is taken from the [VuDRM integration sample](app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java): -```java -JSONObject jsonBody = new JSONObject(); +``` +val jsonBody = JSONObject() try { - jsonBody.put("token", token); - jsonBody.put("drm_info", TypeUtils.fromByteArrayToUint8JsonArray(request.getBody())); - jsonBody.put("kid", kid); -} catch (JSONException e) { - e.printStackTrace(); + jsonBody.put("token", token) + jsonBody.put("drm_info", fromByteArrayToUint8JsonArray(request.body!!)) + jsonBody.put("kid", kid) +} catch (e: JSONException) { + e.printStackTrace() } -request.setBody(jsonBody.toString().getBytes()); +request.body = fromJsonToByteArray(jsonBody) ``` + where the `fromByteArrayToUint8JsonArray` helper method creates a JSON array from a `byte[]` object. Similarly, the `Response` object returned from the server contains among others the response headers and the response @@ -264,10 +264,11 @@ The repository already contains a few integration examples that could be used as - Microsoft Azure DRM - KeyOS -The repository also lists some examples with placeholder data (in `SourceManager.java`) that can use the default Widevine integration: +The repository also lists some examples with placeholder data (in `SourceManager`) that can use the default Widevine integration: - Verimatrix Core - Verimatrix MultiDRM Standard +- Titanium DRM, either using authToken or device info ### Testing an integration @@ -276,7 +277,7 @@ reach out to THEOplayer [customer support](https://www.theoplayer.com/contact). - Depending on the features included in your THEOplayer build, include the necessary dependencies in `/android/app/build.gradle`. - Open the `/android` folder in [Android Studio](https://developer.android.com/studio) and build the project. -- Ensure that a valid license key is entered in the `AndroidManifest.xml` instead of `"YOUR_LICENSE_HERE"`. More information is available at https://github.com/THEOplayer/theoplayer-sdk-android. +- Ensure that a valid license key is entered in the `theoplayer_license` entry of `values.xml`. More information is available at https://github.com/THEOplayer/theoplayer-sdk-android. - Make sure to fill in the necessary fields in `SourceManager` for the content integration that will be tested, such as the manifest url and any integration parameters. - Attach either a physical Android device or start an Android emulator, and run the project. From a57964727fe8f5a1423dd7df8971c8694589cd88 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Fri, 25 Nov 2022 09:14:54 +0100 Subject: [PATCH 53/85] Add verimatrixcoredrm Widevine connector for Android --- ...oreWidevineContentProtectionIntegration.kt | 37 +++++++++++++++++++ ...vineContentProtectionIntegrationFactory.kt | 11 ++++++ 2 files changed, 48 insertions(+) create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegration.kt create mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegrationFactory.kt diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegration.kt new file mode 100644 index 00000000..51d49e8d --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegration.kt @@ -0,0 +1,37 @@ +package com.theoplayer.contentprotectionintegration.integration.verimatrixcoredrm + +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration +import com.theoplayer.android.api.contentprotection.CertificateRequestCallback +import com.theoplayer.android.api.contentprotection.LicenseRequestCallback +import com.theoplayer.android.api.contentprotection.Request +import java.lang.NullPointerException + +private const val HEADER_AUTH = "Authorization" +private const val PARAM_TOKEN = "drmToken" + +class VerimatrixCoreWidevineContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : + ContentProtectionIntegration() { + + init { + if (contentProtectionConfiguration.integrationParameters["drmToken"] == null) { + throw(NullPointerException("The Verimatrix drmToken can not be null")) + } + } + + private fun applyHeaders(request: Request): Request { + if (request.body == null) { + throw NullPointerException("The request body can not be null") + } + request.headers[HEADER_AUTH] = contentProtectionConfiguration.integrationParameters[PARAM_TOKEN] as String + return request + } + + override fun onCertificateRequest(request: Request, callback: CertificateRequestCallback) { + callback.request(applyHeaders(request)) + } + + override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { + callback.request(applyHeaders(request)) + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegrationFactory.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegrationFactory.kt new file mode 100644 index 00000000..421bf764 --- /dev/null +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegrationFactory.kt @@ -0,0 +1,11 @@ +package com.theoplayer.contentprotectionintegration.integration.verimatrixcoredrm + +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory +import com.theoplayer.android.api.source.drm.DRMConfiguration +import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration + +class VerimatrixCoreWidevineContentProtectionIntegrationFactory : ContentProtectionIntegrationFactory { + override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { + return VerimatrixCoreWidevineContentProtectionIntegration(configuration) + } +} \ No newline at end of file From 0514c9699e9b3f6b3fa4374d616457f2d1d72a4e Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Fri, 25 Nov 2022 09:16:42 +0100 Subject: [PATCH 54/85] Clean source descriptions --- .../SourceManager.kt | 178 +++++++++--------- 1 file changed, 88 insertions(+), 90 deletions(-) diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt index f464c6b7..ce37d420 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt @@ -5,14 +5,23 @@ import com.theoplayer.android.api.source.SourceDescription import com.theoplayer.android.api.source.drm.DRMConfiguration import com.theoplayer.android.api.THEOplayerGlobal import com.theoplayer.android.api.contentprotection.KeySystemId +import com.theoplayer.android.api.source.SourceType import com.theoplayer.android.api.source.TypedSource import com.theoplayer.android.api.source.drm.KeySystemConfiguration import com.theoplayer.contentprotectionintegration.integration.vudrm.VudrmWidevineContentProtectionIntegrationFactory import com.theoplayer.contentprotectionintegration.integration.azuredrm.AzureWidevineContentProtectionIntegrationFactory import com.theoplayer.contentprotectionintegration.integration.keyos.KeyOsWidevineContentProtectionIntegrationFactory import com.theoplayer.contentprotectionintegration.integration.titanium.TitaniumWidevineContentProtectionIntegrationFactory +import com.theoplayer.contentprotectionintegration.integration.verimatrixcoredrm.VerimatrixCoreWidevineContentProtectionIntegrationFactory import java.util.HashMap +private const val VUDRM_ID = "VUDRM" +private const val AZURE_ID = "AZURE" +private const val KEYOS_ID = "buydrm-keyos" +private const val VERIMATRIX_CORE_ID = "custom_verimatrix_core" +private const val TITANIUM_AUTH_ID = "custom_titanium_auth" +private const val TITANIUM_DEVICE_ID = "custom_titanium_device" + @Suppress("SameParameterValue") class SourceManager private constructor(context: Context) { companion object { @@ -38,139 +47,128 @@ class SourceManager private constructor(context: Context) { val sourcesNames: Array get() = sources.keys.toTypedArray() - private fun buildWidevineSourceDescription( + /** + * Convenience method to create a Widevine DRM configuration instance. + */ + private fun buildWidevineDrmConfiguration( integrationId: String, - manifestUrl: String, licenseUrl: String, integrationParams: HashMap - ): SourceDescription { - return SourceDescription.Builder( - TypedSource.Builder(manifestUrl) - .drm(DRMConfiguration.Builder() - .customIntegrationId(integrationId) - .integrationParameters(integrationParams) - .widevine(KeySystemConfiguration.Builder(licenseUrl).build()) - .build()) - .build() - ).build() - } - - private fun buildDefaultWidevineSourceDescription( - manifestUrl: String, - licenseUrl: String, - headers: HashMap - ): SourceDescription { - return SourceDescription.Builder( - TypedSource.Builder(manifestUrl) - .drm(DRMConfiguration.Builder() - .widevine(KeySystemConfiguration.Builder(licenseUrl) - .headers(headers) - .build()) - .build()) - .build() - ).build() + ): DRMConfiguration { + return DRMConfiguration.Builder() + .customIntegrationId(integrationId) + .integrationParameters(integrationParams) + .widevine(KeySystemConfiguration.Builder(licenseUrl).build()) + .build() } private fun initSources(context: Context) { // Vualto VUDRM Widevine content protect integration - val VUDRM_ID = "VUDRM" THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( VUDRM_ID, KeySystemId.WIDEVINE, VudrmWidevineContentProtectionIntegrationFactory() ) - sources["Vualto VUDRM Widevine"] = buildWidevineSourceDescription( - VUDRM_ID, - "", - "", - hashMapOf( - "token" to "", - "keyId" to "" - ) - ) + sources["Vualto VUDRM Widevine"] = SourceDescription.Builder( + TypedSource.Builder("") + .drm(buildWidevineDrmConfiguration( + VUDRM_ID, + "", + hashMapOf( + "token" to "", + "keyId" to "" + ) + )).build() + ).build() // Microsoft Azure Widevine content protect integration - val AZURE_ID = "AZURE" THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( AZURE_ID, KeySystemId.WIDEVINE, AzureWidevineContentProtectionIntegrationFactory() ) - sources["Microsoft Azure Widevine"] = buildWidevineSourceDescription( - AZURE_ID, - "", - "", - hashMapOf( - "token" to "", - ) - ) + sources["Microsoft Azure Widevine"] = SourceDescription.Builder( + TypedSource.Builder("") + .drm(buildWidevineDrmConfiguration( + AZURE_ID, + "", + hashMapOf( + "token" to "", + ) + )).build() + ).build() // BuyDRM KeyOS Widevine content protect integration - val KEYOS_ID = "buydrm-keyos" THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( KEYOS_ID, KeySystemId.WIDEVINE, KeyOsWidevineContentProtectionIntegrationFactory() ) - sources["BuyDRM KeyOs Widevine"] = buildWidevineSourceDescription( - KEYOS_ID, - "https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd", - "https://wv-keyos.licensekeyserver.com", - hashMapOf( - "x-keyos-authorization" to "PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg==", - ) - ) + sources["BuyDRM KeyOs Widevine"] = SourceDescription.Builder( + TypedSource.Builder("https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd") + .drm(buildWidevineDrmConfiguration( + KEYOS_ID, + "https://wv-keyos.licensekeyserver.com", + hashMapOf( + "x-keyos-authorization" to "PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg==", + ) + )).build() + ).build() // Verimatrix Multi-DRM Core - sources["Verimatrix Multi-DRM Core"] = buildDefaultWidevineSourceDescription( - "", - "https://multidrm.vsaas.verimatrixcloud.net/widevine", - hashMapOf( - "authorization" to "", - ) - ) - - // Verimatrix MultiDRM Standard - sources["Verimatrix MultiDRM Standard"] = buildDefaultWidevineSourceDescription( - "", - "https://vcas4-gc.emea.vmxdemos.net/widevine?deviceId=", - hashMapOf() + THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( + VERIMATRIX_CORE_ID, + KeySystemId.WIDEVINE, + VerimatrixCoreWidevineContentProtectionIntegrationFactory() ) + sources["Verimatrix Multi-DRM Core"] = SourceDescription.Builder( + TypedSource.Builder("") + .type(SourceType.DASH) + .drm(buildWidevineDrmConfiguration( + VERIMATRIX_CORE_ID, + "https://multidrm.vsaas.verimatrixcloud.net/widevine", + hashMapOf( + "drmToken" to "", + ) + )).build() + ).build() // Titanium DRM using an authToken - val TITANIUM_AUTH_ID = "custom_titanium_auth" THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( TITANIUM_AUTH_ID, KeySystemId.WIDEVINE, TitaniumWidevineContentProtectionIntegrationFactory() ) - sources["Titanium Widevine (authToken)"] = buildWidevineSourceDescription( - TITANIUM_AUTH_ID, - "", - "", - hashMapOf( - "authToken" to "" - ) - ) + sources["Titanium Widevine (authToken)"] = SourceDescription.Builder( + TypedSource.Builder("") + .drm(buildWidevineDrmConfiguration( + TITANIUM_AUTH_ID, + "", + hashMapOf( + "authToken" to "" + ) + )).build() + ).build() // Titanium DRM using deviceInfo - val TITANIUM_DEVICE_ID = "custom_titanium_device" THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( TITANIUM_DEVICE_ID, KeySystemId.WIDEVINE, TitaniumWidevineContentProtectionIntegrationFactory() ) - sources["Titanium Widevine (device)"] = buildWidevineSourceDescription( - TITANIUM_DEVICE_ID, - "", - "", - hashMapOf( - "accountName" to "", - "customerName" to "", - "friendlyName" to "", - "portalId" to "", - ) - ) + sources["Titanium Widevine (device)"] = SourceDescription.Builder( + TypedSource.Builder("") + .drm(buildWidevineDrmConfiguration( + TITANIUM_DEVICE_ID, + "", + hashMapOf( + "accountName" to "", + "customerName" to "", + "friendlyName" to "", + "portalId" to "", + ) + )).build() + ).build() // add other registrations & sources here ... } From 5cde1acd1d38daac24e1c2167edf05ce32436ab2 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Fri, 25 Nov 2022 09:20:08 +0100 Subject: [PATCH 55/85] Update README --- android/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/android/README.md b/android/README.md index 0c08e0c3..b25fd3a4 100644 --- a/android/README.md +++ b/android/README.md @@ -267,7 +267,6 @@ The repository already contains a few integration examples that could be used as The repository also lists some examples with placeholder data (in `SourceManager`) that can use the default Widevine integration: - Verimatrix Core -- Verimatrix MultiDRM Standard - Titanium DRM, either using authToken or device info ### Testing an integration From 95525eac49c8b9e683c8b39370541c1070b6a8f9 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Fri, 25 Nov 2022 09:45:39 +0100 Subject: [PATCH 56/85] Update verimatrixcore drm connectors for web --- web/src/index.ts | 35 ++++++----- .../VerimatrixCoreDrmConfiguration.ts | 29 +++++++++ ...DrmFairplayContentProtectionIntegration.ts | 43 +++++++++++++ ...playContentProtectionIntegrationFactory.ts | 9 +++ ...rmPlayReadyContentProtectionIntegration.ts | 19 ++++++ ...eadyContentProtectionIntegrationFactory.ts | 9 +++ ...DrmWidevineContentProtectionIntegration.ts | 28 +++++++++ ...vineContentProtectionIntegrationFactory.ts | 9 +++ .../VerimatrixCoreIntegrationParameters.ts | 7 +++ .../VerimatrixDrmConfiguration.ts | 17 ------ ...DrmFairPlayContentProtectionIntegration.ts | 60 ------------------- ...PlayContentProtectionIntegrationFactory.ts | 12 ---- web/test/verimatrixcoredrm/fairplay.html | 7 ++- web/test/verimatrixcoredrm/playready.html | 15 +++-- web/test/verimatrixcoredrm/widevine.html | 19 ++++-- 15 files changed, 201 insertions(+), 117 deletions(-) create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts create mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts delete mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixDrmConfiguration.ts delete mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts delete mode 100644 web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory.ts diff --git a/web/src/index.ts b/web/src/index.ts index d5fed2bd..65b6e5aa 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -24,7 +24,7 @@ import { ComcastDrmFairPlayContentProtectionIntegrationFactory } from './integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory'; import { CastLabsDrmFairPlayContentProtectionIntegrationFactory } from './integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory'; -import { IrdetoControlFairplayContentProtectionIntegrationFactory} from +import { IrdetoControlFairplayContentProtectionIntegrationFactory } from './integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory'; import { NagraDrmWidevineContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory'; @@ -35,19 +35,21 @@ import { NagraDrmFairPlayContentProtectionIntegrationFactory } from import { KeyOSDrmFairplayContentProtectionIntegrationFactory } from './integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory'; import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from - "./integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory"; -import { KeyOSDrmPlayReadyContentProtectionIntegrationFactory} from - "./integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory"; -import { VerimatrixDrmFairPlayContentProtectionIntegrationFactory } from - './integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory'; -import { VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory} from - "./integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory"; + './integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory'; +import { KeyOSDrmPlayReadyContentProtectionIntegrationFactory } from + './integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory'; +import { VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory } from + './integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory'; +import { VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory } from + './integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory'; +import { VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory } from + './integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory'; import { TitaniumWidevineContentProtectionIntegrationFactory } from - "./integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory"; -import { TitaniumPlayReadyContentProtectionIntegrationFactory} from - "./integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory"; -import { TitaniumFairplayContentProtectionIntegrationFactory} from - "./integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory"; + './integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory'; +import { TitaniumPlayReadyContentProtectionIntegrationFactory } from + './integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory'; +import { TitaniumFairplayContentProtectionIntegrationFactory } from + './integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory'; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -69,12 +71,13 @@ export { KeyOSDrmWidevineContentProtectionIntegrationFactory, KeyOSDrmFairplayContentProtectionIntegrationFactory, KeyOSDrmPlayReadyContentProtectionIntegrationFactory, - VerimatrixDrmFairPlayContentProtectionIntegrationFactory, + VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory, + VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory, + VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory, CastLabsDrmFairPlayContentProtectionIntegrationFactory, - VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory, TitaniumWidevineContentProtectionIntegrationFactory, TitaniumPlayReadyContentProtectionIntegrationFactory, TitaniumFairplayContentProtectionIntegrationFactory, }; -export const THEOPLAYER_LICENSE = "YOUR_LICENSE_HERE"; \ No newline at end of file +export const THEOPLAYER_LICENSE = 'YOUR_LICENSE_HERE'; diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts new file mode 100644 index 00000000..79164eb8 --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts @@ -0,0 +1,29 @@ +import type { DRMConfiguration } from 'THEOplayer'; +import type { VerimatrixCoreIntegrationParameters } from './VerimatrixCoreIntegrationParameters'; + +/** + * The identifier of the Ezdrm integration. + */ +export type VerimatrixCoreDrmIntegrationID = 'verimatrixcoredrmCustom'; + +/** + * Describes the configuration of the Verimatrix Core DRM integration. + * + * ``` + * const drmConfiguration = { + * integration : 'verimatrixcoredrmCustom', + * fairplay: { + * certificateURL: 'yourCertificateUrl', + * licenseAcquisitionURL: 'yourLicenseAcquisitionURL' + * } + * } + * ``` + */ +export interface VerimatrixCoreDrmConfiguration extends DRMConfiguration { + /** + * The identifier of the DRM integration. + */ + integration: VerimatrixCoreDrmIntegrationID; + + integrationParameters: VerimatrixCoreIntegrationParameters; +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts new file mode 100644 index 00000000..e5690bd2 --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts @@ -0,0 +1,43 @@ +import type { ContentProtectionIntegration, LicenseRequest, LicenseResponse, MaybeAsync } from 'THEOplayer'; +import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; +import { fromBase64StringToUint8Array, fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToObject } from '../../utils/TypeUtils'; + +export class VerimatrixCoreDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { + static readonly DEFAULT_LICENSE_URL = 'insert default license url here'; + + private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; + + constructor(configuration: VerimatrixCoreDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + const spcMessage = fromUint8ArrayToBase64String(request.body!); + const bodyObject = { + spc: spcMessage, + }; + const bodyData = fromObjectToUint8Array(bodyObject); + request.url = + this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? + VerimatrixCoreDrmFairplayContentProtectionIntegration.DEFAULT_LICENSE_URL; + request.headers = { + 'content-type': 'application/json', + Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '', + }; + request.body = bodyData; + return request; + } + + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + const responseObject = fromUint8ArrayToObject(response.body); + return fromBase64StringToUint8Array(responseObject.ckc); + } + + extractFairplayContentId(skdUrl: string): string { + // drop params in url + const chunks = skdUrl.split('?'); + const sdkUrlWithoutParams = chunks[0]; + // drop the 'skd://' part + return sdkUrlWithoutParams.substring(6, sdkUrlWithoutParams.length); + } +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..98fe7c28 --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts @@ -0,0 +1,9 @@ +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; +import { VerimatrixCoreDrmFairplayContentProtectionIntegration } from './VerimatrixCoreDrmFairplayContentProtectionIntegration'; + +export class VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { + return new VerimatrixCoreDrmFairplayContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts new file mode 100644 index 00000000..c9e85483 --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts @@ -0,0 +1,19 @@ +import type { ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; + +export class VerimatrixCoreDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; + + constructor(configuration: VerimatrixCoreDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + 'content-type': 'application/octet-stream', + Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '', + }; + return request; + } +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..e08f686a --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -0,0 +1,9 @@ +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; +import { VerimatrixCoreDrmPlayReadyContentProtectionIntegration } from './VerimatrixCoreDrmPlayReadyContentProtectionIntegration'; + +export class VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { + return new VerimatrixCoreDrmPlayReadyContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts new file mode 100644 index 00000000..00ebd546 --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts @@ -0,0 +1,28 @@ +import type { CertificateRequest, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; + +export class VerimatrixCoreDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { + private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; + + constructor(configuration: VerimatrixCoreDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + } + + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + 'content-type': 'application/octet-stream', + Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '', + }; + return request; + } + + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + 'content-type': 'application/octet-stream', + Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '', + }; + return request; + } +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts new file mode 100644 index 00000000..e8b59e42 --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts @@ -0,0 +1,9 @@ +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; +import { VerimatrixCoreDrmWidevineContentProtectionIntegration } from './VerimatrixCoreDrmWidevineContentProtectionIntegration'; + +export class VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { + build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { + return new VerimatrixCoreDrmWidevineContentProtectionIntegration(configuration); + } +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts b/web/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts new file mode 100644 index 00000000..86b1039b --- /dev/null +++ b/web/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts @@ -0,0 +1,7 @@ +export interface VerimatrixCoreIntegrationParameters { + /** + * The drm token. + * + */ + drmToken?: string; +} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmConfiguration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmConfiguration.ts deleted file mode 100644 index e5bffbe3..00000000 --- a/web/src/integration/verimatrixcoredrm/VerimatrixDrmConfiguration.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { DRMConfiguration } from 'THEOplayer'; - -/** - * The identifier of the Verimatrix Core DRM integration. - */ -export type VerimatrixIntegrationID = 'verimatrixcore'; - -/** - * Describes the configuration of the Verimatrix Core DRM integration. - */ -export interface VerimatrixDrmConfiguration extends DRMConfiguration { - - /** - * The identifier of the DRM integration. - */ - integration: VerimatrixIntegrationID; -} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts deleted file mode 100644 index 3af505b3..00000000 --- a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegration.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { - BufferSource, - ContentProtectionIntegration, - LicenseRequest, - LicenseResponse, - MaybeAsync, -} from 'THEOplayer'; -import { VerimatrixDrmConfiguration } from './VerimatrixDrmConfiguration'; -import { - fromBase64StringToArrayBuffer, - fromBase64StringToString, - fromObjectToUint8Array, - fromUint8ArrayToBase64String, fromUint8ArrayToObject, - fromUint8ArrayToString -} from '../../utils/TypeUtils'; - -export class VerimatrixDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: VerimatrixDrmConfiguration; - private contentId: string | undefined = undefined; - - static readonly DEFAULT_FAIRPLAY_LICENSE_URL = 'https://multidrm.vsaas.verimatrixcloud.net/fairplay'; - - constructor(configuration: VerimatrixDrmConfiguration) { - this.contentProtectionConfiguration = configuration; - } - - onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - const spcMessage = fromUint8ArrayToBase64String(request.body!); - const body = { - "spc": spcMessage - }; - const newBody = fromObjectToUint8Array(body); - const newRequest = { - ...request, - url: this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? - VerimatrixDrmFairPlayContentProtectionIntegration.DEFAULT_FAIRPLAY_LICENSE_URL, - headers: { - 'Content-Type': 'application/json' - }, - body: newBody - }; - return newRequest; - - } - - onLicenseResponse?(response: LicenseResponse): MaybeAsync { - const responseObject = fromUint8ArrayToObject(response.body); - return fromBase64StringToArrayBuffer(responseObject.ckc); - } - - extractFairplayContentId(skdUrl: string): string { - if (skdUrl.indexOf("skd") > 0 || skdUrl.indexOf("http") > 0) { - skdUrl = skdUrl.substring(1); - } - const link = document.createElement('a'); - link.href = skdUrl; - this.contentId = link.hostname; - return this.contentId; - } -} diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory.ts b/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory.ts deleted file mode 100644 index 7cf4553c..00000000 --- a/web/src/integration/verimatrixcoredrm/VerimatrixDrmFairPlayContentProtectionIntegrationFactory.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { VerimatrixDrmConfiguration } from './VerimatrixDrmConfiguration'; -import { VerimatrixDrmFairPlayContentProtectionIntegration } from './VerimatrixDrmFairPlayContentProtectionIntegration'; - -export class VerimatrixDrmFairPlayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - build(configuration: VerimatrixDrmConfiguration): ContentProtectionIntegration { - return new VerimatrixDrmFairPlayContentProtectionIntegration(configuration); - } -} diff --git a/web/test/verimatrixcoredrm/fairplay.html b/web/test/verimatrixcoredrm/fairplay.html index 0b868dd9..e9b1ba7e 100644 --- a/web/test/verimatrixcoredrm/fairplay.html +++ b/web/test/verimatrixcoredrm/fairplay.html @@ -22,7 +22,7 @@ THEOplayer.registerContentProtectionIntegration( 'verimatrixcore', 'fairplay', - new ContentProtectionIntegrations.VerimatrixDrmFairPlayContentProtectionIntegrationFactory() + new ContentProtectionIntegrations.VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory() ); const src = ''; @@ -39,8 +39,11 @@ licenseAcquisitionURL: licenseAcquisitionURL, certificateURL: certificateURL }, + integration: 'verimatrixcore', + integrationParameters: { + drmToken + }, preferredKeySystems: ['fairplay', 'widevine', 'playready'], - integration: 'verimatrixcore' } } ] diff --git a/web/test/verimatrixcoredrm/playready.html b/web/test/verimatrixcoredrm/playready.html index 903be415..15d7b51a 100644 --- a/web/test/verimatrixcoredrm/playready.html +++ b/web/test/verimatrixcoredrm/playready.html @@ -19,10 +19,16 @@ libraryLocation: '/THEOplayer/' }); + THEOplayer.registerContentProtectionIntegration( + 'verimatrixcore', + 'playready', + new ContentProtectionIntegrations.VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory() + ); + const src = ''; const licenseAcquisitionURL = 'https://multidrm.vsaas.verimatrixcloud.net/playready'; const token = ''; - + player.source = { sources: [ { @@ -31,9 +37,10 @@ contentProtection: { playready: { licenseAcquisitionURL: licenseAcquisitionURL, - headers: { - 'Authorization': token - } + }, + integration: 'verimatrixcore', + integrationParameters: { + drmToken }, preferredKeySystems: ['playready', 'widevine', 'fairplay'] } diff --git a/web/test/verimatrixcoredrm/widevine.html b/web/test/verimatrixcoredrm/widevine.html index 61fd3ae2..1eb1c025 100644 --- a/web/test/verimatrixcoredrm/widevine.html +++ b/web/test/verimatrixcoredrm/widevine.html @@ -19,10 +19,16 @@ libraryLocation: '/THEOplayer/' }); + THEOplayer.registerContentProtectionIntegration( + 'verimatrixcore', + 'widevine', + new ContentProtectionIntegrations.VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory() + ); + const src = ''; const licenseAcquisitionURL = 'https://multidrm.vsaas.verimatrixcloud.net/widevine'; - const token = ''; - + const drmToken = ''; + player.source = { sources: [ { @@ -30,10 +36,11 @@ type: 'application/dash+xml', contentProtection: { widevine: { - licenseAcquisitionURL: licenseAcquisitionURL, - headers: { - 'Authorization': token - } + licenseAcquisitionURL: licenseAcquisitionURL + }, + integration: 'verimatrixcore', + integrationParameters: { + drmToken }, preferredKeySystems: ['widevine', 'playready', 'fairplay'] } From 36a382a3ad84a00fe8c62f7b2dd6032e1a0aed28 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Fri, 25 Nov 2022 09:46:10 +0100 Subject: [PATCH 57/85] Remove verimatrix standard drm connectors --- ...VerimatrixMultiDRMStandardConfiguration.ts | 17 ------ ...ardFairPlayContentProtectionIntegration.ts | 52 ------------------- ...PlayContentProtectionIntegrationFactory.ts | 12 ----- .../verimatrixmultidrmstandard/fairplay.html | 51 ------------------ .../verimatrixmultidrmstandard/playready.html | 42 --------------- .../verimatrixmultidrmstandard/widevine.html | 42 --------------- 6 files changed, 216 deletions(-) delete mode 100644 web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardConfiguration.ts delete mode 100644 web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts delete mode 100644 web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory.ts delete mode 100644 web/test/verimatrixmultidrmstandard/fairplay.html delete mode 100644 web/test/verimatrixmultidrmstandard/playready.html delete mode 100644 web/test/verimatrixmultidrmstandard/widevine.html diff --git a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardConfiguration.ts b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardConfiguration.ts deleted file mode 100644 index 1b944890..00000000 --- a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardConfiguration.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { DRMConfiguration } from 'THEOplayer'; - -/** - * The identifier of the Verimatrix Core DRM integration. - */ -export type VerimatrixIntegrationID = 'verimatrixmultidrmstandard'; - -/** - * Describes the configuration of the Verimatrix Core DRM integration. - */ -export interface VerimatrixMultiDRMStandardConfiguration extends DRMConfiguration { - - /** - * The identifier of the DRM integration. - */ - integration: VerimatrixIntegrationID; -} diff --git a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts deleted file mode 100644 index cb362bc4..00000000 --- a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { - BufferSource, - ContentProtectionIntegration, - LicenseRequest, - LicenseResponse, - MaybeAsync, -} from 'THEOplayer'; -import { VerimatrixMultiDRMStandardConfiguration } from './VerimatrixMultiDRMStandardConfiguration'; -import { - fromBase64StringToArrayBuffer, - fromBase64StringToString, - fromObjectToUint8Array, fromStringToUint8Array, - fromUint8ArrayToBase64String, fromUint8ArrayToObject, - fromUint8ArrayToString -} from '../../utils/TypeUtils'; -import { extractContentId } from '../../utils/FairplayUtils'; - -export class VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: VerimatrixMultiDRMStandardConfiguration; - private contentId: string | undefined = undefined; - - constructor(configuration: VerimatrixMultiDRMStandardConfiguration) { - this.contentProtectionConfiguration = configuration; - } - - onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - const spcMessage = fromUint8ArrayToBase64String(request.body!); - const url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; - if (!this.contentId) { - throw new Error('The FairPlay Verimatrix Multi-DRM Standard content ID has not been correctly configured.'); - } - const licenseParameters = `spc=${encodeURIComponent(spcMessage)}&assetId=${encodeURIComponent(this.contentId)}`; - const newBody = fromStringToUint8Array(licenseParameters); - const newRequest = { - ...request, - url: url, - body: newBody - }; - return newRequest; - } - - onLicenseResponse?(response: LicenseResponse): MaybeAsync { - const responseObject = fromUint8ArrayToObject(response.body); - return fromBase64StringToArrayBuffer(responseObject.ckc); - } - - extractFairplayContentId(skdUrl: string): string { - this.contentId = extractContentId(skdUrl); - return this.contentId; - } - -} diff --git a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory.ts b/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory.ts deleted file mode 100644 index bfd8c2bc..00000000 --- a/web/src/integration/verimatrixmultidrmstandard/VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { VerimatrixMultiDRMStandardConfiguration } from './VerimatrixMultiDRMStandardConfiguration'; -import { VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration } from './VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration'; - -export class VerimatrixMultiDRMStandardFairPlayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - build(configuration: VerimatrixMultiDRMStandardConfiguration): ContentProtectionIntegration { - return new VerimatrixMultiDRMStandardFairPlayContentProtectionIntegration(configuration); - } -} diff --git a/web/test/verimatrixmultidrmstandard/fairplay.html b/web/test/verimatrixmultidrmstandard/fairplay.html deleted file mode 100644 index 74f47a07..00000000 --- a/web/test/verimatrixmultidrmstandard/fairplay.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Verimatrix MultiDRM Standard FairPlay Test - - - - - -

- - - diff --git a/web/test/verimatrixmultidrmstandard/playready.html b/web/test/verimatrixmultidrmstandard/playready.html deleted file mode 100644 index 41c1544d..00000000 --- a/web/test/verimatrixmultidrmstandard/playready.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Verimatrix MultiDRM Standard PlayReady Test - - - - - -
- - - diff --git a/web/test/verimatrixmultidrmstandard/widevine.html b/web/test/verimatrixmultidrmstandard/widevine.html deleted file mode 100644 index 1094853e..00000000 --- a/web/test/verimatrixmultidrmstandard/widevine.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Verimatrix MultiDRM Standard Widevine Test - - - - - -
- - - From 2aa171dcceddb19cea74aa5b3c1b24d07e5bb120 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Thu, 1 Dec 2022 09:49:34 +0100 Subject: [PATCH 58/85] Fix optional parameters --- .../TitaniumDeviceAuthorizationData.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt index 1315c162..a1c28c1d 100644 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt +++ b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt @@ -5,17 +5,17 @@ data class TitaniumCDMDescription( * String denoting the vendor of the underlying Content Decryption Module (CDM) provided by * the host platform, e.g. “Google” (OPTIONAL) */ - val DRMProvider: String, + val DRMProvider: String?, /** * String denoting the CDM version (OPTIONAL) */ - val DRMVersion: String, + val DRMVersion: String?, /** * String denoting the DRM scheme that the CDM implements, e.g. “Widevine” (OPTIONAL) */ - val DRMType: String, + val DRMType: String?, ) val TitaniumWidevineCDMDescription = TitaniumCDMDescription( @@ -46,43 +46,43 @@ data class TitaniumDeviceInfo( /** * String that should be set to the value “PC” for browser-based applications (OPTIONAL). */ - val DeviceType: String, + val DeviceType: String?, /** * String denoting the operating system version of the host platform, e.g. “Linux” (OPTIONAL). */ - val OSType: String, + val OSType: String?, /** * String denoting the operating system version of the host platform, e.g. “8.1” (OPTIONAL). */ - val OSVersion: String, + val OSVersion: String?, /** * String denoting the vendor of the underlying Content Decryption Module (CDM) provided by * the host platform, e.g. “Google” (OPTIONAL). */ - val DRMProvider: String, + val DRMProvider: String?, /** * String denoting the CDM version (OPTIONAL). */ - val DRMVersion: String, + val DRMVersion: String?, /** * String denoting the DRM scheme that the CDM implements, e.g. “Widevine” (OPTIONAL). */ - val DRMType: String, + val DRMType: String?, /** * String denoting the OEM vendor of the host hardware platform (OPTIONAL). */ - val DeviceVendor: String, + val DeviceVendor: String?, /** * String denoting the OEM model identifier of the host hardware platform (OPTIONAL). */ - val DeviceModel: String + val DeviceModel: String? ) data class TitaniumLatensRegistration( From d7512974d5d6980a604ba46e6d8a5d94672f0212 Mon Sep 17 00:00:00 2001 From: Jeroen Veltmans Date: Tue, 13 Dec 2022 11:20:14 +0100 Subject: [PATCH 59/85] Improve extractContentId --- web/src/utils/FairplayUtils.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/src/utils/FairplayUtils.ts b/web/src/utils/FairplayUtils.ts index ca584f17..2cc4e9df 100644 --- a/web/src/utils/FairplayUtils.ts +++ b/web/src/utils/FairplayUtils.ts @@ -5,6 +5,13 @@ export function extractContentId(skdUrl: string): string { if (questionMarkIndex >= 0) { return skdUrl.substr(questionMarkIndex + 1); } else { + const strippedSkd = skdUrl.split('skd://').pop(); + if (strippedSkd) { + const base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; + if (base64regex.test(strippedSkd)) { + return strippedSkd; + } + } const chunks = skdUrl.split('/'); return chunks[chunks.length - 1]; } From 5ca8613a4b68ced8f4aa17eadc8020201737f4db Mon Sep 17 00:00:00 2001 From: ceyhun-o <74964451+ceyhun-o@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:53:58 +0200 Subject: [PATCH 60/85] Copy transmuxer and type definitions. --- web/rollup.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/rollup.config.js b/web/rollup.config.js index 7a0a2a75..18f59b46 100644 --- a/web/rollup.config.js +++ b/web/rollup.config.js @@ -18,7 +18,7 @@ export default { commonJs({ extensions: [".js", ".ts"] }), copy({ targets: [ - { src: './node_modules/theoplayer/*.(js|css|html)' , dest: './THEOplayer' } + { src: './node_modules/theoplayer/*.(js|css|html|ts|wasm)' , dest: './THEOplayer' } ] }), typescript() From 38c2a5a75598e3d6326028f010844d110680edaa Mon Sep 17 00:00:00 2001 From: ceyhun-o <74964451+ceyhun-o@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:07:01 +0100 Subject: [PATCH 61/85] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4a72822c..069ccbbd 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ THEOplayer Content Protection API. More information on the integration process can be found in the [how-to guide](https://docs.theoplayer.com/how-to-guides/04-drm/00-introduction.md). +DRM connector samples for the THEOplayer React Native SDK can be found [here](https://github.com/THEOplayer/react-native-theoplayer-drm). + ### Getting started - [Getting started on Web](web/README.md) - [Getting started on Android](android/README.md) From 9437c84eb3e48f9b35ce7fe697dcea1a06dc12e1 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 14:50:20 +0200 Subject: [PATCH 62/85] Remove all except web --- .gitignore | 55 --- README.md | 62 --- android/.gitignore | 15 - android/README.md | 288 ----------- android/app/.gitignore | 1 - android/app/build.gradle | 31 -- android/app/src/main/AndroidManifest.xml | 31 -- .../MainActivity.kt | 44 -- .../PlayerActivity.kt | 53 -- .../SourceManager.kt | 175 ------- .../contentprotectionintegration/TypeUtils.kt | 24 - .../device/DeviceInfo.kt | 42 -- .../device/DeviceType.kt | 5 - ...ureWidevineContentProtectionIntegration.kt | 29 -- ...vineContentProtectionIntegrationFactory.kt | 11 - ...yOsWidevineContentProtectionIntegration.kt | 20 - ...vineContentProtectionIntegrationFactory.kt | 11 - .../titanium/TitaniumBaseRegistration.kt | 69 --- .../TitaniumDeviceAuthorizationData.kt | 125 ----- ...iumWidevineContentProtectionIntegration.kt | 23 - ...neContentProtectionIntegrationFactory.java | 12 - ...oreWidevineContentProtectionIntegration.kt | 37 -- ...vineContentProtectionIntegrationFactory.kt | 11 - ...drmWidevineContentProtectionIntegration.kt | 61 --- ...vineContentProtectionIntegrationFactory.kt | 11 - .../main/res/drawable-hdpi/ic_theo_logo.png | Bin 4073 -> 0 bytes .../main/res/drawable-mdpi/ic_theo_logo.png | Bin 2731 -> 0 bytes .../main/res/drawable-xhdpi/ic_theo_logo.png | Bin 6067 -> 0 bytes .../main/res/drawable-xxhdpi/ic_theo_logo.png | Bin 8193 -> 0 bytes .../res/drawable-xxxhdpi/ic_theo_logo.png | Bin 10983 -> 0 bytes .../res/drawable/ic_launcher_foreground.xml | 30 -- .../src/main/res/drawable/splash_screen.xml | 10 - .../app/src/main/res/layout/activity_main.xml | 21 - .../src/main/res/layout/activity_player.xml | 28 -- android/app/src/main/res/layout/list_item.xml | 14 - .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 - .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 4068 -> 0 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 2101 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 4068 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2653 -> 0 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 1394 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 2653 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 5761 -> 0 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 2859 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 5761 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 8884 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 4312 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 8884 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 12447 -> 0 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 5893 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 12447 -> 0 bytes android/app/src/main/res/values/styles.xml | 23 - android/app/src/main/res/values/values.xml | 14 - .../main/res/xml/network_security_config.xml | 8 - android/build.gradle | 26 - android/gradle.properties | 19 - .../gradle/wrapper/gradle-wrapper.properties | 6 - android/gradlew | 172 ------- android/gradlew.bat | 84 ---- android/settings.gradle | 2 - .../project.pbxproj | 467 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../AppDelegate.swift | 50 -- .../AppIcon.appiconset/Contents.json | 98 ---- .../Assets.xcassets/Contents.json | 6 - .../Base.lproj/LaunchScreen.storyboard | 25 - .../Base.lproj/Main.storyboard | 24 - ios/ContentProtectionIntegration/Info.plist | 64 --- .../SceneDelegate.swift | 52 -- .../TypeUtils.swift | 24 - .../ViewController.swift | 46 -- .../ArrisTitaniumDrmIntegration.swift | 242 --------- .../integration/AzureDRMIntegration.swift | 81 --- .../integration/EzdrmDRMIntegration.swift | 57 --- .../integration/KeyOsDRMIntegration.swift | 80 --- .../integration/UplynkDRMIntegration.swift | 82 --- .../VerimatrixCoreDRMIntegration.swift | 82 --- .../integration/VuDRMIntegration.swift | 74 --- ios/Podfile | 11 - ios/README.md | 257 ---------- package-lock.json | 3 - resources/android_custom_drm_classes.svg | 3 - resources/custom_drm_integration_seq.svg | 3 - resources/ios_custom_drm_classes.svg | 3 - resources/web_custom_drm_classes.svg | 3 - 87 files changed, 3565 deletions(-) delete mode 100644 .gitignore delete mode 100644 README.md delete mode 100644 android/.gitignore delete mode 100644 android/README.md delete mode 100644 android/app/.gitignore delete mode 100644 android/app/build.gradle delete mode 100644 android/app/src/main/AndroidManifest.xml delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceInfo.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceType.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumBaseRegistration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegrationFactory.java delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegrationFactory.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.kt delete mode 100644 android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.kt delete mode 100644 android/app/src/main/res/drawable-hdpi/ic_theo_logo.png delete mode 100644 android/app/src/main/res/drawable-mdpi/ic_theo_logo.png delete mode 100644 android/app/src/main/res/drawable-xhdpi/ic_theo_logo.png delete mode 100644 android/app/src/main/res/drawable-xxhdpi/ic_theo_logo.png delete mode 100644 android/app/src/main/res/drawable-xxxhdpi/ic_theo_logo.png delete mode 100644 android/app/src/main/res/drawable/ic_launcher_foreground.xml delete mode 100644 android/app/src/main/res/drawable/splash_screen.xml delete mode 100644 android/app/src/main/res/layout/activity_main.xml delete mode 100644 android/app/src/main/res/layout/activity_player.xml delete mode 100644 android/app/src/main/res/layout/list_item.xml delete mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/values/styles.xml delete mode 100644 android/app/src/main/res/values/values.xml delete mode 100644 android/app/src/main/res/xml/network_security_config.xml delete mode 100644 android/build.gradle delete mode 100644 android/gradle.properties delete mode 100644 android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 android/gradlew delete mode 100644 android/gradlew.bat delete mode 100644 android/settings.gradle delete mode 100644 ios/ContentProtectionIntegration.xcodeproj/project.pbxproj delete mode 100644 ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 ios/ContentProtectionIntegration/AppDelegate.swift delete mode 100644 ios/ContentProtectionIntegration/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 ios/ContentProtectionIntegration/Assets.xcassets/Contents.json delete mode 100644 ios/ContentProtectionIntegration/Base.lproj/LaunchScreen.storyboard delete mode 100644 ios/ContentProtectionIntegration/Base.lproj/Main.storyboard delete mode 100644 ios/ContentProtectionIntegration/Info.plist delete mode 100644 ios/ContentProtectionIntegration/SceneDelegate.swift delete mode 100644 ios/ContentProtectionIntegration/TypeUtils.swift delete mode 100644 ios/ContentProtectionIntegration/ViewController.swift delete mode 100644 ios/ContentProtectionIntegration/integration/ArrisTitaniumDrmIntegration.swift delete mode 100644 ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift delete mode 100644 ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift delete mode 100644 ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift delete mode 100644 ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift delete mode 100644 ios/ContentProtectionIntegration/integration/VerimatrixCoreDRMIntegration.swift delete mode 100644 ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift delete mode 100644 ios/Podfile delete mode 100644 ios/README.md delete mode 100644 package-lock.json delete mode 100644 resources/android_custom_drm_classes.svg delete mode 100644 resources/custom_drm_integration_seq.svg delete mode 100644 resources/ios_custom_drm_classes.svg delete mode 100644 resources/web_custom_drm_classes.svg diff --git a/.gitignore b/.gitignore deleted file mode 100644 index eeb38795..00000000 --- a/.gitignore +++ /dev/null @@ -1,55 +0,0 @@ -# These are some examples of commonly ignored file patterns. -# You should customize this list as applicable to your project. -# Learn more about .gitignore: -# https://www.atlassian.com/git/tutorials/saving-changes/gitignore - -# Node artifact files -node_modules/ -dist/ - -# Compiled Java class files -*.class - -# Compiled Python bytecode -*.py[cod] - -# Log files -*.log - -# Package files -*.jar - -# Maven -target/ -dist/ - -# JetBrains IDE -.idea/ - -# Unit test reports -TEST*.xml - -# Generated by MacOS -.DS_Store - -# Generated by Windows -Thumbs.db - -# Applications -*.app -*.exe -*.war - -# Large media files -*.mp4 -*.tiff -*.avi -*.flv -*.mov -*.wmv - -# THEOplayer build and TypeScript definitions -THEOplayer/ -ios/THEOplayerSDK.framework -xcuserdata/ -android/app/libs/theoplayer.aar diff --git a/README.md b/README.md deleted file mode 100644 index 069ccbbd..00000000 --- a/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# THEOplayer DRM integrations - -### Table of contents - -1. [Introduction](#introduction) -2. [DRM flow](#drm-flow) -3. [DRM integration API](#drm-integration-api) -4. [Getting started](#getting-started) - -### Introduction - -A detailed explanation on why DRM (Digital Rights Management) is necessary, and how it works, can -be found in THEOplayer's [knowledge base](https://docs.theoplayer.com/knowledge-base/02-content-protection/00-introduction.md). -For the purpose of the integration examples in this repository we will first briefly explain some key -concepts being used in the process of requesting a decryption key, or the *DRM flow*. - -### DRM flow - -The examples in this repository are grouped per platform, but they share a common overall DRM flow. -Whenever the player encounters encrypted content, it will need a *decryption or license key* to decrypt the content -before it can be played. -This key is requested from a license server by means of a *license acquisition request*. -The actual decryption is done by the *CDM (Content Decryption Module)*, a hardware or software -component external to the player, which creates (part of) the request body (the challenge) to send to the -server, and takes the resulting key from the response. - -Optionally, the license request is preceded by a *certificate request*. The certificate is then used -to encrypt certain parts of the license request itself. - -So in the whole DRM process the player just mediates and passes through information between the license -server and the CDM. The details of this communication is very specific to the type of DRM -being used and the DRM vendor, however. Handling the way the license requests and response bodies are -formatted, or wrapped with additional information, is called the *DRM integration*. -Due the vast diversity of integrations a DRM Integration API and this sample repository were created. - -### DRM integration API - -THEOplayer supports Fairplay, PlayReady and Widevine by default. In many cases however, developers -are working with a multi-DRM vendor that requires a tailored integration approach. -THEOplayer already includes a large number of pre-integrated solutions through partnerships with multi-DRM vendors. -In addition, because there is no one-fits-all approach, an API is available that allows to build a custom -DRM integrations. It gives the possibility to alter the DRM process by hooking into key points of the DRM -flow, such as right before creating certificate and license request bodies, or right after -receiving the responses. - -The sequence diagram below depicts a simplified version the DRM flow and how a custom integration can intervene -at certain key points. - -![Custom DRM integration sequence diagram](./resources/custom_drm_integration_seq.svg) - -This repository contains a number of such DRM flows that are already pre-integrated in THEOplayer, -but rewritten as a custom DRM integration. They serve as examples for integrating with the -THEOplayer Content Protection API. - -More information on the integration process can be found in the [how-to guide](https://docs.theoplayer.com/how-to-guides/04-drm/00-introduction.md). - -DRM connector samples for the THEOplayer React Native SDK can be found [here](https://github.com/THEOplayer/react-native-theoplayer-drm). - -### Getting started -- [Getting started on Web](web/README.md) -- [Getting started on Android](android/README.md) -- [Getting started on iOS](ios/README.md) diff --git a/android/.gitignore b/android/.gitignore deleted file mode 100644 index 941bab58..00000000 --- a/android/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml -.DS_Store -/build -/captures -/app/libs -.externalNativeBuild -.cxx diff --git a/android/README.md b/android/README.md deleted file mode 100644 index b25fd3a4..00000000 --- a/android/README.md +++ /dev/null @@ -1,288 +0,0 @@ -## Getting started on Android - -### Table of contents - -1. [Overview](#overview) -2. [Creating a new integration](#creating-a-new-integration) -3. [Request and Response types](#request-and-response-types) -4. [Available examples](#available-examples) -5. [Testing an integration](#testing-an-integration) -6. [Conclusion](#conclusion) - -### Overview - -This document provides a step-by-step approach on how to create a custom DRM integration with the THEOplayer Android SDK. -It gives an overview of which classes are involved and how they participate in the DRM flow. - -The project's top-level [README](../README.md) elaborates on what it means to create a DRM integration, gives a brief -platform-independent overview of the flow, and clarifies the terminology being used throughout the document. Make sure -to familiarise yourself with it before starting your own implementation. - -The static class diagram below depicts classes that are part of the SDK in white, while coloured classes need to be -implemented when creating a custom integration. The `ContentProtectionIntegrationFactory` subclass is only used once -by THEOplayer to create an instance of a `ContentProtectedIntegration` subclass. The latter contains the actual hook methods -being referred to in the DRM integration [sequence diagram](../README.md#drm-integration-api). - -![Custom DRM integration class diagram](../resources/android_custom_drm_classes.svg) - -In the next section a custom integration is built by implementing both subclasses. - -### Creating a new integration - -First create a custom implementation of [ContentProtectionIntegration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/android/latest/com/theoplayer/android/api/contentprotection/ContentProtectionIntegration.html) -in the [com.theoplayer.contentprotectionintegration.integration](/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration) -package. -This object defines handler methods that allow altering license and certificate requests and responses as part of the -DRM flow. -All methods are optional. They can be omitted if the integration does not require additional action, in which case the -default implementation will be used. - -``` -package com.theoplayer.contentprotectionintegration.custom - -import com.theoplayer.android.api.contentprotection.CertificateRequestCallback -import com.theoplayer.android.api.contentprotection.CertificateResponseCallback -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback -import com.theoplayer.android.api.contentprotection.LicenseResponseCallback -import com.theoplayer.android.api.contentprotection.Request -import com.theoplayer.android.api.contentprotection.Response -import com.theoplayer.android.api.source.drm.DRMConfiguration - -class CustomContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : - ContentProtectionIntegration() { - - override fun onCertificateRequest(request: Request, callback: CertificateRequestCallback) { - callback.request(request) - } - - override fun onCertificateResponse(response: Response, callback: CertificateResponseCallback) { - callback.respond(response.body) - } - - override fun onLicenseRequest(Request request, LicenseRequestCallback callback) { - // /** - // * Optionally apply integration parameters, such as a token, which are passed when setting the source, or - // * add additional header fields. - // */ - // val token = contentProtectionConfiguration.integrationParameters["token"] - // request.headers["x-token"] = token - // request.headers["Content-Type"] = "text/plain" - - // /** - // * If required by the DRM provider, wrap or transform the request body. - // */ - // val kid = contentProtectionConfiguration.integrationParameters["keyId"] - // val jsonBody = JSONObject() - // try { - // jsonBody.put("token", token) - // jsonBody.put("drm_info", fromByteArrayToUint8JsonArray(request.body!!)) - // jsonBody.put("kid", kid) - // } catch (e: JSONException) { - // e.printStackTrace() - // } - // request.body = fromJsonToByteArray(jsonBody) - - callback.request(request) - } - - override fun onLicenseResponse(response: Response, callback: LicenseResponseCallback) { - callback.respond(response.body) - } -} -``` - -Optional parameters needed for certificate or license requests, such as tokens, can be added to a -[DRMConfiguration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/android/latest/com/theoplayer/android/api/source/drm/DRMConfiguration.html) -object that is passed when creating instances of the `CustomContentProtectionIntegration` class. -In the example, `CustomContentProtectionIntegration` adds a token from the configuration object as part of the headers -during a license request. - -Next, create a [ContentProtectionIntegrationFactory](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/android/latest/com/theoplayer/android/api/contentprotection/ContentProtectionIntegrationFactory.html) -for building CustomContentProtectionIntegration instances. -THEOplayer will use this factory in its DRM flow whenever it needs a ContentProtectionIntegration instance that -matches with the content protected source. How THEOplayer knows which factory to take will be determined in the -`registerContentProtectionIntegration` step next. - -``` -package com.theoplayer.contentprotectionintegration.custom - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory -import com.theoplayer.android.api.source.drm.DRMConfiguration - -class CustomContentProtectionIntegrationFactory: ContentProtectionIntegrationFactory { - - override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { - return CustomContentProtectionIntegration(configuration) - } -} -``` - -An instance of `CustomContentProtectionIntegrationFactory` needs to be registered with THEOplayer's global instance in the -[SourceManager](/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.java) -by specifying a unique `integrationId`, such as `"CUSTOM"` in this example. - -```java -String CUSTOM_ID = "CUSTOM"; -THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - CUSTOM_ID, - KeySystemId.WIDEVINE, - new CustomContentProtectionIntegrationFactory() -); -``` - -When the player now loads a source with a `customIntegrationId` that matches the `integrationId` -passed during registration, an instance of `CustomContentProtectionIntegration` will be created and used in the DRM flow. - -Also add the source description here, which provides the manifest and license URLs along with any integration parameters. - -```java -class SourceManager private constructor(context: Context) { - - private fun initSources(context: Context) { - // Custom content protect integration - val CUSTOM_ID = "CUSTOM" - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - CUSTOM_ID, - KeySystemId.WIDEVINE, - CustomWidevineContentProtectionIntegrationFactory() - ) - sources["Custom Widevine"] = buildWidevineSourceDescription( - CUSTOM_ID, - "", - "", - hashMapOf( - // optional integration parameters - // "token" to "", - // "keyId" to "" - ) - ) - - // add other registrations & sources here ... - } - - private fun buildWidevineSourceDescription( - integrationId: String, - manifestUrl: String, - licenseUrl: String, - integrationParams: HashMap - ): SourceDescription { - return SourceDescription.Builder( - TypedSource.Builder(manifestUrl) - .drm(DRMConfiguration.Builder() - .customIntegrationId(integrationId) - .integrationParameters(integrationParams) - .widevine(KeySystemConfiguration.Builder(licenseUrl).build()) - .build()) - .build() - ).build() - } -} -``` - -Finally, build and run the app on an Android device or Android emulator. - -### Request and Response types - -Manipulating certificate and license requests and responses requires special care. Next to adding header -fields or changing the target url, the body of the `Request` most often needs to be transformed or wrapped -before passing it along. - -```java -public class Request { - @NonNull - public String getUrl(); - public void setUrl(@NonNull String url); - - @NonNull - public RequestMethod getMethod(); - public void setMethod(@NonNull RequestMethod method); - - @NonNull - public Map getHeaders(); - public void setHeaders(@NonNull Map headers); - - @Nullable - public byte[] getBody(); - public void setBody(@Nullable byte[] body); -} -``` - -A `Request` object expects the body to be an array of `byte`. In case of a license request it originally contains the -challenge generated by the CDM. -A common way of passing extra data to the server is by wrapping the raw request body -in a JSON object with some additional properties, which is then transformed back into the required type `byte[]`. The following -example is taken from the [VuDRM integration sample](app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.java): - -``` -val jsonBody = JSONObject() -try { - jsonBody.put("token", token) - jsonBody.put("drm_info", fromByteArrayToUint8JsonArray(request.body!!)) - jsonBody.put("kid", kid) -} catch (e: JSONException) { - e.printStackTrace() -} -request.body = fromJsonToByteArray(jsonBody) -``` - -where the `fromByteArrayToUint8JsonArray` helper method creates a JSON array from a `byte[]` object. - -Similarly, the `Response` object returned from the server contains among others the response headers and the response -body. The latter is again an array of `byte`, containing the certificate or license that will be passed to the CDM. - -```java -public interface Response { - @NonNull - Request getRequest(); - - @NonNull - String getUrl(); - - int getStatus(); - - @NonNull - String getStatusText(); - - @NonNull - Map getHeaders(); - - @Nullable - byte[] getBody(); -} -``` - -Depending on the DRM integration, the response body either already is a raw certificate or license that can be passed along as-is, -or needs to be transformed or unwrapped first in a way similar to the request body. - -### Available examples - -The repository already contains a few integration examples that could be used as a starting point. - -- Vualto VuDRM -- Microsoft Azure DRM -- KeyOS - -The repository also lists some examples with placeholder data (in `SourceManager`) that can use the default Widevine integration: - -- Verimatrix Core -- Titanium DRM, either using authToken or device info - -### Testing an integration - -Make sure to apply the following steps before testing your custom integration. If a problem persists, please -reach out to THEOplayer [customer support](https://www.theoplayer.com/contact). - -- Depending on the features included in your THEOplayer build, include the necessary dependencies in `/android/app/build.gradle`. -- Open the `/android` folder in [Android Studio](https://developer.android.com/studio) and build the project. -- Ensure that a valid license key is entered in the `theoplayer_license` entry of `values.xml`. More information is available at https://github.com/THEOplayer/theoplayer-sdk-android. -- Make sure to fill in the necessary fields in `SourceManager` for the content integration that will be tested, such as the manifest url and any integration parameters. -- Attach either a physical Android device or start an Android emulator, and run the project. - -### Conclusion - -This document showed how to create a custom DRM integration for Android using THEOplayer's Content Integration API, -and register it with THEOplayer. The Android integration API can slightly differ on other platforms, so it is best -to check the platform's specific document. - diff --git a/android/app/.gitignore b/android/app/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/android/app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle deleted file mode 100644 index 2c02cf88..00000000 --- a/android/app/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' - -android { - compileSdkVersion 33 - buildToolsVersion "30.0.2" - - defaultConfig { - applicationId "com.theoplayer.contentprotectionintegration" - minSdkVersion 24 - targetSdkVersion 33 - multiDexEnabled true - versionCode 1 - versionName "1.0" - } - - buildFeatures { - viewBinding = true - } -} - -dependencies { - implementation 'androidx.appcompat:appcompat:1.5.1' - implementation 'com.google.android.material:material:1.6.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'com.google.code.gson:gson:2.8.9' - implementation 'com.theoplayer.theoplayer-sdk-android:unified:+' - implementation 'com.android.support:multidex:1.0.3' - implementation 'androidx.core:core-ktx:1.9.0' -} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index dba4f363..00000000 --- a/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt deleted file mode 100644 index 12604405..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/MainActivity.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.theoplayer.contentprotectionintegration - -import android.content.Intent -import android.os.Bundle -import android.view.View -import android.widget.AdapterView -import android.widget.AdapterView.OnItemClickListener -import android.widget.ArrayAdapter -import androidx.appcompat.app.AppCompatActivity -import com.theoplayer.contentprotectionintegration.databinding.ActivityMainBinding -import com.theoplayer.contentprotectionintegration.device.DeviceInfo - -const val EXTRA_SOURCE_NAME = "sourceName" - -class MainActivity : AppCompatActivity() { - private lateinit var viewBinding: ActivityMainBinding - - override fun onCreate(savedInstanceState: Bundle?) { - setTheme(R.style.TheoTheme_Base) - super.onCreate(savedInstanceState) - - // Provide context to DeviceTypeResolver - DeviceInfo.init(this) - - // Inflating view and obtaining an instance of the binding class. - viewBinding = ActivityMainBinding.inflate(layoutInflater) - val view = viewBinding.root - setContentView(view) - - populateSources() - } - - private fun populateSources() { - val listView = viewBinding.sourceList - val adapter = ArrayAdapter(this, R.layout.list_item, R.id.list_item_name, SourceManager.getInstance(this).sourcesNames) - listView.adapter = adapter - listView.onItemClickListener = - OnItemClickListener { _: AdapterView<*>?, _: View?, position: Int, _: Long -> - val intent = Intent(this, PlayerActivity::class.java) - intent.putExtra(EXTRA_SOURCE_NAME, adapter.getItem(position)) - startActivity(intent) - } - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.kt deleted file mode 100644 index 0fbac665..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/PlayerActivity.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.theoplayer.contentprotectionintegration - -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import com.theoplayer.android.api.THEOplayerView -import com.theoplayer.android.api.event.player.PlayerEventTypes -import com.theoplayer.contentprotectionintegration.databinding.ActivityPlayerBinding - -class PlayerActivity : AppCompatActivity() { - private lateinit var playerView: THEOplayerView - private lateinit var viewBinding: ActivityPlayerBinding - - override fun onCreate(savedInstanceState: Bundle?) { - setTheme(R.style.TheoTheme_Base) - super.onCreate(savedInstanceState) - - viewBinding = ActivityPlayerBinding.inflate(layoutInflater) - val view = viewBinding.root - setContentView(view) - - playerView = viewBinding.theoplayer - playerView.player.addEventListener(PlayerEventTypes.ERROR) { error -> - viewBinding.message.text = error.errorObject.message - } - - // Get source description from the extras bundle - val extras = intent.extras - if (extras != null) { - val sourceName = extras.getString(EXTRA_SOURCE_NAME) - val sourceDescription = SourceManager.getInstance(this).getSource(sourceName) - - playerView.player.apply { - source = sourceDescription - play() - } - } - } - - override fun onPause() { - super.onPause() - playerView.onPause() - } - - override fun onResume() { - super.onResume() - playerView.onResume() - } - - override fun onDestroy() { - super.onDestroy() - playerView.onDestroy() - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt deleted file mode 100644 index ce37d420..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/SourceManager.kt +++ /dev/null @@ -1,175 +0,0 @@ -package com.theoplayer.contentprotectionintegration - -import android.content.Context -import com.theoplayer.android.api.source.SourceDescription -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.android.api.THEOplayerGlobal -import com.theoplayer.android.api.contentprotection.KeySystemId -import com.theoplayer.android.api.source.SourceType -import com.theoplayer.android.api.source.TypedSource -import com.theoplayer.android.api.source.drm.KeySystemConfiguration -import com.theoplayer.contentprotectionintegration.integration.vudrm.VudrmWidevineContentProtectionIntegrationFactory -import com.theoplayer.contentprotectionintegration.integration.azuredrm.AzureWidevineContentProtectionIntegrationFactory -import com.theoplayer.contentprotectionintegration.integration.keyos.KeyOsWidevineContentProtectionIntegrationFactory -import com.theoplayer.contentprotectionintegration.integration.titanium.TitaniumWidevineContentProtectionIntegrationFactory -import com.theoplayer.contentprotectionintegration.integration.verimatrixcoredrm.VerimatrixCoreWidevineContentProtectionIntegrationFactory -import java.util.HashMap - -private const val VUDRM_ID = "VUDRM" -private const val AZURE_ID = "AZURE" -private const val KEYOS_ID = "buydrm-keyos" -private const val VERIMATRIX_CORE_ID = "custom_verimatrix_core" -private const val TITANIUM_AUTH_ID = "custom_titanium_auth" -private const val TITANIUM_DEVICE_ID = "custom_titanium_device" - -@Suppress("SameParameterValue") -class SourceManager private constructor(context: Context) { - companion object { - private var instance: SourceManager? = null - fun getInstance(context: Context): SourceManager { - if (instance == null) { - instance = SourceManager(context) - } - return instance!! - } - } - - private val sources = HashMap() - - init { - initSources(context) - } - - fun getSource(name: String?): SourceDescription? { - return sources[name] - } - - val sourcesNames: Array - get() = sources.keys.toTypedArray() - - /** - * Convenience method to create a Widevine DRM configuration instance. - */ - private fun buildWidevineDrmConfiguration( - integrationId: String, - licenseUrl: String, - integrationParams: HashMap - ): DRMConfiguration { - return DRMConfiguration.Builder() - .customIntegrationId(integrationId) - .integrationParameters(integrationParams) - .widevine(KeySystemConfiguration.Builder(licenseUrl).build()) - .build() - } - - private fun initSources(context: Context) { - // Vualto VUDRM Widevine content protect integration - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - VUDRM_ID, - KeySystemId.WIDEVINE, - VudrmWidevineContentProtectionIntegrationFactory() - ) - sources["Vualto VUDRM Widevine"] = SourceDescription.Builder( - TypedSource.Builder("") - .drm(buildWidevineDrmConfiguration( - VUDRM_ID, - "", - hashMapOf( - "token" to "", - "keyId" to "" - ) - )).build() - ).build() - - // Microsoft Azure Widevine content protect integration - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - AZURE_ID, - KeySystemId.WIDEVINE, - AzureWidevineContentProtectionIntegrationFactory() - ) - sources["Microsoft Azure Widevine"] = SourceDescription.Builder( - TypedSource.Builder("") - .drm(buildWidevineDrmConfiguration( - AZURE_ID, - "", - hashMapOf( - "token" to "", - ) - )).build() - ).build() - - // BuyDRM KeyOS Widevine content protect integration - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - KEYOS_ID, - KeySystemId.WIDEVINE, - KeyOsWidevineContentProtectionIntegrationFactory() - ) - sources["BuyDRM KeyOs Widevine"] = SourceDescription.Builder( - TypedSource.Builder("https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd") - .drm(buildWidevineDrmConfiguration( - KEYOS_ID, - "https://wv-keyos.licensekeyserver.com", - hashMapOf( - "x-keyos-authorization" to "PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg==", - ) - )).build() - ).build() - - // Verimatrix Multi-DRM Core - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - VERIMATRIX_CORE_ID, - KeySystemId.WIDEVINE, - VerimatrixCoreWidevineContentProtectionIntegrationFactory() - ) - sources["Verimatrix Multi-DRM Core"] = SourceDescription.Builder( - TypedSource.Builder("") - .type(SourceType.DASH) - .drm(buildWidevineDrmConfiguration( - VERIMATRIX_CORE_ID, - "https://multidrm.vsaas.verimatrixcloud.net/widevine", - hashMapOf( - "drmToken" to "", - ) - )).build() - ).build() - - // Titanium DRM using an authToken - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - TITANIUM_AUTH_ID, - KeySystemId.WIDEVINE, - TitaniumWidevineContentProtectionIntegrationFactory() - ) - sources["Titanium Widevine (authToken)"] = SourceDescription.Builder( - TypedSource.Builder("") - .drm(buildWidevineDrmConfiguration( - TITANIUM_AUTH_ID, - "", - hashMapOf( - "authToken" to "" - ) - )).build() - ).build() - - // Titanium DRM using deviceInfo - THEOplayerGlobal.getSharedInstance(context).registerContentProtectionIntegration( - TITANIUM_DEVICE_ID, - KeySystemId.WIDEVINE, - TitaniumWidevineContentProtectionIntegrationFactory() - ) - sources["Titanium Widevine (device)"] = SourceDescription.Builder( - TypedSource.Builder("") - .drm(buildWidevineDrmConfiguration( - TITANIUM_DEVICE_ID, - "", - hashMapOf( - "accountName" to "", - "customerName" to "", - "friendlyName" to "", - "portalId" to "", - ) - )).build() - ).build() - - // add other registrations & sources here ... - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.kt deleted file mode 100644 index 2498a1be..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/TypeUtils.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.theoplayer.contentprotectionintegration - -import org.json.JSONArray -import org.json.JSONObject - -object TypeUtils { - /** - * Convert an array of bytes to a JSONArray object. - */ - fun fromByteArrayToUint8JsonArray(bytes: ByteArray): JSONArray { - val jsonArray = JSONArray() - for (aByte in bytes) { - jsonArray.put((aByte.toInt() and 0xff).toByte()) - } - return jsonArray - } - - /** - * Convert a JSON object to an array of bytes. - */ - fun fromJsonToByteArray(jsonObject: JSONObject): ByteArray { - return jsonObject.toString().toByteArray() - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceInfo.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceInfo.kt deleted file mode 100644 index 212dc379..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceInfo.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.theoplayer.contentprotectionintegration.device - -import android.annotation.SuppressLint -import android.app.UiModeManager -import android.content.Context -import android.content.res.Configuration -import android.os.Build - -@SuppressLint("StaticFieldLeak") -object DeviceInfo { - fun init(context: Context) { - deviceType = determineDeviceType(context) - } - - lateinit var deviceType: DeviceType - - val deviceTypeAsString: String - get() = deviceType.value - - val model: String - get() = Build.MODEL - - val brand: String - get() = Build.BRAND - - val osVersion: Int - get() = Build.VERSION.SDK_INT - - val osVersionAsString: String - get() = osVersion.toString() - - private fun determineDeviceType(context: Context): DeviceType { - val uiManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager - if (uiManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) { - return DeviceType.TV - } - return if ((context.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) - DeviceType.TABLET - else - DeviceType.PHONE - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceType.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceType.kt deleted file mode 100644 index 600ec76c..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/device/DeviceType.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.theoplayer.contentprotectionintegration.device - -enum class DeviceType(val value: String) { - PHONE("phone"), TABLET("tablet"), TV("tv"); -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.kt deleted file mode 100644 index b28f26c4..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegration.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.azuredrm - -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback -import com.theoplayer.android.api.contentprotection.Request -import java.lang.NullPointerException - -class AzureWidevineContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : - ContentProtectionIntegration() { - override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { - val token = contentProtectionConfiguration.integrationParameters["token"] - if (token == null) { - callback.error(NullPointerException("The Azure drm token can not be null")) - return - } - var licenseUrl: String? = null - if (contentProtectionConfiguration.widevine != null) { - licenseUrl = contentProtectionConfiguration.widevine!!.licenseAcquisitionURL - } - if (licenseUrl == null) { - callback.error(NullPointerException("The Azure licenseAcquisitionURL can not be null")) - return - } - request.url = licenseUrl - request.headers["Authorization"] = "Bearer $token" - callback.request(request) - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.kt deleted file mode 100644 index 15d77760..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/azuredrm/AzureWidevineContentProtectionIntegrationFactory.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.azuredrm - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration - -class AzureWidevineContentProtectionIntegrationFactory : ContentProtectionIntegrationFactory { - override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { - return AzureWidevineContentProtectionIntegration(configuration) - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.kt deleted file mode 100644 index cd09387e..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegration.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.keyos - -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback -import com.theoplayer.android.api.contentprotection.Request -import java.lang.NullPointerException - -class KeyOsWidevineContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : - ContentProtectionIntegration() { - override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { - if (contentProtectionConfiguration.widevine == null) { - throw NullPointerException("The license acquisition URL can not be null") - } - request.url = contentProtectionConfiguration.widevine!!.licenseAcquisitionURL - request.headers["x-keyos-authorization"] = - contentProtectionConfiguration.integrationParameters["x-keyos-authorization"].toString() - callback.request(request) - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.kt deleted file mode 100644 index 6a12bfde..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/keyos/KeyOsWidevineContentProtectionIntegrationFactory.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.keyos - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory -import com.theoplayer.android.api.source.drm.DRMConfiguration - -class KeyOsWidevineContentProtectionIntegrationFactory : ContentProtectionIntegrationFactory { - override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { - return KeyOsWidevineContentProtectionIntegration(configuration) - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumBaseRegistration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumBaseRegistration.kt deleted file mode 100644 index f0b16fcd..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumBaseRegistration.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.titanium - -import android.util.Base64 -import com.google.gson.Gson -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.contentprotectionintegration.BuildConfig -import com.theoplayer.contentprotectionintegration.device.DeviceInfo -import java.util.HashMap - -object TitaniumBaseRegistration { - - private const val HEADER_CONTENT_TYPE = "Content-Type" - private const val HEADER_AUTHORIZATION = "Authorization" - private const val HEADER_TITANIUM_DRM_CDATA = "X-TITANIUM-DRM-CDATA" - - private const val PROP_AUTH_TOKEN = "authToken" - private const val PROP_CUSTOMER_NAME = "customerName" - private const val PROP_ACCOUNT_NAME = "accountName" - private const val PROP_PORTAL_ID = "portalId" - private const val PROP_FRIENDLY_NAME = "friendlyName" - - fun createTitaniumHeaders(configuration: DRMConfiguration, cdmType: TitaniumCDMDescription): HashMap { - val headers = HashMap() - headers[HEADER_CONTENT_TYPE] = "application/octet-stream" - if (isTokenBasedTitaniumDRMConfiguration(configuration)) { - headers[HEADER_AUTHORIZATION] = createTitaniumAuthHeader(configuration) - } else { - headers[HEADER_TITANIUM_DRM_CDATA] = createTitaniumDeviceHeader(configuration, cdmType) - } - return headers - } - - private fun isTokenBasedTitaniumDRMConfiguration(configuration: DRMConfiguration): Boolean { - return configuration.integrationParameters.containsKey(PROP_AUTH_TOKEN) - } - - private fun createTitaniumAuthHeader(configuration: DRMConfiguration) : String { - return "Bearer ${configuration.integrationParameters[PROP_AUTH_TOKEN]}" - } - - private fun getTitaniumDeviceAuthorizationData(integrationParameters: Map, cdmType: TitaniumCDMDescription) : TitaniumDeviceAuthorizationData { - return TitaniumDeviceAuthorizationData( - TitaniumLatensRegistration( - CustomerName = integrationParameters[PROP_CUSTOMER_NAME] as String, - AccountName = integrationParameters[PROP_ACCOUNT_NAME] as String, - PortalId = integrationParameters[PROP_PORTAL_ID] as String, - FriendlyName = integrationParameters[PROP_FRIENDLY_NAME] as String, - AppVersion = BuildConfig.VERSION_NAME, - DeviceInfo = TitaniumDeviceInfo( - FormatVersion = "1", - DeviceType = DeviceInfo.deviceTypeAsString, - OSType = "Android", - OSVersion = DeviceInfo.osVersionAsString, - DRMProvider = cdmType.DRMProvider, - DRMVersion = cdmType.DRMVersion, - DRMType = cdmType.DRMType, - DeviceVendor = DeviceInfo.brand, - DeviceModel = DeviceInfo.model - ) - ) - ) - } - - private fun createTitaniumDeviceHeader(configuration: DRMConfiguration, cdmType: TitaniumCDMDescription): String { - val deviceAuthorizationData = getTitaniumDeviceAuthorizationData(configuration.integrationParameters, cdmType) - val jsonData = Gson().toJson(deviceAuthorizationData) - return Base64.encodeToString(jsonData.toByteArray(), Base64.NO_WRAP) - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt deleted file mode 100644 index a1c28c1d..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumDeviceAuthorizationData.kt +++ /dev/null @@ -1,125 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.titanium - -data class TitaniumCDMDescription( - /** - * String denoting the vendor of the underlying Content Decryption Module (CDM) provided by - * the host platform, e.g. “Google” (OPTIONAL) - */ - val DRMProvider: String?, - - /** - * String denoting the CDM version (OPTIONAL) - */ - val DRMVersion: String?, - - /** - * String denoting the DRM scheme that the CDM implements, e.g. “Widevine” (OPTIONAL) - */ - val DRMType: String?, -) - -val TitaniumWidevineCDMDescription = TitaniumCDMDescription( -"Google", -"1.4.8.86", -"Widevine" -) - -val PlayreadyV2CDMDescription = TitaniumCDMDescription( - "Microsoft", - "2.9", - "Playready" -) - -val PlayreadyV3CDMDescription = TitaniumCDMDescription( - "Microsoft", - "3", - "Playready" -) - -data class TitaniumDeviceInfo( - /** - * String that should be set to the value “1” for applications compliant with the latest - * document version. - */ - val FormatVersion: String, - - /** - * String that should be set to the value “PC” for browser-based applications (OPTIONAL). - */ - val DeviceType: String?, - - /** - * String denoting the operating system version of the host platform, e.g. “Linux” (OPTIONAL). - */ - val OSType: String?, - - /** - * String denoting the operating system version of the host platform, e.g. “8.1” (OPTIONAL). - */ - val OSVersion: String?, - - /** - * String denoting the vendor of the underlying Content Decryption Module (CDM) provided by - * the host platform, e.g. “Google” (OPTIONAL). - */ - val DRMProvider: String?, - - /** - * String denoting the CDM version (OPTIONAL). - */ - val DRMVersion: String?, - - /** - * String denoting the DRM scheme that the CDM implements, e.g. “Widevine” (OPTIONAL). - */ - val DRMType: String?, - - /** - * String denoting the OEM vendor of the host hardware platform (OPTIONAL). - */ - val DeviceVendor: String?, - - /** - * String denoting the OEM model identifier of the host hardware platform (OPTIONAL). - */ - val DeviceModel: String? -) - -data class TitaniumLatensRegistration( - /** - * String denoting the Customer ID attribute as defined in the MultiTrust subscriber management - * system. - */ - val CustomerName: String, - - /** - * String denoting the Account ID attribute as defined in the MultiTrust subscriber management - * system. - */ - val AccountName: String, - - /** - * String denoting a unique identifier derived for this device and provisioned in the - * MultiTrust subscriber management system. - */ - val PortalId: String, - - /** - * String denoting an application defined ‘friendly name’ associated with this device. - */ - val FriendlyName: String, - - /** - * String denoting the versioning information for the application (OPTIONAL). - */ - val AppVersion: String?, - - /** - * Object describing the host platform. - */ - val DeviceInfo: TitaniumDeviceInfo -) - -data class TitaniumDeviceAuthorizationData( - val LatensRegistration: TitaniumLatensRegistration -) diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegration.kt deleted file mode 100644 index 04381348..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegration.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.titanium - -import com.theoplayer.android.api.contentprotection.* -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.contentprotectionintegration.integration.titanium.TitaniumBaseRegistration.createTitaniumHeaders - -class TitaniumWidevineContentProtectionIntegration(private val configuration: DRMConfiguration): - ContentProtectionIntegration() { - - override fun onCertificateRequest(request: Request, callback: CertificateRequestCallback) { - request.apply { - headers.putAll(createTitaniumHeaders(configuration, TitaniumWidevineCDMDescription)) - callback.request(this) - } - } - - override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { - request.apply { - headers.putAll(createTitaniumHeaders(configuration, TitaniumWidevineCDMDescription)) - callback.request(this) - } - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegrationFactory.java b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegrationFactory.java deleted file mode 100644 index 73d84419..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/titanium/TitaniumWidevineContentProtectionIntegrationFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.titanium; - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration; -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory; -import com.theoplayer.android.api.source.drm.DRMConfiguration; - -public class TitaniumWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - @Override - public ContentProtectionIntegration build(DRMConfiguration configuration) { - return new TitaniumWidevineContentProtectionIntegration(configuration); - } -} diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegration.kt deleted file mode 100644 index 51d49e8d..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegration.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.verimatrixcoredrm - -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration -import com.theoplayer.android.api.contentprotection.CertificateRequestCallback -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback -import com.theoplayer.android.api.contentprotection.Request -import java.lang.NullPointerException - -private const val HEADER_AUTH = "Authorization" -private const val PARAM_TOKEN = "drmToken" - -class VerimatrixCoreWidevineContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : - ContentProtectionIntegration() { - - init { - if (contentProtectionConfiguration.integrationParameters["drmToken"] == null) { - throw(NullPointerException("The Verimatrix drmToken can not be null")) - } - } - - private fun applyHeaders(request: Request): Request { - if (request.body == null) { - throw NullPointerException("The request body can not be null") - } - request.headers[HEADER_AUTH] = contentProtectionConfiguration.integrationParameters[PARAM_TOKEN] as String - return request - } - - override fun onCertificateRequest(request: Request, callback: CertificateRequestCallback) { - callback.request(applyHeaders(request)) - } - - override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { - callback.request(applyHeaders(request)) - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegrationFactory.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegrationFactory.kt deleted file mode 100644 index 421bf764..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/verimatrixcoredrm/VerimatrixCoreWidevineContentProtectionIntegrationFactory.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.verimatrixcoredrm - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration - -class VerimatrixCoreWidevineContentProtectionIntegrationFactory : ContentProtectionIntegrationFactory { - override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { - return VerimatrixCoreWidevineContentProtectionIntegration(configuration) - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.kt deleted file mode 100644 index e2a0af95..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegration.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.vudrm - -import com.theoplayer.contentprotectionintegration.TypeUtils.fromByteArrayToUint8JsonArray -import com.theoplayer.contentprotectionintegration.TypeUtils.fromJsonToByteArray -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration -import org.json.JSONObject -import org.json.JSONException -import com.theoplayer.android.api.contentprotection.CertificateRequestCallback -import com.theoplayer.android.api.contentprotection.LicenseRequestCallback -import com.theoplayer.android.api.contentprotection.Request -import java.lang.NullPointerException - -class VudrmWidevineContentProtectionIntegration(private val contentProtectionConfiguration: DRMConfiguration) : - ContentProtectionIntegration() { - - companion object { - const val DEFAULT_LICENSE_URL = "https://widevine-proxy.drm.technology/proxy" - } - - private fun wrapRequest(request: Request): Request { - if (request.body == null) { - throw NullPointerException("The request body can not be null") - } - val token = contentProtectionConfiguration.integrationParameters["token"] - ?: throw NullPointerException("The Widevine vuDRM token can not be null") - var licenseUrl = DEFAULT_LICENSE_URL - if (contentProtectionConfiguration.widevine != null) { - licenseUrl = contentProtectionConfiguration.widevine!!.licenseAcquisitionURL - } - request.url = licenseUrl - request.headers["Content-Type"] = "text/plain" - val kid = contentProtectionConfiguration.integrationParameters["keyId"] - val jsonBody = JSONObject() - try { - jsonBody.put("token", token) - jsonBody.put("drm_info", fromByteArrayToUint8JsonArray(request.body!!)) - jsonBody.put("kid", kid) - } catch (e: JSONException) { - e.printStackTrace() - } - request.body = fromJsonToByteArray(jsonBody) - return request - } - - override fun onCertificateRequest(request: Request, callback: CertificateRequestCallback) { - try { - callback.request(wrapRequest(request)) - } catch (error: Throwable) { - callback.error(error) - } - } - - override fun onLicenseRequest(request: Request, callback: LicenseRequestCallback) { - try { - callback.request(wrapRequest(request)) - } catch (error: Throwable) { - callback.error(error) - } - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.kt b/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.kt deleted file mode 100644 index 4baace10..00000000 --- a/android/app/src/main/java/com/theoplayer/contentprotectionintegration/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.theoplayer.contentprotectionintegration.integration.vudrm - -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegrationFactory -import com.theoplayer.android.api.source.drm.DRMConfiguration -import com.theoplayer.android.api.contentprotection.ContentProtectionIntegration - -class VudrmWidevineContentProtectionIntegrationFactory : ContentProtectionIntegrationFactory { - override fun build(configuration: DRMConfiguration): ContentProtectionIntegration { - return VudrmWidevineContentProtectionIntegration(configuration) - } -} \ No newline at end of file diff --git a/android/app/src/main/res/drawable-hdpi/ic_theo_logo.png b/android/app/src/main/res/drawable-hdpi/ic_theo_logo.png deleted file mode 100644 index 23546968f7f930ae0d72e50f046fdb7591f3d867..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4073 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 diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_theo_logo.png b/android/app/src/main/res/drawable-xxxhdpi/ic_theo_logo.png deleted file mode 100644 index ed1b1745bbadb9021f77b5158107a594ec2a3e33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10983 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 diff --git a/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 359e690c..00000000 --- a/android/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - diff --git a/android/app/src/main/res/drawable/splash_screen.xml b/android/app/src/main/res/drawable/splash_screen.xml deleted file mode 100644 index 06175b14..00000000 --- a/android/app/src/main/res/drawable/splash_screen.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index b3c2e9d1..00000000 --- a/android/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - diff --git a/android/app/src/main/res/layout/activity_player.xml b/android/app/src/main/res/layout/activity_player.xml deleted file mode 100644 index c7b19b6e..00000000 --- a/android/app/src/main/res/layout/activity_player.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/layout/list_item.xml b/android/app/src/main/res/layout/list_item.xml deleted file mode 100644 index 28723653..00000000 --- a/android/app/src/main/res/layout/list_item.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 5aa3d53c..00000000 --- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 5aa3d53c..00000000 --- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 2ed0ffec66e189cfbaa60c0a6d5ebb59e293f590..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4068 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 Rk}~;Dz*(>4GA diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index 2ed0ffec66e189cfbaa60c0a6d5ebb59e293f590..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4068 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 LNkvXXu0mjf&~N~Q diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 258b1315158460139d9b5945ddb53ca2bdcf0828..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1394 zcmaJ>`#aMM7+-3XtQzIAIuy>xUO~>}w~?iQ);lmZq_KY8tt2gcKRg zEghGc%T_MqG>I{JFdT#!atTNOK=1Rs@8@|x&*$@e-k)BIo2vsv7A6YoNv%tsj`w$$0VDJQyQHzW0*? z>Nl>C15+UM#TDW5<4sqq%@$@AC8A4ujBJJTRYt2Q*ga-5XPp$8Ql$I-_=?M2q+8dOxP%ARvyK0I%Hf{FQ@mhD5c%GU8MyfX!n;PuA4A148iR|EV>;#@!dRuOG7 ztUO3tLeGP^Y@UXzC3T0Ano9!o`wYMrgVh-)%T5V->z};$Mo+@G=pkJ3f!=N9I@^Pf zMx!n+TG9`MKRuKJhfUnR-Ewk9tIRTk$7PkmNVMy?uxQ6(OuM1)@C!BMc(ugh*$J1e z;eG^!44x4BCM8B?EgMq-wkmC{rqyJspNh}?2VgLXnF{j$*)4k5*xV?CjabtN!<85r za+dO>`FZUYz2v~mHzSUP>hsX11OQIHPLDhar2h@$tr!r|qq5FnigITVOmh_=dyT^~awx2w`Yo7zR#9m7ToSB9rSH){ea=kGv<*SvzHEhLncLo7Qo>qxqAC?=h zy9{GkQiTvh=N{JaIJ}nv(b@4y06sGpz~aU|60x3%?y(;HCRLT^9~RY=U)DQ0Yx$xR zvB80#kpj(dN=F&5@(WW?frI)}Ub>qVV5|Zk)Jc)E&=y7y4JF2=ojJ%$#xsf)SC^2frn^u}N^jGMw4Q9VV}Uy^rdxM2*) zY|mHfA-?K2lgbwfL^kb2i;)E4RRS(et81I{Ee$2ZCoZI)&8ThT<8O8G*L76MKGo6! z!TJqo(%J8o>Eh&qu;MG4+T9_HV*rOa^p*PbwC*2ythext<&KMc-!~HO79l%^lerYTUDM&L9DBHyvom6#YIZfh@+Nc5LRts*2G|rcE5y z5-h^Dx)Jxh3$4LrfLl8V18&pp>nxig*+oSAP`u1fMy@0{ttnclF=)zR-D+KXF;e1& z0lYjvm}~=mT-4A7=+dzIAdU=-k{6$eM`VXRlp`#~*|P<6L#Uwy=+c()ze;km@Ba^sXPL(U diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index 44a12f8cb928201dc59de187af8624a497e68bd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2653 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 LNkvXXu0mjf&~N~Q diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 394e36fe105234bf7fbb30c4dfd727800565dba7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5761 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 diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 86d027dd92434ee42cebfd8ef45b8cd0c3aafb31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2859 zcmb_ei#HSOA8)f&`J4=7#1kVN9bO-Tr$$uWjSQz{di>icvjd{t_-r^BxHJ%Y2_8 z_P$O>b7^K>J$KO}^iafN7KuC&F_R@Dcit-KSrSXumdHOdqh_k=eg4{z@-HstSWq!* zG4$tUZt;9P--9WKB>=;5MSZ+#WgTvo@e7wnA!;2~n#w-93-}TBT*2Fz_3FjkXcf9g zVB^~a4mW{RZ{9GhgkluI30+>=fNW+gV-;0ykvW9CE+FXIidk7*b{E&%rtM)qso8 zG}5y^fB%bY+Zgc83V!2gtX~Yx8RJulF4mrVDhoT7C{3u<`*lrqHD{+O37`5NA4aN9 zZ=?8re6~HHP=PB@k}#{KKZ*gNLspiI2ih?VxSKjc=)i8C0{cqY50Lf&$+OCP&U<0b zR1S%B)k^(n0ngh{DRN2wcISM)dG}^jjHn;`AXoQX zE6g`Do~Fc%*9I%d_MT~@hJk+&gEI{=^5Njs3{CQ zFdya@2`q2_z!R7A^@uE=t7-L-Stvxqlij6ziLH@mru=%3ro5Pq z20{9^a^$8A&Nt|7TvMot(SGJNmCdaB9BR}W-bL{<=`dWZ1j zM)43dT}d9}UXi+9xc7&tlBsYdiK6|9GBzz;Jwj~78>0?>k#W?3)EjcT^{sB(5$qpi zj#A($(`Um>KC6aU90ox^MmTY5hI50fvHBs8f&)aCQ}i>x(ABm& z#CVxvx&CIrVck9*l=&C5iS}>gXLo$>%_{IGQm0}?(u@xX5~462-yZ-?LeRxZ)WA4? z;fBzZ-$I$)OEQ(}BAHRxyD$h5MX z11D`Gzjv;c{28}BJ(bjm?TBHRDF< zBwVoG&nuI^@t17N5y}=-!sxYr*o`~W-!{47FX-Zeu>G{i{&YxAf@#+nmd za!C|wZ!rssxod#7ukCQ{EkvL7ep3{fI0Wl@8a{OS8r`FZ=C6dyXM7+E3(>nm)+2kr zR{t~6^+#D?m?oW8y6F83YUx_>G-RA*7}~eWYp3qILg>_7RzfpbAUDBNCqIosv zo5F|WNG)l&d&O=o9~S}FjonxxaSey&*$j6KicaH3`FS zkl){!Q;lLGno94$MCp9EV;1bDIDCh%O1;s${r6B0-I}R}lP%_Vi<`BCzSB@86z;3R zi?RV;QYLX`VIb(S+vtTi-PRdjM4voQJA|}ERa0t=Nq-v7qo`^%a9zs&f1vtvB=gp^8* zcLtyDsJFEjuDB?h*-A6?PI?)HOKSo$o(z>`KY*c5TAQ0Db=tJcR?66RnWE~)vmU7{ zGM0H)jAI-L%bqu3dN3A0>9_jl_s0-l4R_}`&du{Ma$)5 z&q79Cu%|@Rzj0?NGu|oO8rca%C?u_p0zERHATplvRlPU?_2s)SwdA(8l3oAjgxZA#I;Z>Ucp~OrY~x_oKf|U7J!vULH$Y? zF7}U}_>~Y14RUA*&?k~^wb2>=(FIEh*4gE7qBpSoIf5|o_KxDfer>YzWOO_^x!l^R zcX>IQu(WmKNfQVY(HgGT?zvyM)-thpr7rPki=EZ?NW!`Pg%FKM%L~I7?vAjZ7b%o=}dOct=_kvd4(2WG~{ zVcrpw$3rEP6NT_^kf8+1Hja>KjUrzelXyaqb?E))1I8AUK^v)YL1HA9mz!mpshg%r t%1*6+bWZ#qt26=dU;G?yP;Kp5-$ZE4yLFFzI_EdDqrJ0T=`mvLe*yC*SLFZz diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 394e36fe105234bf7fbb30c4dfd727800565dba7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5761 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 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index a931dd8609e61cd048ae23d2d260bb5053c659e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8884 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 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index a931dd8609e61cd048ae23d2d260bb5053c659e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8884 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 P1CYG5id6Lnli>dWd%MS% diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index ef99ad546d785c1900dcc33f3c6311a723a64bd0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5893 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�Lt8gc4AtWg7q>t&UtIH5pq3M(h=w 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 P1CYG5id6Lnli>dWd%MS% diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 73a7408d..00000000 --- a/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - #FFFFFF - #344A5E - - - - - - diff --git a/android/app/src/main/res/values/values.xml b/android/app/src/main/res/values/values.xml deleted file mode 100644 index 67165dfa..00000000 --- a/android/app/src/main/res/values/values.xml +++ /dev/null @@ -1,14 +0,0 @@ - - ConnectorSamples - THEO DRM Connector Samples - - 15dp - - #6200EE - #3700B3 - #03DAC5 - #FFFFFF - - - - diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml deleted file mode 100644 index bd229b92..00000000 --- a/android/app/src/main/res/xml/network_security_config.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index 7c6f0533..00000000 --- a/android/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -buildscript { - ext { - kotlin_version = '1.7.10' - } - repositories { - google() - mavenCentral() - } - dependencies { - classpath "com.android.tools.build:gradle:4.2.2" - classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10' - } -} - -allprojects { - repositories { - google() - mavenCentral() - mavenLocal() - maven { url 'https://jitpack.io' } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/android/gradle.properties b/android/gradle.properties deleted file mode 100644 index c52ac9b7..00000000 --- a/android/gradle.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 9db9e361..00000000 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Mon Sep 07 22:14:00 CEST 2020 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip diff --git a/android/gradlew b/android/gradlew deleted file mode 100644 index cccdd3d5..00000000 --- a/android/gradlew +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env sh - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat deleted file mode 100644 index f9553162..00000000 --- a/android/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/android/settings.gradle b/android/settings.gradle deleted file mode 100644 index de3e0024..00000000 --- a/android/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -include ':app' -rootProject.name = "ContentProtectionIntegration" \ No newline at end of file diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj b/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj deleted file mode 100644 index 4e06607f..00000000 --- a/ios/ContentProtectionIntegration.xcodeproj/project.pbxproj +++ /dev/null @@ -1,467 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 51; - objects = { - -/* Begin PBXBuildFile section */ - 620E3EA0267CF4910049F3FF /* KeyOsDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */; }; - 657D888E2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657D888D2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift */; }; - 765B351C27B44D520001270E /* TypeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 765B351B27B44D520001270E /* TypeUtils.swift */; }; - 76B2A70027D150CF009480EB /* VerimatrixCoreDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */; }; - 8FF28873064ABFF844CA8F8B /* Pods_ContentProtectionIntegration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7E0E5387344C04F3BAFF4A8 /* Pods_ContentProtectionIntegration.framework */; }; - D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */; }; - D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */; }; - D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */; }; - D99BC03525A4679200AE24B0 /* EzdrmDRMIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */; }; - E279FE3A25139E4700EC0EFA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3925139E4700EC0EFA /* AppDelegate.swift */; }; - E279FE3C25139E4700EC0EFA /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */; }; - E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E279FE3D25139E4700EC0EFA /* ViewController.swift */; }; - E279FE4125139E4700EC0EFA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE3F25139E4700EC0EFA /* Main.storyboard */; }; - E279FE4325139E4900EC0EFA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4225139E4900EC0EFA /* Assets.xcassets */; }; - E279FE4625139E4900EC0EFA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyOsDRMIntegration.swift; sourceTree = ""; }; - 657D888D2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrisTitaniumDrmIntegration.swift; sourceTree = ""; }; - 765B351B27B44D520001270E /* TypeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeUtils.swift; sourceTree = ""; }; - 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerimatrixCoreDRMIntegration.swift; sourceTree = ""; }; - 9579374696DA3C9C1AC37A64 /* Pods-ContentProtectionIntegration.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentProtectionIntegration.debug.xcconfig"; path = "Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration.debug.xcconfig"; sourceTree = ""; }; - CD6ABAD3AD9CFA4F41C8F0E5 /* Pods-ContentProtectionIntegration.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentProtectionIntegration.release.xcconfig"; path = "Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration.release.xcconfig"; sourceTree = ""; }; - D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VuDRMIntegration.swift; sourceTree = ""; }; - D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UplynkDRMIntegration.swift; sourceTree = ""; }; - D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDRMIntegration.swift; sourceTree = ""; }; - D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EzdrmDRMIntegration.swift; sourceTree = ""; }; - E279FE3625139E4700EC0EFA /* ContentProtectionIntegration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ContentProtectionIntegration.app; sourceTree = BUILT_PRODUCTS_DIR; }; - E279FE3925139E4700EC0EFA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - E279FE3D25139E4700EC0EFA /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - E279FE4025139E4700EC0EFA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - E279FE4225139E4900EC0EFA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - E279FE4525139E4900EC0EFA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - E279FE4725139E4900EC0EFA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E7E0E5387344C04F3BAFF4A8 /* Pods_ContentProtectionIntegration.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ContentProtectionIntegration.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - E279FE3325139E4700EC0EFA /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 8FF28873064ABFF844CA8F8B /* Pods_ContentProtectionIntegration.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1247B51564027806B98BE478 /* Pods */ = { - isa = PBXGroup; - children = ( - 9579374696DA3C9C1AC37A64 /* Pods-ContentProtectionIntegration.debug.xcconfig */, - CD6ABAD3AD9CFA4F41C8F0E5 /* Pods-ContentProtectionIntegration.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - E279FE2D25139E4700EC0EFA = { - isa = PBXGroup; - children = ( - E279FE3825139E4700EC0EFA /* ContentProtectionIntegration */, - E279FE3725139E4700EC0EFA /* Products */, - E279FE4D25139EBA00EC0EFA /* Frameworks */, - 1247B51564027806B98BE478 /* Pods */, - ); - sourceTree = ""; - }; - E279FE3725139E4700EC0EFA /* Products */ = { - isa = PBXGroup; - children = ( - E279FE3625139E4700EC0EFA /* ContentProtectionIntegration.app */, - ); - name = Products; - sourceTree = ""; - }; - E279FE3825139E4700EC0EFA /* ContentProtectionIntegration */ = { - isa = PBXGroup; - children = ( - E279FE5225139F2000EC0EFA /* integration */, - E279FE3925139E4700EC0EFA /* AppDelegate.swift */, - E279FE3B25139E4700EC0EFA /* SceneDelegate.swift */, - E279FE3D25139E4700EC0EFA /* ViewController.swift */, - E279FE3F25139E4700EC0EFA /* Main.storyboard */, - E279FE4225139E4900EC0EFA /* Assets.xcassets */, - E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */, - E279FE4725139E4900EC0EFA /* Info.plist */, - 765B351B27B44D520001270E /* TypeUtils.swift */, - ); - path = ContentProtectionIntegration; - sourceTree = ""; - }; - E279FE4D25139EBA00EC0EFA /* Frameworks */ = { - isa = PBXGroup; - children = ( - E7E0E5387344C04F3BAFF4A8 /* Pods_ContentProtectionIntegration.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - E279FE5225139F2000EC0EFA /* integration */ = { - isa = PBXGroup; - children = ( - D5F8329B251CB5C900032D63 /* AzureDRMIntegration.swift */, - 620E3E9F267CF4910049F3FF /* KeyOsDRMIntegration.swift */, - D5F83297251CAE7400032D63 /* VuDRMIntegration.swift */, - D5F83299251CB0CF00032D63 /* UplynkDRMIntegration.swift */, - D99BC03425A4679200AE24B0 /* EzdrmDRMIntegration.swift */, - 76B2A6FF27D150CF009480EB /* VerimatrixCoreDRMIntegration.swift */, - 657D888D2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift */, - ); - path = integration; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - E279FE3525139E4700EC0EFA /* ContentProtectionIntegration */ = { - isa = PBXNativeTarget; - buildConfigurationList = E279FE4A25139E4900EC0EFA /* Build configuration list for PBXNativeTarget "ContentProtectionIntegration" */; - buildPhases = ( - 0D15DADA531C7EBE18F2747C /* [CP] Check Pods Manifest.lock */, - E279FE3225139E4700EC0EFA /* Sources */, - E279FE3325139E4700EC0EFA /* Frameworks */, - E279FE3425139E4700EC0EFA /* Resources */, - 50CBB4E6454573C97513B0CC /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ContentProtectionIntegration; - productName = ContentProtectionIntegration; - productReference = E279FE3625139E4700EC0EFA /* ContentProtectionIntegration.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - E279FE2E25139E4700EC0EFA /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1170; - LastUpgradeCheck = 1170; - ORGANIZATIONNAME = THEOplayer; - TargetAttributes = { - E279FE3525139E4700EC0EFA = { - CreatedOnToolsVersion = 11.7; - }; - }; - }; - buildConfigurationList = E279FE3125139E4700EC0EFA /* Build configuration list for PBXProject "ContentProtectionIntegration" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = E279FE2D25139E4700EC0EFA; - productRefGroup = E279FE3725139E4700EC0EFA /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - E279FE3525139E4700EC0EFA /* ContentProtectionIntegration */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - E279FE3425139E4700EC0EFA /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E279FE4625139E4900EC0EFA /* LaunchScreen.storyboard in Resources */, - E279FE4325139E4900EC0EFA /* Assets.xcassets in Resources */, - E279FE4125139E4700EC0EFA /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 0D15DADA531C7EBE18F2747C /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-ContentProtectionIntegration-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 50CBB4E6454573C97513B0CC /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ContentProtectionIntegration/Pods-ContentProtectionIntegration-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - E279FE3225139E4700EC0EFA /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 657D888E2923B4BB0083761C /* ArrisTitaniumDrmIntegration.swift in Sources */, - 76B2A70027D150CF009480EB /* VerimatrixCoreDRMIntegration.swift in Sources */, - D99BC03525A4679200AE24B0 /* EzdrmDRMIntegration.swift in Sources */, - D5F83298251CAE7400032D63 /* VuDRMIntegration.swift in Sources */, - E279FE3E25139E4700EC0EFA /* ViewController.swift in Sources */, - 765B351C27B44D520001270E /* TypeUtils.swift in Sources */, - D5F8329A251CB0CF00032D63 /* UplynkDRMIntegration.swift in Sources */, - E279FE3A25139E4700EC0EFA /* AppDelegate.swift in Sources */, - D5F8329C251CB5C900032D63 /* AzureDRMIntegration.swift in Sources */, - 620E3EA0267CF4910049F3FF /* KeyOsDRMIntegration.swift in Sources */, - E279FE3C25139E4700EC0EFA /* SceneDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - E279FE3F25139E4700EC0EFA /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - E279FE4025139E4700EC0EFA /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - E279FE4425139E4900EC0EFA /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - E279FE4525139E4900EC0EFA /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - E279FE4825139E4900EC0EFA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.7; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - E279FE4925139E4900EC0EFA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.7; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - E279FE4B25139E4900EC0EFA /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9579374696DA3C9C1AC37A64 /* Pods-ContentProtectionIntegration.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = 8YAB8ZY55Y; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - "$(PROJECT_DIR)/ContentProtectionIntegration", - ); - INFOPLIST_FILE = ContentProtectionIntegration/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = theoplayer.ContentProtectionIntegration; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development theoplayer.* 1613572623"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - E279FE4C25139E4900EC0EFA /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = CD6ABAD3AD9CFA4F41C8F0E5 /* Pods-ContentProtectionIntegration.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = 8YAB8ZY55Y; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - "$(PROJECT_DIR)/ContentProtectionIntegration", - ); - INFOPLIST_FILE = ContentProtectionIntegration/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = theoplayer.ContentProtectionIntegration; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development theoplayer.* 1613572623"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - E279FE3125139E4700EC0EFA /* Build configuration list for PBXProject "ContentProtectionIntegration" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E279FE4825139E4900EC0EFA /* Debug */, - E279FE4925139E4900EC0EFA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E279FE4A25139E4900EC0EFA /* Build configuration list for PBXNativeTarget "ContentProtectionIntegration" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E279FE4B25139E4900EC0EFA /* Debug */, - E279FE4C25139E4900EC0EFA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = E279FE2E25139E4700EC0EFA /* Project object */; -} diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 185f3510..00000000 --- a/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/ios/ContentProtectionIntegration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/ios/ContentProtectionIntegration/AppDelegate.swift b/ios/ContentProtectionIntegration/AppDelegate.swift deleted file mode 100644 index 54ba9f0e..00000000 --- a/ios/ContentProtectionIntegration/AppDelegate.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// AppDelegate.swift -// ContentProtectionIntegration -// -// Copyright © 2020 THEOplayer. All rights reserved. -// - -import UIKit -import THEOplayerSDK - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - - THEOplayer.registerContentProtectionIntegration(integrationId: VuDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: VuDRMIntegrationFactory()) - - THEOplayer.registerContentProtectionIntegration(integrationId: UplynkDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: UplynkDRMIntegrationFactory()) - - THEOplayer.registerContentProtectionIntegration(integrationId: AzureDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: AzureDRMIntegrationFactory()) - - THEOplayer.registerContentProtectionIntegration(integrationId: EzdrmDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: EzdrmDRMIntegrationFactory()) - - THEOplayer.registerContentProtectionIntegration(integrationId: KeyOsDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: KeyOsDRMIntegrationFactory()) - - THEOplayer.registerContentProtectionIntegration(integrationId: VerimatrixCoreDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: VerimatrixCoreDRMIntegrationFactory()) - - THEOplayer.registerContentProtectionIntegration(integrationId: TitaniumDRMIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: TitaniumDRMIntegrationFactory()) - - return true - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - -} - diff --git a/ios/ContentProtectionIntegration/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/ContentProtectionIntegration/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9221b9bb..00000000 --- a/ios/ContentProtectionIntegration/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/ios/ContentProtectionIntegration/Assets.xcassets/Contents.json b/ios/ContentProtectionIntegration/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/ios/ContentProtectionIntegration/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/ios/ContentProtectionIntegration/Base.lproj/LaunchScreen.storyboard b/ios/ContentProtectionIntegration/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329..00000000 --- a/ios/ContentProtectionIntegration/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/ContentProtectionIntegration/Base.lproj/Main.storyboard b/ios/ContentProtectionIntegration/Base.lproj/Main.storyboard deleted file mode 100644 index 25a76385..00000000 --- a/ios/ContentProtectionIntegration/Base.lproj/Main.storyboard +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/ContentProtectionIntegration/Info.plist b/ios/ContentProtectionIntegration/Info.plist deleted file mode 100644 index 2a3483c0..00000000 --- a/ios/ContentProtectionIntegration/Info.plist +++ /dev/null @@ -1,64 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/ios/ContentProtectionIntegration/SceneDelegate.swift b/ios/ContentProtectionIntegration/SceneDelegate.swift deleted file mode 100644 index a3e7038f..00000000 --- a/ios/ContentProtectionIntegration/SceneDelegate.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// SceneDelegate.swift -// ContentProtectionIntegration -// -// Copyright © 2020 THEOplayer. All rights reserved. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let _ = (scene as? UIWindowScene) else { return } - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - - -} - diff --git a/ios/ContentProtectionIntegration/TypeUtils.swift b/ios/ContentProtectionIntegration/TypeUtils.swift deleted file mode 100644 index bd93e4a0..00000000 --- a/ios/ContentProtectionIntegration/TypeUtils.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// TypeUtils.swift -// ContentProtectionIntegration -// -// Copyright © 2020 THEOplayer. All rights reserved. -// - -import Foundation - -func fromUtf8StringToData(str: String) -> Data? { - return str.data(using: .utf8) -} - -func fromBase64StringToData(base64Encoded: String) -> Data? { - return Data(base64Encoded: base64Encoded) -} - -func fromDataToBase64String(data: Data?) -> String? { - return data?.base64EncodedString() -} - -func fromDataToUtf8String(data: Data) -> String? { - return String(data: data, encoding: .utf8) -} diff --git a/ios/ContentProtectionIntegration/ViewController.swift b/ios/ContentProtectionIntegration/ViewController.swift deleted file mode 100644 index 12f22cc5..00000000 --- a/ios/ContentProtectionIntegration/ViewController.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// ViewController.swift -// ContentProtectionIntegration -// -// Copyright © 2020 THEOplayer. All rights reserved. -// - -import UIKit -import THEOplayerSDK - -class ViewController: UIViewController { - var theoplayer: THEOplayer! - - override func viewDidLoad() { - super.viewDidLoad() - setupTheoPlayer() - self.theoplayer.source = sampleSource - } - - func setupTheoPlayer() { - var frame: CGRect = UIScreen.main.bounds - frame.origin.y = 0 - frame.size.height = frame.size.width * 9 / 16 - self.theoplayer = THEOplayer(configuration: THEOplayerConfiguration( - pip: nil, - license: "YOUR_LICENSE_HERE" - )) - self.theoplayer.frame = frame - self.theoplayer.addAsSubview(of: self.view) - } - - var sampleSource: SourceDescription { - return SourceDescription( - source: TypedSource( - src: "https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-19.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/hls-fp/master.m3u8", - type: "application/x-mpegurl", - drm: FairPlayDRMConfiguration( - customIntegrationId: KeyOsDRMIntegration.integrationID, - licenseAcquisitionURL: "https://fp-keyos.licensekeyserver.com/getkey/", - certificateURL: "https://fp-keyos.licensekeyserver.com/cert/7e11400c7dccd29d0174c674397d99dd.der", - integrationParameters: ["x-keyos-authorization":"PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg=="] - ) - ) - ) - } -} diff --git a/ios/ContentProtectionIntegration/integration/ArrisTitaniumDrmIntegration.swift b/ios/ContentProtectionIntegration/integration/ArrisTitaniumDrmIntegration.swift deleted file mode 100644 index 753de57e..00000000 --- a/ios/ContentProtectionIntegration/integration/ArrisTitaniumDrmIntegration.swift +++ /dev/null @@ -1,242 +0,0 @@ -// -// ArrisTitaniumDrmIntegration.swift -// ContentProtectionIntegration -// -// Created by Daniel on 15/11/2022. -// Copyright © 2022 THEOplayer. All rights reserved. -// - -import Foundation -import THEOplayerSDK - -/// Sample source usage: -/// -/// - Token-based authorization with Cetificate URL -/// -/// var integrationParameters: [String:Any] = [:] -/// integrationParameters["authToken"] = "___JWT_AUTH_TOKEN___" -/// -/// let drmConfig = FairPlayDRMConfiguration( -/// customIntegrationId: TitaniumDRMIntegration.integrationID, -/// licenseAcquisitionURL: "___LICENSE_SERVER_URL___", -/// certificateURL: "___CERTIFICATE_URL___", -/// integrationParameters: integrationParameters -/// ) -/// -/// let source = SourceDescription( -/// sources: [TypedSource( -/// src: "___SOURCE_URL___", -/// type: "application/x-mpegurl", -/// drm: drmConfig)] -/// ) -/// -/// theoplayer.source = source -/// -/// -/// - Token-based authorization with base64 encoded Certificate data -/// -/// var integrationParameters: [String:Any] = [:] -/// integrationParameters["authToken"] = "___JWT_AUTH_TOKEN___" -/// integrationParameters["certificateData"] = "___BASE64_ENCODED_CERT___" // passing base64 encoded certificate data instead of loading it from a URL (useful, if the certificate is inside the app) -/// -/// let drmConfig = FairPlayDRMConfiguration( -/// customIntegrationId: TitaniumDRMIntegration.integrationID, -/// licenseAcquisitionURL: "___LICENSE_SERVER_URL___", -/// certificateURL: "https://dummyurl.com", // you can use any dummy URL to trigger and intercept the flow (request will be not executed) -/// integrationParameters: integrationParameters -/// ) -/// -/// let source = SourceDescription( -/// sources: [TypedSource( -/// src: "___SOURCE_URL___", -/// type: "application/x-mpegurl", -/// drm: drmConfig)] -/// ) -/// -/// theoplayer.source = source -/// -/// - Device-based authorization with Cetificate URL -/// -/// var integrationParameters: [String:Any] = [:] -/// integrationParameters["accountName"] = "___ACCOUNT_NAME___" // mandatory parameter for device-based authorization -/// integrationParameters["customerName"] = "___CUSTOMER_NAME___" // mandatory parameter for device-based authorization -/// integrationParameters["portalId"] = "___PORTAL_ID_NAME___" // mandatory parameter for device-based authorization -/// integrationParameters["friendlyName"] = "___FRIENDLY_NAME___" // mandatory parameter for device-based authorization -/// -/// let drmConfig = FairPlayDRMConfiguration( -/// customIntegrationId: TitaniumDRMIntegration.integrationID, -/// licenseAcquisitionURL: "___LICENSE_SERVER_URL___", -/// certificateURL: "___CERTIFICATE_URL___", -/// integrationParameters: integrationParameters -/// ) -/// -/// let source = SourceDescription( -/// sources: [TypedSource( -/// src: "___SOURCE_URL___", -/// type: "application/x-mpegurl", -/// drm: drmConfig)] -/// ) -/// -/// theoplayer.source = source - -class TitaniumDRMIntegration: ContentProtectionIntegration { - static let integrationID = "titanium" - - let fairplayKeySystemConfiguration: KeySystemConfiguration - var drmConfiguration: DRMConfiguration - - init(drmConfiguration: FairPlayDRMConfiguration) { - self.drmConfiguration = drmConfiguration - self.fairplayKeySystemConfiguration = drmConfiguration.fairplay - } - - init(drmConfiguration: MultiplatformDRMConfiguration) { - self.drmConfiguration = drmConfiguration - self.fairplayKeySystemConfiguration = drmConfiguration.keySystemConfigurations.fairplay! - } - - func extractFairplayContentId(skdUrl: String) -> String { - print("[TitaniumDRMIntegration] <- \(#function): \(skdUrl)") - let arr = skdUrl.components(separatedBy: "/") - let skd = arr[arr.count - 1] - print("[TitaniumDRMIntegration] -> \(#function): \(skd)") - return skd - } - - func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - let requestString = String(data: try! JSONEncoder().encode(request), encoding: .utf8)! - print("[TitaniumDRMIntegration] <- \(#function): \(requestString)") - - if let certificateData = drmConfiguration.integrationParameters?["certificateData"] as? String { - callback.respond(certificate: Data(base64Encoded: certificateData, options: .ignoreUnknownCharacters)!) - } else if let certificateURL = fairplayKeySystemConfiguration.certificateURL { - var newRequest = URLRequest(url: certificateURL) - newRequest.httpMethod = "GET" - URLSession.shared.dataTask(with: newRequest) { data, response, error in - if let error = error { - callback.error(error: error) - print("[TitaniumDRMIntegration] error", error) - return - } - - if let certData = data { - print("[TitaniumDRMIntegration] -> \(#function): respond with data") - callback.respond(certificate: certData) - } else { - print("[TitaniumDRMIntegration] -> \(#function): error", error) - callback.error(error: URLError.init(URLError.badServerResponse)) - } - } - .resume() - } else { - print("[TitaniumDRMIntegration] -> \(#function): error clientCertificateRequired") - callback.error(error: URLError.init(URLError.clientCertificateRequired)) - } - - } - - func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - let requestString = String(data: try! JSONEncoder().encode(request), encoding: .utf8)! - print("[TitaniumDRMIntegration] <- \(#function): \(requestString)") - - guard let serviceUrl = fairplayKeySystemConfiguration.licenseAcquisitionURL else { - fatalError("[TitaniumDRMIntegration] LA is not a valid URL") - } - var urlRequest = URLRequest(url: serviceUrl) - - // support for token-based authorization - if let authToken = drmConfiguration.integrationParameters?["authToken"] as? String { - urlRequest.setValue("Bearer " + authToken, forHTTPHeaderField: "Authorization") - - // support for device specific authorization - } else if let accountName = drmConfiguration.integrationParameters?["accountName"] as? String, - let customerName = drmConfiguration.integrationParameters?["customerName"] as? String, - let portalId = drmConfiguration.integrationParameters?["portalId"] as? String, - let friendlyName = drmConfiguration.integrationParameters?["friendlyName"] as? String { - - let lr = DeviceSpecificAuth(LatensRegistration: LatensRegistration(CustomerName: customerName, AccountName: accountName, PortalId: portalId, FriendlyName: friendlyName, DeviceInfo: DeviceInfo())) - - urlRequest.setValue(try! JSONEncoder().encode(lr).base64EncodedString(), forHTTPHeaderField: "X-TITANIUM-DRM-CDATA") - - } else { - print("[TitaniumDRMIntegration] -> \(#function): error userAuthenticationRequired") - callback.error(error: URLError.init(URLError.userAuthenticationRequired)) - return - } - - urlRequest.httpMethod = "POST" - urlRequest.httpBody = request.body - urlRequest.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type") - - URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in - if let data = data { - print("[TitaniumDRMIntegration] -> \(#function): respond with license") - callback.respond(license: data) - } else { - print("[TitaniumDRMIntegration] -> \(#function): error", error) - callback.error(error: error!) - } - }.resume() - - } - - func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - print("[TitaniumDRMIntegration] <- \(#function): response") - callback.respond(license: response.body) - } - -} - -class TitaniumDRMIntegrationFactory: ContentProtectionIntegrationFactory { - func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { - if let fairplayConfiguration = configuration as? FairPlayDRMConfiguration { - return TitaniumDRMIntegration(drmConfiguration: fairplayConfiguration) - } else if let multiDrm = configuration as? MultiplatformDRMConfiguration, multiDrm.keySystemConfigurations.fairplay != nil { - return TitaniumDRMIntegration(drmConfiguration: multiDrm) - } else { - fatalError("DRMConfiguration must contain a FairPlay Keysystem configuration") - } - } -} - -struct DeviceSpecificAuth: Encodable { - var LatensRegistration: LatensRegistration -} - -struct LatensRegistration: Encodable { - var CustomerName: String - var AccountName: String - var PortalId: String - var FriendlyName: String - var AppVersion: String = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" - var DeviceInfo: DeviceInfo -} - -struct DeviceInfo: Encodable { - var FormatVersion: String = "1" - var varDeviceType: String = DeviceInfo.getDeviceType() - var OSType: String = UIDevice.current.systemName - var OSVersion: String = UIDevice.current.systemVersion - var DRMProvider: String = "Apple" - var DRMVersion: String = "1.0" - var DRMType: String = "Fairplay" - var DeviceVendor: String = "Apple" - var DeviceModel: String = UIDevice.current.model - - static func getDeviceType() -> String { - switch UIDevice.current.userInterfaceIdiom { - case .carPlay: - return "CarPlay" - case .mac: - return "Mac" - case .pad: - return "iPad" - case .phone: - return "iPhone" - case .tv: - return "AppleTV" - default: - return "Unknown" - } - } -} diff --git a/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift deleted file mode 100644 index 3ca073c3..00000000 --- a/ios/ContentProtectionIntegration/integration/AzureDRMIntegration.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// AzureDRMIntegration.swift -// ContentProtectionIntegration -// -// Copyright © 2020 THEOplayer. All rights reserved. -// - -import Foundation -import THEOplayerSDK - -class AzureDRMIntegration: ContentProtectionIntegration { - static let integrationID = "customAzureDRM" - var configuration: DRMConfiguration - - var contentId: String? - - init(configuration: DRMConfiguration) { - self.configuration = configuration - } - - func extractFairplayContentId(skdUrl: String) -> String { - let components = skdUrl.components(separatedBy: "?") - let skd = components.last! - self.contentId = skd - return skd - } - - func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - request.headers = [ - "Authorization": "Bearer \(self.getTokenFromDrmConfiguration())", - "Content-Type": "application/x-www-form-urlencoded" - ] - callback.request(request: request) - } - - func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { - callback.respond(certificate: response.body) - } - - func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - guard let contentId = self.contentId else { - fatalError("contentID was nil.") - } - request.headers = [ - "Authorization": "Bearer \(self.getTokenFromDrmConfiguration())", - "Content-Type": "application/x-www-form-urlencoded" - ] - if let body64 = fromDataToBase64String(data: request.body) { - request.body = fromUtf8StringToData(str: "spc=\(body64)&assetId=\(contentId)") - callback.request(request: request) - } else { - fatalError("RequestBody was nil.") - } - } - - func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - guard var licenseBody = fromDataToUtf8String(data: response.body) else { - fatalError("Could not create a string from the reponseBody provided.") - } - licenseBody = licenseBody.replacingOccurrences(of: "", with: "") - licenseBody = licenseBody.replacingOccurrences(of: "", with: "") - if let data = fromBase64StringToData(base64Encoded: licenseBody) { - callback.respond(license: data) - } else { - fatalError("Could not create a Data Object from the responseBody provided.") - } - } - - private func getTokenFromDrmConfiguration() -> String { - guard let token = self.configuration.integrationParameters?["token"] as? String else { - fatalError("Could not find the token in the integrationParameters.") - } - return token - } -} - -class AzureDRMIntegrationFactory: ContentProtectionIntegrationFactory { - func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { - return AzureDRMIntegration(configuration: configuration) - } -} diff --git a/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift deleted file mode 100644 index ca827fe9..00000000 --- a/ios/ContentProtectionIntegration/integration/EzdrmDRMIntegration.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// EzdrmDRMIntegration.swift -// ContentProtectionIntegration -// -// Copyright © 2021 THEOplayer. All rights reserved. -// - -import Foundation -import THEOplayerSDK - -class EzdrmDRMIntegration: ContentProtectionIntegration { - static let integrationID = "EzdrmDRMIntegration" - - func extractFairplayContentId(skdUrl: String) -> String { - let arr = skdUrl.components(separatedBy: ";") - let skd = arr[arr.count - 1] - return skd - } - - func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - callback.request(request: request) - } - - func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { - callback.respond(certificate: response.body) - } - - func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - // `LicenseRequestCallback.respond(:data)` - `LicenseRequestCallback.error(:error)` - `CertificateRequestCallback.respond(:data)` and - // `CertificateRequestCallback.error(:error)` are available as of v2.81.0, so in THEOplayer versions < 2.81.0, setting the `request.url` to a valid - // dummy URL is necessary to bypass a known limitation. - // - step: 1 - // in `onLicenseRequest(:request:callback)` - // request.url = "https://httpstatuses.com/200" - // callback.request(request: request) - // - step: 2 - // in `onLicenseResponse(:response:callback)` you need to download the actual license - // and give it back to THEOplayer using `LicenseResponseCallback.respond(:data)` - var urlRequest = URLRequest(url: URL(string: request.url)!) - urlRequest.httpMethod = "POST" - urlRequest.httpBody = request.body - urlRequest.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type") - URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in - if let data = data { - callback.respond(license: data) - } else { - callback.error(error: error!) - } - }.resume() - } -} - -class EzdrmDRMIntegrationFactory: ContentProtectionIntegrationFactory { - func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { - return EzdrmDRMIntegration() - } -} diff --git a/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift deleted file mode 100644 index 01b4415c..00000000 --- a/ios/ContentProtectionIntegration/integration/KeyOsDRMIntegration.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// KeyOsDRMIntegration.swift -// ContentProtectionIntegration -// -// Created by Wonne Joosen on 18/06/2021. -// Copyright © 2021 THEOplayer. All rights reserved. -// - -import Foundation -import THEOplayerSDK - -class KeyOsDRMIntegration: ContentProtectionIntegration { - static let integrationID = "customkeyosDRM" - var configuration: DRMConfiguration - - var contentId: String? - - init(configuration: DRMConfiguration) { - self.configuration = configuration - } - - func extractFairplayContentId(skdUrl: String) -> String { - let components = skdUrl.components(separatedBy: "?") - let skd = components.last! - self.contentId = skd.replacingOccurrences(of: "skd://", with: "") - return skd - } - - func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - request.headers.updateValue(self.getXKeyosAuthorizationFromDrmConfiguration(), forKey: "x-keyos-authorization") - callback.request(request: request) - - } - - func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { - callback.respond(certificate: response.body) - } - - - func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - guard let contentId = self.contentId else { - fatalError("contentID was nil.") - } - - request.headers.updateValue(self.getXKeyosAuthorizationFromDrmConfiguration(), forKey: "x-keyos-authorization") - - if let body64 = fromDataToBase64String(data: request.body) { - request.body = fromUtf8StringToData(str: "spc=\(body64)&assetId=\(contentId)") - callback.request(request: request) - } else { - fatalError("RequestBody was nil.") - } - } - - func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - guard var licenseBody = fromDataToUtf8String(data: response.body) else { - fatalError("Could not create a string from the reponseBody provided.") - } - licenseBody = licenseBody.replacingOccurrences(of: "", with: "") - licenseBody = licenseBody.replacingOccurrences(of: "", with: "") - if let data = fromBase64StringToData(base64Encoded: licenseBody) { - callback.respond(license: data) - } else { - fatalError("Could not create a Data Object from the responseBody provided.") - } - } - - private func getXKeyosAuthorizationFromDrmConfiguration() -> String { - guard let customdata = self.configuration.integrationParameters?["x-keyos-authorization"] as? String else { - fatalError("Could not find the x-keyos-authorization value in the integrationParameters.") - } - return customdata - } -} - -class KeyOsDRMIntegrationFactory: ContentProtectionIntegrationFactory { - func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { - return KeyOsDRMIntegration(configuration: configuration) - } -} diff --git a/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift deleted file mode 100644 index 6f12bcca..00000000 --- a/ios/ContentProtectionIntegration/integration/UplynkDRMIntegration.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// UplynkDRMIntegration.swift -// ContentProtectionIntegration -// -// Copyright © 2020 THEOplayer. All rights reserved. -// - -import Foundation -import THEOplayerSDK - -class UplynkDRMIntegration: ContentProtectionIntegration { - static let integrationID = "customUplynkDRM" - let UPLYNK_CONTENT_ID_PARAMETER_NAME = "b"; - var skdUrl: String? - - var configuration: DRMConfiguration - init(configuration: DRMConfiguration) { - self.configuration = configuration - } - - func extractFairplayContentId(skdUrl: String) -> String { - self.skdUrl = skdUrl - guard let urlComponents = URLComponents(string: skdUrl), - let queryItems = urlComponents.queryItems, - let queryItemSkd = queryItems.first(where: { $0.name == UPLYNK_CONTENT_ID_PARAMETER_NAME }), - let skd = queryItemSkd.value - else { - fatalError("Could Not parse the skd") - } - return skd - } - - func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - callback.request(request: request) - } - - func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { - callback.respond(certificate: response.body) - } - - func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - guard let skdUrl = self.skdUrl else { - fatalError("skdUrl was nil.") - } - let laURL = skdUrl.replacingOccurrences(of: "skd://", with: "https://") - request.url = laURL - var dict = [String: String]() - if let spc = fromDataToBase64String(data: request.body) { - dict.updateValue(spc, forKey: "spc") - } - do { - request.body = try JSONEncoder().encode(dict) - callback.request(request: request) - } catch let error { - fatalError(error.localizedDescription) - } - } - - func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - do { - let dto = try JSONDecoder().decode(UplynkDRMLicenseResponse.self, from: response.body) - guard let responseBody = fromBase64StringToData(base64Encoded: dto.ckc) else { - fatalError("Could not Decode base64Encoded ckc") - } - response.body = responseBody - callback.respond(license: response.body) - } catch let err { - print(err) - callback.error(error: err) - } - } - - private struct UplynkDRMLicenseResponse: Codable { - var ckc: String - } -} - -class UplynkDRMIntegrationFactory: ContentProtectionIntegrationFactory { - func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { - return UplynkDRMIntegration(configuration: configuration) - } -} diff --git a/ios/ContentProtectionIntegration/integration/VerimatrixCoreDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/VerimatrixCoreDRMIntegration.swift deleted file mode 100644 index 844e7076..00000000 --- a/ios/ContentProtectionIntegration/integration/VerimatrixCoreDRMIntegration.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// VerimatrixCoreDRMIntegration.swift -// ContentProtectionIntegration -// -// Created by Wonne Joosen on 09/03/2022. -// Copyright © 2022 THEOplayer. All rights reserved. -// - -import Foundation -import THEOplayerSDK - -class VerimatrixCoreDRMIntegration: ContentProtectionIntegration { - static let integrationID = "verimatrix" - var configuration: DRMConfiguration - - var contentId: String? - - init(configuration: DRMConfiguration) { - self.configuration = configuration - } - - func extractFairplayContentId(skdUrl: String) -> String { - let components = skdUrl.components(separatedBy: "?") - let skd = components.first! - self.contentId = skd.replacingOccurrences(of: "skd://", with: "") - return self.contentId! - } - - func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - callback.request(request: request) - - } - - func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { - callback.respond(certificate: response.body) - } - - - func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - if let body64 = request.body?.base64EncodedString() { - let body = "{\"spc\":\"\(body64)\"}" - request.url = request.url + "?Authorization=" + getAuthorizationFromDrmConfiguration() - request.headers = [ - "Content-Type":"application/json", - "User-Agent": "ContentProtectionIntegration/0.0.1" - ] - request.body = body.data(using: .utf8) - callback.request(request: request) - } else { - fatalError("RequestBody was nil.") - } - } - - struct LicResp: Decodable { - let ckc: String - } - - func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - guard let licenseBody = String(data: response.body, encoding: .utf8) else { - fatalError("Could not create a string from the reponseBody provided.") - } - let jsonResponse: LicResp = try! JSONDecoder().decode(LicResp.self, from: licenseBody.data(using: .utf8)!) - if let data = Data(base64Encoded: jsonResponse.ckc) { - callback.respond(license: data) - } else { - fatalError("Could not create a Data Object from the responseBody provided.") - } - } - - private func getAuthorizationFromDrmConfiguration() -> String { - guard let authorization = self.configuration.integrationParameters?["authorization"] as? String else { - fatalError("Could not find the authorization value in the integrationParameters.") - } - return authorization - } -} - -class VerimatrixCoreDRMIntegrationFactory: ContentProtectionIntegrationFactory { - func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { - return VerimatrixCoreDRMIntegration(configuration: configuration) - } -} diff --git a/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift b/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift deleted file mode 100644 index 341f54ed..00000000 --- a/ios/ContentProtectionIntegration/integration/VuDRMIntegration.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// VuDRMIntegration.swift -// ContentProtectionIntegration -// -// Copyright © 2020 THEOplayer. All rights reserved. -// - -import Foundation -import THEOplayerSDK - - -class VuDRMIntegration: ContentProtectionIntegration { - static let integrationID = "customVuDRM" - var contentID: String? - var configuration: DRMConfiguration - - init(configuration: DRMConfiguration) { - self.configuration = configuration - } - - func extractFairplayContentId(skdUrl: String) -> String { - let arr = skdUrl.components(separatedBy: "/") - let skd = arr[arr.count - 1] - self.contentID = skd - return skd - } - - func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - request.headers.updateValue(self.getTokenFromDrmConfiguration(), forKey: "x-vudrm-token") - request.headers.updateValue("application/json", forKey: "Content-Type") - callback.request(request: request) - } - - func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { - callback.respond(certificate: response.body) - } - - func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - guard let contentID = self.contentID else { - fatalError("contentID was nil.") - } - request.headers.updateValue("application/json", forKey: "content-type") - - var dict = [String: String]() - dict.updateValue(self.getTokenFromDrmConfiguration(), forKey: "token") - dict.updateValue(contentID, forKey: "contentId") - if let payload = fromDataToBase64String(data: request.body) { - dict.updateValue(payload, forKey: "payload") - } - do { - request.body = try JSONEncoder().encode(dict) - callback.request(request: request) - } catch let error { - fatalError(error.localizedDescription) - } - } - - func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - callback.respond(license: response.body) - } - - private func getTokenFromDrmConfiguration() -> String { - guard let token = self.configuration.integrationParameters?["token"] as? String else { - fatalError("Could not find the token in the integrationParameters") - } - return token - } -} - -class VuDRMIntegrationFactory: ContentProtectionIntegrationFactory { - func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { - return VuDRMIntegration(configuration: configuration) - } -} diff --git a/ios/Podfile b/ios/Podfile deleted file mode 100644 index f3c0a4b9..00000000 --- a/ios/Podfile +++ /dev/null @@ -1,11 +0,0 @@ -# Uncomment the next line to define a global platform for your project -# platform :ios, '9.0' - -target 'ContentProtectionIntegration' do - # Comment the next line if you don't want to use dynamic frameworks - use_frameworks! - - # Pods for ContentProtectionIntegration - pod 'THEOplayerSDK-basic' - -end diff --git a/ios/README.md b/ios/README.md deleted file mode 100644 index 4f5c6d7a..00000000 --- a/ios/README.md +++ /dev/null @@ -1,257 +0,0 @@ -## Getting started on iOS - -1. [Overview](#overview) -2. [Creating a new integration](#creating-a-new-integration) -3. [Request and Response types](#request-and-response-types) -4. [Available examples](#available-examples) -5. [Testing an integration](#testing-an-integration) -6. [Conclusion](#conclusion) - -### Overview - -This document provides a step-by-step approach on how to create a custom DRM integration with the THEOplayer iOS SDK. -It gives an overview of which classes are involved and how they participate in the DRM flow. - -The project's top-level [README](../README.md) elaborates on what it means to create a DRM integration, gives a brief -platform-independent overview of the flow, and clarifies the terminology being used throughout the document. Make sure -to familiarise yourself with it before starting your own implementation. - -The static class diagram below depicts classes that are part of the SDK in white, while coloured classes need to be -implemented when creating a custom integration. The `ContentProtectionIntegrationFactory` subclass is only used once -by THEOplayer to create an instance of a `ContentProtectedIntegration` subclass. The latter contains the actual hook methods -being referred to in the DRM integration [sequence diagram](../README.md#drm-integration-api). - -![Custom DRM integration class diagram](../resources/ios_custom_drm_classes.svg) - -In the next section a custom integration is built by implementing both subclasses. - -### Creating a new integration - -First create a custom implementation of [ContentProtectionIntegration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/ios/latest/External%20Content%20Protection%20integration%20API.html#/c:@M@THEOplayerSDK@objc(pl)ContentProtectionIntegration) -under `ios/ContentProtectionIntegration/integration`. -This object defines handler methods that allow altering license and certificate requests and responses as part of the -DRM flow. -All methods are optional. They can be omitted if the integration does not require additional action, in which case the -default implementation will be used. - -```swift -import Foundation -import THEOplayerSDK - -class MyCustomIntegration: ContentProtectionIntegration { - static let integrationID = "myCustomDRM" - - let configuration: DRMConfiguration - - init(configuration: DRMConfiguration) { - self.configuration = configuration - } - - func onCertificateRequest(request: CertificateRequest, callback: CertificateRequestCallback) { - callback.request(request: request) - } - - func onCertificateResponse(response: CertificateResponse, callback: CertificateResponseCallback) { - callback.respond(certificate: response.body) - } - - func onLicenseRequest(request: LicenseRequest, callback: LicenseRequestCallback) { - // request.headers = [ - // "x-token": self.getTokenFromDrmConfiguration(), - // ] - callback.request(request: request) - } - - func onLicenseResponse(response: LicenseResponse, callback: LicenseResponseCallback) { - callback.respond(license: response.body) - } - - func extractFairplayContentId(skdUrl: String) -> String { - return "" - } - - private func getTokenFromDrmConfiguration() -> String { - guard let token = self.configuration.integrationParameters?["token"] as? String else { - fatalError("Could not find the token in the integrationParameters.") - } - return token - } -} -``` - -Optional parameters needed for certificate or license requests, such as tokens, can be added to a -[DRMConfiguration](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/ios/latest/Protocols/DRMConfiguration.html) -object that is passed when creating instances of the `MyCustomIntegration` class. -In the example, `MyCustomIntegration` adds a token from the configuration object as part of the headers -during a license request. - -Next, create a [ContentProtectionIntegrationFactory](https://theoplayer-cdn.s3.eu-west-1.amazonaws.com/doc/ios/latest/External%20Content%20Protection%20integration%20API.html#/s:13THEOplayerSDK35ContentProtectionIntegrationFactoryP) for building MyCustomIntegration instances. -THEOplayer will use this factory in its DRM flow whenever it needs a ContentProtectionIntegration instance that -matches with the content protected source. How THEOplayer knows which factory to take will be determined in the -`registerContentProtectionIntegration` step next. - -```swift -class MyCustomIntegrationFactory: ContentProtectionIntegrationFactory { - func build(configuration: DRMConfiguration) -> ContentProtectionIntegration { - return MyCustomIntegration(configuration: configuration) - } -} -``` - -An instance of `MyCustomIntegrationFactory` needs to be registered with THEOplayer's global instance in -[AppDelegate](/ios/ContentProtectionIntegration/AppDelegate.swift) -by specifying a unique `integrationId`, such as `"myCustomDRM"` in this example. - -```swift -class AppDelegate: UIResponder, UIApplicationDelegate { - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - THEOplayer.registerContentProtectionIntegration(integrationId: MyCustomIntegration.integrationID, keySystem: .FAIRPLAY, integrationFactory: MyCustomIntegrationFactory()) - return true - } -} -``` - -When the player now loads a source with a `customIntegrationId` that matches the `integrationId` -passed during registration, an instance of `MyCustomIntegration` will be created and used in the DRM flow. - -Also, fill the source description in [ViewController](/ios/ContentProtectionIntegration/ViewController.swift), -which provides the manifest, certificate and license URLs along with any integration parameters. - -*Note: The Dictionary ```integrationParameters``` only supports Primitive-types and Codable values. all other types will ignored* -```swift -var sampleSource: SourceDescription { - return SourceDescription( - source: TypedSource( - src: "", - type: "application/x-mpegurl", - drm: FairPlayDRMConfiguration( - customIntegrationId: MyCustomIntegration.integrationID, - licenseAcquisitionURL: "", - certificateURL: "", - integrationParameters: [ - // optional integration parameters - // "token": "" - ] - ) - ) - ) -} -``` -Finally, build and run the app on an iOS device. - -### Request and Response types - -Manipulating certificate and license requests and responses requires special care. Next to adding header -fields or changing the target url, the bodies of `CertificateRequest` and`LicenseRequest` most often -need to be transformed or wrapped before passing it along. - -```objc -@objc public class CertificateRequest : THEOplayerSDK.Request { - @objc override public init( - url: String, - method: String, - headers: [String : String], - body: Data? - ) - required public init(from decoder: Decoder) throws -} - -@objc public class LicenseRequest : THEOplayerSDK.Request { - @objc public var fairplaySkdUrl: String? - @objc override public init( - url: String, - method: String, - headers: [String : String], - body: Data? - ) - @objc public init( - url: String, - method: String, - headers: [String : String], - body: Data?, - fairplaySkdUrl: String?, - useCredentials: Bool - ) -} -``` - -Both `CertificateRequest` and `LicenseRequest` objects expect the body to be of byte buffer type -[Data](https://developer.apple.com/documentation/foundation/data). -In case of a license request it originally contains the challenge generated by the CDM. -A common way of passing extra data to the server is by wrapping the raw request body -in a JSON object with some additional properties, which is then transformed back into the required type `Data`. The following -example in Swift is taken from the [VuDRM integration sample](ContentProtectionIntegration/integration/VuDRMIntegration.swift): - -```swift -var dict = [String: String]() -dict.updateValue(self.getTokenFromDrmConfiguration(), forKey: "token") -dict.updateValue(contentID, forKey: "contentId") -if let payload = fromDataToBase64String(data: request.body) { - dict.updateValue(payload, forKey: "payload") -} -do { - request.body = try JSONEncoder().encode(dict) - callback.request(request: request) -} catch let error { - fatalError(error.localizedDescription) -} -``` -where the `fromDataToBase64String` helper method creates a base64-encoded string from the request body. - -Similarly, `CertificateResponse` and `LicenseResponse` objects returned from the server contain among others the -response headers and the response body. -The latter is again of type [Data](https://developer.apple.com/documentation/foundation/data), -containing the certificate or license that will be passed to the CDM. - -```obj -@objc public class CertificateResponse : THEOplayerSDK.Response { - @objc public init( - certificateRequest: THEOplayerSDK.CertificateRequest, - url: String, - status: Int, - statusText: String, - headers: [String : String], - body: Data - ) -} - -@objc public class LicenseResponse : THEOplayerSDK.Response { - @objc public init( - licenseRequest: THEOplayerSDK.LicenseRequest, - url: String, - status: Int, - statusText: String, - headers: [String : String], - body: Data - ) -} -``` - -Depending on the DRM integration, the response body either already is a raw certificate or license that can be passed along as-is, -or needs to be transformed or unwrapped first in a way similar to the request body. - -### Available examples - -- Vualto VuDRM -- Microsoft Azure DRM -- Verizon Uplynk DRM -- EZ DRM -- Verimatrix Core DRM -- Arris Titanium DRM (supported from THEOplayer 4.4.0) - -### Testing an integration - -- Ensure that your Podfile is point to an appropriate [THEOplayer iOS SDK](https://github.com/THEOplayer/theoplayer-sdk-ios). -- Run `pod install --repo-update` in the `ios/` folder to install your Podfile. -- Open the `.xcworkspace` file instead of the `.xcodeproj` file. -- Enter a valid license key in `ViewController.swift` instead of `"YOUR_LICENSE_HERE"`. -- Make sure to fill in the necessary fields `ViewController` for the content integration that will be tested, such as the manifest url and any integration parameters. -- Attach an iOS device, and finally build and run the project. - -### Conclusion - -This document showed how to create a custom DRM integration for iOS using THEOplayer's Content Integration API, -and register it with THEOplayer. The iOS integration API can slightly differ on other platforms, so it is best -to check the platform's specific document. - \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 48e341a0..00000000 --- a/package-lock.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "lockfileVersion": 1 -} diff --git a/resources/android_custom_drm_classes.svg b/resources/android_custom_drm_classes.svg deleted file mode 100644 index a6531968..00000000 --- a/resources/android_custom_drm_classes.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -«interface»ContentProtectionIntegration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()«interface»ContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)CustomContentProtectionIntegration+ configuration: DRMConfiguration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()CustomContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)
creates
creates
DRMConfiguration+ customIntegrationId: String+ integrationParameters: Map<String, String>
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/resources/custom_drm_integration_seq.svg b/resources/custom_drm_integration_seq.svg deleted file mode 100644 index 7a245b31..00000000 --- a/resources/custom_drm_integration_seq.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
opt
opt
CDM
CDM
THEOplayer
THEOplayer
License
Server
License...
request certificate
request certificate
certificate response
certificate response
generate key request
generate key request
ContentProtection
Integration
ContentProtection...
onCertificateRequest()
onCertificateRequest()
altered request
altered request
Content
Server
Content...
encrypted
content
encrypted...
onCertificateResponse()
onCertificateResponse()
altered response
altered response
onLicenseRequest()
onLicenseRequest()
altered request
altered request
request license
request license
license response
license response
onLicenseResponse()
onLicenseResponse()
altered response
altered response
key request
key request
set license key
set license key
decrypt content
decrypt content
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/resources/ios_custom_drm_classes.svg b/resources/ios_custom_drm_classes.svg deleted file mode 100644 index 65a48221..00000000 --- a/resources/ios_custom_drm_classes.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -«interface»ContentProtectionIntegration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()«interface»ContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)CustomContentProtectionIntegration+ configuration: DRMConfiguration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()CustomContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)
creates
creates
DRMConfiguration+ customIntegrationId: String+ integrationParameters: [String : Any]
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/resources/web_custom_drm_classes.svg b/resources/web_custom_drm_classes.svg deleted file mode 100644 index 61705608..00000000 --- a/resources/web_custom_drm_classes.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -«interface»ContentProtectionIntegration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()«interface»ContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)CustomContentProtectionIntegration+ configuration: DRMConfiguration+ onCertificateRequest()+ onCertificateResponse()+ onLicenseRequest()+ onLicenseResponse()CustomContentProtectionIntegrationFactory+ build(configuration: DRMConfiguration)
creates
creates
DRMConfiguration+ customIntegrationId: string+ integrationParameters: { [name: string]: any }
Viewer does not support full SVG 1.1
\ No newline at end of file From 37a5af37f0020c3f97d347b60aaeb8d47c29bbc6 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 14:50:52 +0200 Subject: [PATCH 63/85] Rename folder to drm --- {web => drm}/.eslintrc.json | 0 {web => drm}/README.md | 0 {web => drm}/package-lock.json | 0 {web => drm}/package.json | 0 {web => drm}/rollup.config.js | 0 {web => drm}/src/index.ts | 0 {web => drm}/src/integration/axinomdrm/AxinomDrmConfiguration.ts | 0 .../axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts | 0 .../AxinomDrmFairplayContentProtectionIntegrationFactory.ts | 0 .../axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts | 0 .../AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/axinomdrm/AxinomDrmUtils.ts | 0 .../axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts | 0 .../AxinomDrmWidevineContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/azuredrm/AzureDrmConfiguration.ts | 0 .../azuredrm/AzureDrmFairplayContentProtectionIntegration.ts | 0 .../AzureDrmFairplayContentProtectionIntegrationFactory.ts | 0 .../azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts | 0 .../AzureDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/azuredrm/AzureDrmUtils.ts | 0 .../azuredrm/AzureDrmWidevineContentProtectionIntegration.ts | 0 .../AzureDrmWidevineContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/castlabs/CastLabsDrmConfiguration.ts | 0 .../castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts | 0 .../CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/castlabs/CastLabsDrmUtils.ts | 0 .../src/integration/comcastdrm/ComcastDrmConfiguration.ts | 0 .../comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts | 0 .../ComcastDrmFairPlayContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/comcastdrm/ComcastDrmUtils.ts | 0 .../comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts | 0 .../ComcastDrmWidevineContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/ezdrm/EzdrmDrmConfiguration.ts | 0 .../ezdrm/EzdrmFairplayContentProtectionIntegration.ts | 0 .../ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts | 0 .../src/integration/irdetocontrol/IrdetoControlConfiguration.ts | 0 .../IrdetoControlFairplayContentProtectionIntegration.ts | 0 .../IrdetoControlFairplayContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/keyos/KeyOSDrmConfiguration.ts | 0 .../keyos/KeyOSDrmFairplayContentProtectionIntegration.ts | 0 .../keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts | 0 .../keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts | 0 {web => drm}/src/integration/keyos/KeyOSDrmUtils.ts | 0 .../keyos/KeyOSDrmWidevineContentProtectionIntegration.ts | 0 .../keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts | 0 .../keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/nagradrm/NagraDrmConfiguration.ts | 0 .../nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts | 0 .../NagraDrmFairPlayContentProtectionIntegrationFactory.ts | 0 .../nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts | 0 .../NagraDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/nagradrm/NagraDrmUtils.ts | 0 .../nagradrm/NagraDrmWidevineContentProtectionIntegration.ts | 0 .../NagraDrmWidevineContentProtectionIntegrationFactory.ts | 0 .../src/integration/titaniumdrm/TitaniumBaseRegistration.ts | 0 .../src/integration/titaniumdrm/TitaniumDrmConfiguration.ts | 0 .../titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts | 0 .../TitaniumFairplayContentProtectionIntegrationFactory.ts | 0 .../src/integration/titaniumdrm/TitaniumIntegrationParameters.ts | 0 .../titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts | 0 .../TitaniumPlayReadyContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/titaniumdrm/TitaniumUtils.ts | 0 .../titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts | 0 .../TitaniumWidevineContentProtectionIntegrationFactory.ts | 0 .../verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts | 0 .../VerimatrixCoreDrmFairplayContentProtectionIntegration.ts | 0 ...erimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts | 0 .../VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts | 0 ...rimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 .../VerimatrixCoreDrmWidevineContentProtectionIntegration.ts | 0 ...erimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts | 0 .../verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts | 0 {web => drm}/src/integration/vudrm/VudrmDrmConfiguration.ts | 0 .../vudrm/VudrmFairplayContentProtectionIntegration.ts | 0 .../vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts | 0 .../vudrm/VudrmPlayReadyContentProtectionIntegration.ts | 0 .../vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/integration/vudrm/VudrmUtil.ts | 0 .../vudrm/VudrmWidevineContentProtectionIntegration.ts | 0 .../vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts | 0 {web => drm}/src/utils/FairplayUtils.ts | 0 {web => drm}/src/utils/TypeUtils.ts | 0 {web => drm}/test/axinomdrm/fairplay.html | 0 {web => drm}/test/axinomdrm/playready.html | 0 {web => drm}/test/axinomdrm/widevine.html | 0 {web => drm}/test/azuredrm/fairplay.html | 0 {web => drm}/test/azuredrm/playready.html | 0 {web => drm}/test/azuredrm/widevine.html | 0 {web => drm}/test/castlabs/fairplay.html | 0 {web => drm}/test/castlabs/playready.html | 0 {web => drm}/test/castlabs/widevine.html | 0 {web => drm}/test/comcastdrm/fairplay.html | 0 {web => drm}/test/comcastdrm/playready.html | 0 {web => drm}/test/comcastdrm/style.css | 0 {web => drm}/test/comcastdrm/widevine.html | 0 {web => drm}/test/ezdrm/fairplay.html | 0 {web => drm}/test/irdetocontrol/fairplay.html | 0 {web => drm}/test/irdetocontrol/playready.html | 0 {web => drm}/test/irdetocontrol/widevine.html | 0 {web => drm}/test/keyos/fairplay.html | 0 {web => drm}/test/keyos/playready.html | 0 {web => drm}/test/keyos/widevine.html | 0 {web => drm}/test/nagradrm/fairplay.html | 0 {web => drm}/test/nagradrm/playready.html | 0 {web => drm}/test/nagradrm/style.css | 0 {web => drm}/test/nagradrm/widevine.html | 0 {web => drm}/test/titaniumdrm/fairplay.html | 0 {web => drm}/test/titaniumdrm/playready.html | 0 {web => drm}/test/titaniumdrm/widevine.html | 0 {web => drm}/test/verimatrixcoredrm/fairplay.html | 0 {web => drm}/test/verimatrixcoredrm/playready.html | 0 {web => drm}/test/verimatrixcoredrm/widevine.html | 0 {web => drm}/test/vudrm/fairplay.html | 0 {web => drm}/test/vudrm/playready.html | 0 {web => drm}/test/vudrm/widevine.html | 0 {web => drm}/tsconfig.json | 0 116 files changed, 0 insertions(+), 0 deletions(-) rename {web => drm}/.eslintrc.json (100%) rename {web => drm}/README.md (100%) rename {web => drm}/package-lock.json (100%) rename {web => drm}/package.json (100%) rename {web => drm}/rollup.config.js (100%) rename {web => drm}/src/index.ts (100%) rename {web => drm}/src/integration/axinomdrm/AxinomDrmConfiguration.ts (100%) rename {web => drm}/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/axinomdrm/AxinomDrmUtils.ts (100%) rename {web => drm}/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/azuredrm/AzureDrmConfiguration.ts (100%) rename {web => drm}/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/azuredrm/AzureDrmUtils.ts (100%) rename {web => drm}/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/castlabs/CastLabsDrmConfiguration.ts (100%) rename {web => drm}/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/castlabs/CastLabsDrmUtils.ts (100%) rename {web => drm}/src/integration/comcastdrm/ComcastDrmConfiguration.ts (100%) rename {web => drm}/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/comcastdrm/ComcastDrmUtils.ts (100%) rename {web => drm}/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/ezdrm/EzdrmDrmConfiguration.ts (100%) rename {web => drm}/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/irdetocontrol/IrdetoControlConfiguration.ts (100%) rename {web => drm}/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/keyos/KeyOSDrmConfiguration.ts (100%) rename {web => drm}/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/keyos/KeyOSDrmUtils.ts (100%) rename {web => drm}/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/nagradrm/NagraDrmConfiguration.ts (100%) rename {web => drm}/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/nagradrm/NagraDrmUtils.ts (100%) rename {web => drm}/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumBaseRegistration.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumUtils.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts (100%) rename {web => drm}/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts (100%) rename {web => drm}/src/integration/vudrm/VudrmDrmConfiguration.ts (100%) rename {web => drm}/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/integration/vudrm/VudrmUtil.ts (100%) rename {web => drm}/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts (100%) rename {web => drm}/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts (100%) rename {web => drm}/src/utils/FairplayUtils.ts (100%) rename {web => drm}/src/utils/TypeUtils.ts (100%) rename {web => drm}/test/axinomdrm/fairplay.html (100%) rename {web => drm}/test/axinomdrm/playready.html (100%) rename {web => drm}/test/axinomdrm/widevine.html (100%) rename {web => drm}/test/azuredrm/fairplay.html (100%) rename {web => drm}/test/azuredrm/playready.html (100%) rename {web => drm}/test/azuredrm/widevine.html (100%) rename {web => drm}/test/castlabs/fairplay.html (100%) rename {web => drm}/test/castlabs/playready.html (100%) rename {web => drm}/test/castlabs/widevine.html (100%) rename {web => drm}/test/comcastdrm/fairplay.html (100%) rename {web => drm}/test/comcastdrm/playready.html (100%) rename {web => drm}/test/comcastdrm/style.css (100%) rename {web => drm}/test/comcastdrm/widevine.html (100%) rename {web => drm}/test/ezdrm/fairplay.html (100%) rename {web => drm}/test/irdetocontrol/fairplay.html (100%) rename {web => drm}/test/irdetocontrol/playready.html (100%) rename {web => drm}/test/irdetocontrol/widevine.html (100%) rename {web => drm}/test/keyos/fairplay.html (100%) rename {web => drm}/test/keyos/playready.html (100%) rename {web => drm}/test/keyos/widevine.html (100%) rename {web => drm}/test/nagradrm/fairplay.html (100%) rename {web => drm}/test/nagradrm/playready.html (100%) rename {web => drm}/test/nagradrm/style.css (100%) rename {web => drm}/test/nagradrm/widevine.html (100%) rename {web => drm}/test/titaniumdrm/fairplay.html (100%) rename {web => drm}/test/titaniumdrm/playready.html (100%) rename {web => drm}/test/titaniumdrm/widevine.html (100%) rename {web => drm}/test/verimatrixcoredrm/fairplay.html (100%) rename {web => drm}/test/verimatrixcoredrm/playready.html (100%) rename {web => drm}/test/verimatrixcoredrm/widevine.html (100%) rename {web => drm}/test/vudrm/fairplay.html (100%) rename {web => drm}/test/vudrm/playready.html (100%) rename {web => drm}/test/vudrm/widevine.html (100%) rename {web => drm}/tsconfig.json (100%) diff --git a/web/.eslintrc.json b/drm/.eslintrc.json similarity index 100% rename from web/.eslintrc.json rename to drm/.eslintrc.json diff --git a/web/README.md b/drm/README.md similarity index 100% rename from web/README.md rename to drm/README.md diff --git a/web/package-lock.json b/drm/package-lock.json similarity index 100% rename from web/package-lock.json rename to drm/package-lock.json diff --git a/web/package.json b/drm/package.json similarity index 100% rename from web/package.json rename to drm/package.json diff --git a/web/rollup.config.js b/drm/rollup.config.js similarity index 100% rename from web/rollup.config.js rename to drm/rollup.config.js diff --git a/web/src/index.ts b/drm/src/index.ts similarity index 100% rename from web/src/index.ts rename to drm/src/index.ts diff --git a/web/src/integration/axinomdrm/AxinomDrmConfiguration.ts b/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts similarity index 100% rename from web/src/integration/axinomdrm/AxinomDrmConfiguration.ts rename to drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts diff --git a/web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts rename to drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts diff --git a/web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts diff --git a/web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/axinomdrm/AxinomDrmUtils.ts b/drm/src/integration/axinomdrm/AxinomDrmUtils.ts similarity index 100% rename from web/src/integration/axinomdrm/AxinomDrmUtils.ts rename to drm/src/integration/axinomdrm/AxinomDrmUtils.ts diff --git a/web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts rename to drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts diff --git a/web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/azuredrm/AzureDrmConfiguration.ts b/drm/src/integration/azuredrm/AzureDrmConfiguration.ts similarity index 100% rename from web/src/integration/azuredrm/AzureDrmConfiguration.ts rename to drm/src/integration/azuredrm/AzureDrmConfiguration.ts diff --git a/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts rename to drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts diff --git a/web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts diff --git a/web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/azuredrm/AzureDrmUtils.ts b/drm/src/integration/azuredrm/AzureDrmUtils.ts similarity index 100% rename from web/src/integration/azuredrm/AzureDrmUtils.ts rename to drm/src/integration/azuredrm/AzureDrmUtils.ts diff --git a/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts rename to drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts diff --git a/web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/castlabs/CastLabsDrmConfiguration.ts b/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts similarity index 100% rename from web/src/integration/castlabs/CastLabsDrmConfiguration.ts rename to drm/src/integration/castlabs/CastLabsDrmConfiguration.ts diff --git a/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts rename to drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts diff --git a/web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts rename to drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/castlabs/CastLabsDrmUtils.ts b/drm/src/integration/castlabs/CastLabsDrmUtils.ts similarity index 100% rename from web/src/integration/castlabs/CastLabsDrmUtils.ts rename to drm/src/integration/castlabs/CastLabsDrmUtils.ts diff --git a/web/src/integration/comcastdrm/ComcastDrmConfiguration.ts b/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts similarity index 100% rename from web/src/integration/comcastdrm/ComcastDrmConfiguration.ts rename to drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts diff --git a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts rename to drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts diff --git a/web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts rename to drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/comcastdrm/ComcastDrmUtils.ts b/drm/src/integration/comcastdrm/ComcastDrmUtils.ts similarity index 100% rename from web/src/integration/comcastdrm/ComcastDrmUtils.ts rename to drm/src/integration/comcastdrm/ComcastDrmUtils.ts diff --git a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts rename to drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts diff --git a/web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/ezdrm/EzdrmDrmConfiguration.ts b/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts similarity index 100% rename from web/src/integration/ezdrm/EzdrmDrmConfiguration.ts rename to drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts diff --git a/web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts rename to drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts diff --git a/web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/irdetocontrol/IrdetoControlConfiguration.ts b/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts similarity index 100% rename from web/src/integration/irdetocontrol/IrdetoControlConfiguration.ts rename to drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts diff --git a/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts rename to drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts diff --git a/web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts rename to drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/keyos/KeyOSDrmConfiguration.ts b/drm/src/integration/keyos/KeyOSDrmConfiguration.ts similarity index 100% rename from web/src/integration/keyos/KeyOSDrmConfiguration.ts rename to drm/src/integration/keyos/KeyOSDrmConfiguration.ts diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts rename to drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts diff --git a/web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts diff --git a/web/src/integration/keyos/KeyOSDrmUtils.ts b/drm/src/integration/keyos/KeyOSDrmUtils.ts similarity index 100% rename from web/src/integration/keyos/KeyOSDrmUtils.ts rename to drm/src/integration/keyos/KeyOSDrmUtils.ts diff --git a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts rename to drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts diff --git a/web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/nagradrm/NagraDrmConfiguration.ts b/drm/src/integration/nagradrm/NagraDrmConfiguration.ts similarity index 100% rename from web/src/integration/nagradrm/NagraDrmConfiguration.ts rename to drm/src/integration/nagradrm/NagraDrmConfiguration.ts diff --git a/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts rename to drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts diff --git a/web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts rename to drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts diff --git a/web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/nagradrm/NagraDrmUtils.ts b/drm/src/integration/nagradrm/NagraDrmUtils.ts similarity index 100% rename from web/src/integration/nagradrm/NagraDrmUtils.ts rename to drm/src/integration/nagradrm/NagraDrmUtils.ts diff --git a/web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts rename to drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts diff --git a/web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts b/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumBaseRegistration.ts rename to drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts diff --git a/web/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts b/drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts rename to drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts diff --git a/web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts rename to drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts diff --git a/web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts rename to drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts b/drm/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts rename to drm/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts diff --git a/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts rename to drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts diff --git a/web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/titaniumdrm/TitaniumUtils.ts b/drm/src/integration/titaniumdrm/TitaniumUtils.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumUtils.ts rename to drm/src/integration/titaniumdrm/TitaniumUtils.ts diff --git a/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts rename to drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts diff --git a/web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts rename to drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts similarity index 100% rename from web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts rename to drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts rename to drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts rename to drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts similarity index 100% rename from web/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts rename to drm/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts diff --git a/web/src/integration/vudrm/VudrmDrmConfiguration.ts b/drm/src/integration/vudrm/VudrmDrmConfiguration.ts similarity index 100% rename from web/src/integration/vudrm/VudrmDrmConfiguration.ts rename to drm/src/integration/vudrm/VudrmDrmConfiguration.ts diff --git a/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts rename to drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts diff --git a/web/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts rename to drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts diff --git a/web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/web/src/integration/vudrm/VudrmUtil.ts b/drm/src/integration/vudrm/VudrmUtil.ts similarity index 100% rename from web/src/integration/vudrm/VudrmUtil.ts rename to drm/src/integration/vudrm/VudrmUtil.ts diff --git a/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts similarity index 100% rename from web/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts rename to drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts diff --git a/web/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from web/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts diff --git a/web/src/utils/FairplayUtils.ts b/drm/src/utils/FairplayUtils.ts similarity index 100% rename from web/src/utils/FairplayUtils.ts rename to drm/src/utils/FairplayUtils.ts diff --git a/web/src/utils/TypeUtils.ts b/drm/src/utils/TypeUtils.ts similarity index 100% rename from web/src/utils/TypeUtils.ts rename to drm/src/utils/TypeUtils.ts diff --git a/web/test/axinomdrm/fairplay.html b/drm/test/axinomdrm/fairplay.html similarity index 100% rename from web/test/axinomdrm/fairplay.html rename to drm/test/axinomdrm/fairplay.html diff --git a/web/test/axinomdrm/playready.html b/drm/test/axinomdrm/playready.html similarity index 100% rename from web/test/axinomdrm/playready.html rename to drm/test/axinomdrm/playready.html diff --git a/web/test/axinomdrm/widevine.html b/drm/test/axinomdrm/widevine.html similarity index 100% rename from web/test/axinomdrm/widevine.html rename to drm/test/axinomdrm/widevine.html diff --git a/web/test/azuredrm/fairplay.html b/drm/test/azuredrm/fairplay.html similarity index 100% rename from web/test/azuredrm/fairplay.html rename to drm/test/azuredrm/fairplay.html diff --git a/web/test/azuredrm/playready.html b/drm/test/azuredrm/playready.html similarity index 100% rename from web/test/azuredrm/playready.html rename to drm/test/azuredrm/playready.html diff --git a/web/test/azuredrm/widevine.html b/drm/test/azuredrm/widevine.html similarity index 100% rename from web/test/azuredrm/widevine.html rename to drm/test/azuredrm/widevine.html diff --git a/web/test/castlabs/fairplay.html b/drm/test/castlabs/fairplay.html similarity index 100% rename from web/test/castlabs/fairplay.html rename to drm/test/castlabs/fairplay.html diff --git a/web/test/castlabs/playready.html b/drm/test/castlabs/playready.html similarity index 100% rename from web/test/castlabs/playready.html rename to drm/test/castlabs/playready.html diff --git a/web/test/castlabs/widevine.html b/drm/test/castlabs/widevine.html similarity index 100% rename from web/test/castlabs/widevine.html rename to drm/test/castlabs/widevine.html diff --git a/web/test/comcastdrm/fairplay.html b/drm/test/comcastdrm/fairplay.html similarity index 100% rename from web/test/comcastdrm/fairplay.html rename to drm/test/comcastdrm/fairplay.html diff --git a/web/test/comcastdrm/playready.html b/drm/test/comcastdrm/playready.html similarity index 100% rename from web/test/comcastdrm/playready.html rename to drm/test/comcastdrm/playready.html diff --git a/web/test/comcastdrm/style.css b/drm/test/comcastdrm/style.css similarity index 100% rename from web/test/comcastdrm/style.css rename to drm/test/comcastdrm/style.css diff --git a/web/test/comcastdrm/widevine.html b/drm/test/comcastdrm/widevine.html similarity index 100% rename from web/test/comcastdrm/widevine.html rename to drm/test/comcastdrm/widevine.html diff --git a/web/test/ezdrm/fairplay.html b/drm/test/ezdrm/fairplay.html similarity index 100% rename from web/test/ezdrm/fairplay.html rename to drm/test/ezdrm/fairplay.html diff --git a/web/test/irdetocontrol/fairplay.html b/drm/test/irdetocontrol/fairplay.html similarity index 100% rename from web/test/irdetocontrol/fairplay.html rename to drm/test/irdetocontrol/fairplay.html diff --git a/web/test/irdetocontrol/playready.html b/drm/test/irdetocontrol/playready.html similarity index 100% rename from web/test/irdetocontrol/playready.html rename to drm/test/irdetocontrol/playready.html diff --git a/web/test/irdetocontrol/widevine.html b/drm/test/irdetocontrol/widevine.html similarity index 100% rename from web/test/irdetocontrol/widevine.html rename to drm/test/irdetocontrol/widevine.html diff --git a/web/test/keyos/fairplay.html b/drm/test/keyos/fairplay.html similarity index 100% rename from web/test/keyos/fairplay.html rename to drm/test/keyos/fairplay.html diff --git a/web/test/keyos/playready.html b/drm/test/keyos/playready.html similarity index 100% rename from web/test/keyos/playready.html rename to drm/test/keyos/playready.html diff --git a/web/test/keyos/widevine.html b/drm/test/keyos/widevine.html similarity index 100% rename from web/test/keyos/widevine.html rename to drm/test/keyos/widevine.html diff --git a/web/test/nagradrm/fairplay.html b/drm/test/nagradrm/fairplay.html similarity index 100% rename from web/test/nagradrm/fairplay.html rename to drm/test/nagradrm/fairplay.html diff --git a/web/test/nagradrm/playready.html b/drm/test/nagradrm/playready.html similarity index 100% rename from web/test/nagradrm/playready.html rename to drm/test/nagradrm/playready.html diff --git a/web/test/nagradrm/style.css b/drm/test/nagradrm/style.css similarity index 100% rename from web/test/nagradrm/style.css rename to drm/test/nagradrm/style.css diff --git a/web/test/nagradrm/widevine.html b/drm/test/nagradrm/widevine.html similarity index 100% rename from web/test/nagradrm/widevine.html rename to drm/test/nagradrm/widevine.html diff --git a/web/test/titaniumdrm/fairplay.html b/drm/test/titaniumdrm/fairplay.html similarity index 100% rename from web/test/titaniumdrm/fairplay.html rename to drm/test/titaniumdrm/fairplay.html diff --git a/web/test/titaniumdrm/playready.html b/drm/test/titaniumdrm/playready.html similarity index 100% rename from web/test/titaniumdrm/playready.html rename to drm/test/titaniumdrm/playready.html diff --git a/web/test/titaniumdrm/widevine.html b/drm/test/titaniumdrm/widevine.html similarity index 100% rename from web/test/titaniumdrm/widevine.html rename to drm/test/titaniumdrm/widevine.html diff --git a/web/test/verimatrixcoredrm/fairplay.html b/drm/test/verimatrixcoredrm/fairplay.html similarity index 100% rename from web/test/verimatrixcoredrm/fairplay.html rename to drm/test/verimatrixcoredrm/fairplay.html diff --git a/web/test/verimatrixcoredrm/playready.html b/drm/test/verimatrixcoredrm/playready.html similarity index 100% rename from web/test/verimatrixcoredrm/playready.html rename to drm/test/verimatrixcoredrm/playready.html diff --git a/web/test/verimatrixcoredrm/widevine.html b/drm/test/verimatrixcoredrm/widevine.html similarity index 100% rename from web/test/verimatrixcoredrm/widevine.html rename to drm/test/verimatrixcoredrm/widevine.html diff --git a/web/test/vudrm/fairplay.html b/drm/test/vudrm/fairplay.html similarity index 100% rename from web/test/vudrm/fairplay.html rename to drm/test/vudrm/fairplay.html diff --git a/web/test/vudrm/playready.html b/drm/test/vudrm/playready.html similarity index 100% rename from web/test/vudrm/playready.html rename to drm/test/vudrm/playready.html diff --git a/web/test/vudrm/widevine.html b/drm/test/vudrm/widevine.html similarity index 100% rename from web/test/vudrm/widevine.html rename to drm/test/vudrm/widevine.html diff --git a/web/tsconfig.json b/drm/tsconfig.json similarity index 100% rename from web/tsconfig.json rename to drm/tsconfig.json From 0b33f414846ba291e7fff290ffc4605c6247c4ff Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 15:06:37 +0200 Subject: [PATCH 64/85] Convert to connector template --- drm/.eslintrc.json | 23 - drm/.gitignore | 24 + drm/LICENSE.md | 21 + drm/package-lock.json | 5248 ----------------------------------------- drm/package.json | 74 +- drm/rollup.config.js | 26 - drm/rollup.config.mjs | 13 + drm/tsconfig.json | 74 +- drm/typedoc.json | 12 + 9 files changed, 117 insertions(+), 5398 deletions(-) delete mode 100644 drm/.eslintrc.json create mode 100644 drm/.gitignore create mode 100644 drm/LICENSE.md delete mode 100644 drm/package-lock.json delete mode 100644 drm/rollup.config.js create mode 100644 drm/rollup.config.mjs create mode 100644 drm/typedoc.json diff --git a/drm/.eslintrc.json b/drm/.eslintrc.json deleted file mode 100644 index 1a794348..00000000 --- a/drm/.eslintrc.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint" - ], - "rules": { - "max-len": ["error", { "code": 150, "ignoreComments": true, "ignoreStrings": true, "ignoreTemplateLiterals": true }], - "@typescript-eslint/explicit-module-boundary-types": "off" - } -} diff --git a/drm/.gitignore b/drm/.gitignore new file mode 100644 index 00000000..bf62141d --- /dev/null +++ b/drm/.gitignore @@ -0,0 +1,24 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +lib/ +dist/ + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# THEOplayer build and TypeScript definitions +local/ diff --git a/drm/LICENSE.md b/drm/LICENSE.md new file mode 100644 index 00000000..146db44c --- /dev/null +++ b/drm/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 THEO Technologies NV + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/drm/package-lock.json b/drm/package-lock.json deleted file mode 100644 index 38021daa..00000000 --- a/drm/package-lock.json +++ /dev/null @@ -1,5248 +0,0 @@ -{ - "name": "drm-api-plugins", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "drm-api-plugins", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@types/long": "^4.0.1", - "conditional-type-checks": "^1.0.5", - "lodash": "^4.17.20", - "long": "^4.0.0" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^15.0.0", - "@rollup/plugin-node-resolve": "^9.0.0", - "@rollup/plugin-typescript": "^5.0.2", - "@types/lodash": "^4.14.161", - "@types/node": "^14.6.3", - "@typescript-eslint/eslint-plugin": "^4.0.1", - "@typescript-eslint/parser": "^4.0.1", - "eslint": "^7.8.1", - "eslint-config-airbnb-base": "^14.2.0", - "eslint-plugin-import": "^2.22.0", - "http-server": "^0.12.3", - "rollup": "^2.26.9", - "rollup-plugin-copy": "^3.4.0", - "theoplayer": "latest", - "ts-node": "^9.0.0", - "tslib": "^2.0.1", - "typescript": "^4.0.2" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "node_modules/@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", - "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz", - "integrity": "sha512-8uAdikHqVyrT32w1zB9VhW6uGwGjhKgnDNP4pQJsjdnyF4FgCj6/bmv24c7v2CuKhq32CcyCwRzMPEElaKkn0w==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^2.22.0" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz", - "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-5.0.2.tgz", - "integrity": "sha512-CkS028Itwjqm1uLbFVfpJgtVtnNvZ+og/m6UlNRR5wOOnNTWPcVQzOu5xGdEX+WWJxdvWIqUq2uR/RBt2ZipWg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.0.1", - "resolve": "^1.14.1" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "rollup": "^2.14.0", - "tslib": "*", - "typescript": ">=3.4.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@types/fs-extra": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", - "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "node_modules/@types/lodash": { - "version": "4.14.161", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", - "integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA==", - "dev": true - }, - "node_modules/@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "14.6.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz", - "integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz", - "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "4.0.1", - "@typescript-eslint/scope-manager": "4.0.1", - "debug": "^4.1.1", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz", - "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz", - "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", - "debug": "^4.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz", - "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz", - "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==", - "dev": true, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz", - "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz", - "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.0.1", - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", - "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "dependencies": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/conditional-type-checks": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/conditional-type-checks/-/conditional-type-checks-1.0.5.tgz", - "integrity": "sha512-DkfkvmjXVe4ye4llJ1JADtO3dNvqqcQM08cA9BhNt9Oe8pyRW8X1CZyBg9Qst05bDV9BJM01KLmnFh78NcJgNg==" - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", - "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", - "dev": true - }, - "node_modules/contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/corser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", - "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/ecstatic": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", - "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", - "deprecated": "This package is unmaintained and deprecated. See the GH Issue 259.", - "dev": true, - "dependencies": { - "he": "^1.1.1", - "mime": "^1.6.0", - "minimist": "^1.1.0", - "url-join": "^2.0.5" - }, - "bin": { - "ecstatic": "lib/ecstatic.js" - } - }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "dependencies": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", - "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.1.3", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^1.3.0", - "espree": "^7.3.0", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", - "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.9", - "object.assign": "^4.1.0", - "object.entries": "^1.1.2" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", - "eslint-plugin-import": "^2.21.2" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "dependencies": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", - "dev": true, - "dependencies": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-module-utils/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-plugin-import": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", - "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.3", - "eslint-module-utils": "^2.6.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "dependencies": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", - "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", - "dev": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "dependencies": { - "flat-cache": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - } - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "dependencies": { - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-server": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", - "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", - "dev": true, - "dependencies": { - "basic-auth": "^1.0.3", - "colors": "^1.4.0", - "corser": "^2.0.1", - "ecstatic": "^3.3.2", - "http-proxy": "^1.18.0", - "minimist": "^1.2.5", - "opener": "^1.5.1", - "portfinder": "^1.0.25", - "secure-compare": "3.0.1", - "union": "~0.5.0" - }, - "bin": { - "hs": "bin/http-server", - "http-server": "bin/http-server" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", - "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.entries": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", - "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true, - "bin": { - "opener": "bin/opener-bin.js" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", - "dev": true, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "dependencies": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "dependencies": { - "pify": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/rollup": { - "version": "2.26.9", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.9.tgz", - "integrity": "sha512-XIiWYLayLqV+oY4S2Lub/shJq4uk/QQLwWToYCL4LjZbYHbFK3czea4UDVRUJu+zNmKmxq5Zb/OG7c5HSvH2TQ==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.1.2" - } - }, - "node_modules/rollup-plugin-copy": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", - "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", - "dev": true, - "dependencies": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "engines": { - "node": ">=8.3" - } - }, - "node_modules/rollup-plugin-copy/node_modules/globby": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", - "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", - "dev": true, - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "node_modules/secure-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", - "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", - "dev": true - }, - "node_modules/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/theoplayer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-3.0.0.tgz", - "integrity": "sha512-tYeFmEAgMYEBQENfK5/7MRsMM1CecOrsvuoFrfPC0hvWTA26nr2anog9xqEN8z9RVBFLso7UPzybDIVOg2Dw/w==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-node": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", - "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", - "dev": true, - "dependencies": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "typescript": ">=2.7" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tslib": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", - "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/typescript": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", - "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/union": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", - "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", - "dev": true, - "dependencies": { - "qs": "^6.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-join": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", - "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", - "dev": true - }, - "node_modules/v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "@eslint/eslintrc": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", - "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - } - }, - "@rollup/plugin-commonjs": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz", - "integrity": "sha512-8uAdikHqVyrT32w1zB9VhW6uGwGjhKgnDNP4pQJsjdnyF4FgCj6/bmv24c7v2CuKhq32CcyCwRzMPEElaKkn0w==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - } - }, - "@rollup/plugin-node-resolve": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz", - "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.17.0" - } - }, - "@rollup/plugin-typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-5.0.2.tgz", - "integrity": "sha512-CkS028Itwjqm1uLbFVfpJgtVtnNvZ+og/m6UlNRR5wOOnNTWPcVQzOu5xGdEX+WWJxdvWIqUq2uR/RBt2ZipWg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.0.1", - "resolve": "^1.14.1" - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - } - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "@types/fs-extra": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", - "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/lodash": { - "version": "4.14.161", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", - "integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA==", - "dev": true - }, - "@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "@types/node": { - "version": "14.6.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.3.tgz", - "integrity": "sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww==", - "dev": true - }, - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@typescript-eslint/eslint-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz", - "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "4.0.1", - "@typescript-eslint/scope-manager": "4.0.1", - "debug": "^4.1.1", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/experimental-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz", - "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz", - "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", - "debug": "^4.1.1" - } - }, - "@typescript-eslint/scope-manager": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz", - "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1" - } - }, - "@typescript-eslint/types": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz", - "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz", - "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz", - "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.0.1", - "eslint-visitor-keys": "^2.0.0" - } - }, - "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", - "dev": true - }, - "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true, - "requires": {} - }, - "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "builtin-modules": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", - "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "conditional-type-checks": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/conditional-type-checks/-/conditional-type-checks-1.0.5.tgz", - "integrity": "sha512-DkfkvmjXVe4ye4llJ1JADtO3dNvqqcQM08cA9BhNt9Oe8pyRW8X1CZyBg9Qst05bDV9BJM01KLmnFh78NcJgNg==" - }, - "confusing-browser-globals": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", - "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "corser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", - "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ecstatic": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", - "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", - "dev": true, - "requires": { - "he": "^1.1.1", - "mime": "^1.6.0", - "minimist": "^1.1.0", - "url-join": "^2.0.5" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", - "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.1.3", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^1.3.0", - "espree": "^7.3.0", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - } - } - }, - "eslint-config-airbnb-base": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", - "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", - "dev": true, - "requires": { - "confusing-browser-globals": "^1.0.9", - "object.assign": "^4.1.0", - "object.entries": "^1.1.2" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-plugin-import": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", - "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", - "dev": true, - "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.3", - "eslint-module-utils": "^2.6.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - }, - "espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "estree-walker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", - "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-server": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", - "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", - "dev": true, - "requires": { - "basic-auth": "^1.0.3", - "colors": "^1.4.0", - "corser": "^2.0.1", - "ecstatic": "^3.3.2", - "http-proxy": "^1.18.0", - "minimist": "^1.2.5", - "opener": "^1.5.1", - "portfinder": "^1.0.25", - "secure-compare": "3.0.1", - "union": "~0.5.0" - } - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", - "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", - "dev": true - }, - "is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.entries": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", - "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "has": "^1.0.3" - } - }, - "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "dependencies": { - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - } - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "2.26.9", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.9.tgz", - "integrity": "sha512-XIiWYLayLqV+oY4S2Lub/shJq4uk/QQLwWToYCL4LjZbYHbFK3czea4UDVRUJu+zNmKmxq5Zb/OG7c5HSvH2TQ==", - "dev": true, - "requires": { - "fsevents": "~2.1.2" - } - }, - "rollup-plugin-copy": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", - "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", - "dev": true, - "requires": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "dependencies": { - "globby": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", - "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - } - } - } - }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "secure-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", - "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", - "dev": true - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "theoplayer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-3.0.0.tgz", - "integrity": "sha512-tYeFmEAgMYEBQENfK5/7MRsMM1CecOrsvuoFrfPC0hvWTA26nr2anog9xqEN8z9RVBFLso7UPzybDIVOg2Dw/w==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "ts-node": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", - "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", - "dev": true, - "requires": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - } - }, - "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "tslib": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", - "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==", - "dev": true - }, - "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - } - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "typescript": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", - "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", - "dev": true - }, - "union": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", - "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", - "dev": true, - "requires": { - "qs": "^6.4.0" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-join": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", - "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - } - } -} diff --git a/drm/package.json b/drm/package.json index 2adf048c..f60068e7 100644 --- a/drm/package.json +++ b/drm/package.json @@ -1,43 +1,47 @@ { - "name": "drm-api-plugins", + "name": "@theoplayer/drm-connectors-web", "version": "1.0.0", - "description": "THEOplayer samples for DRM integrations", - "main": "index.js", - "scripts": { - "server": "http-server", - "build": "rollup -c ./rollup.config.js", - "eslint": "eslint 'src/**/*.ts'" - }, + "description": "External DRM connectors for the THEOplayer Web SDK", + "main": "dist/drm-connectors.umd.js", "repository": { "type": "git", - "url": "git+ssh://git@bitbucket.org/r8szq0vy/drm-api-plugin.git" + "url": "git+https://github.com/THEOplayer/web-connectors.git", + "directory": "drm" + }, + "bugs": { + "url": "https://github.com/THEOplayer/web-connectors/issues" }, - "author": "", - "license": "ISC", - "homepage": "https://bitbucket.org/r8szq0vy/drm-api-plugin#readme", - "devDependencies": { - "@rollup/plugin-commonjs": "^15.0.0", - "@rollup/plugin-node-resolve": "^9.0.0", - "@rollup/plugin-typescript": "^5.0.2", - "@types/lodash": "^4.14.161", - "@types/node": "^14.6.3", - "@typescript-eslint/eslint-plugin": "^4.0.1", - "@typescript-eslint/parser": "^4.0.1", - "eslint": "^7.8.1", - "eslint-config-airbnb-base": "^14.2.0", - "eslint-plugin-import": "^2.22.0", - "http-server": "^0.12.3", - "rollup": "^2.26.9", - "rollup-plugin-copy": "^3.4.0", - "theoplayer": "latest", - "ts-node": "^9.0.0", - "tslib": "^2.0.1", - "typescript": "^4.0.2" + "homepage": "https://github.com/THEOplayer/web-connectors/tree/main/drm#readme", + "module": "dist/drm-connectors.esm.js", + "types": "dist/types/index.d.ts", + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/drm-connectors.esm.js", + "require": "./dist/drm-connectors.umd.js" + }, + "./dist/*": "./dist/*", + "./package": "./package.json", + "./package.json": "./package.json" + }, + "scripts": { + "clean": "rimraf lib dist", + "bundle": "rollup -c rollup.config.mjs", + "build": "npm run clean && npm run bundle", + "watch": "npm run bundle -- --watch", + "serve": "http-server", + "test": "jest" }, - "dependencies": { - "@types/long": "^4.0.1", - "conditional-type-checks": "^1.0.5", - "lodash": "^4.17.20", - "long": "^4.0.0" + "author": "THEO Technologies NV", + "license": "MIT", + "files": [ + "dist/", + "CHANGELOG.md", + "README.md", + "LICENSE.md", + "package.json" + ], + "peerDependencies": { + "theoplayer": "^7.0.0" } } diff --git a/drm/rollup.config.js b/drm/rollup.config.js deleted file mode 100644 index 18f59b46..00000000 --- a/drm/rollup.config.js +++ /dev/null @@ -1,26 +0,0 @@ -import commonJs from "@rollup/plugin-commonjs"; -import resolve from "@rollup/plugin-node-resolve"; -import copy from 'rollup-plugin-copy'; -import typescript from "@rollup/plugin-typescript"; - -export default { - input: "src/index.ts", - output: { - file: "dist/bundle.js", - format: "iife", - exports: "auto", - name: "ContentProtectionIntegrations", - globals: { THEOplayer: 'THEOplayer' } - }, - external: ['THEOplayer'], - plugins: [ - resolve(), - commonJs({ extensions: [".js", ".ts"] }), - copy({ - targets: [ - { src: './node_modules/theoplayer/*.(js|css|html|ts|wasm)' , dest: './THEOplayer' } - ] - }), - typescript() - ], -}; diff --git a/drm/rollup.config.mjs b/drm/rollup.config.mjs new file mode 100644 index 00000000..6ae512bc --- /dev/null +++ b/drm/rollup.config.mjs @@ -0,0 +1,13 @@ +import fs from "node:fs"; +import {getSharedBuildConfiguration} from "../tools/build.mjs"; + +const {version} = JSON.parse(fs.readFileSync("./package.json", "utf8")); + +const fileName = "drm-connectors"; +const globalName = "THEOplayerDrmConnector"; +const banner = ` +/** + * THEOplayer DRM Connectors v${version} + */`.trim(); + +export default getSharedBuildConfiguration({ fileName, globalName, banner }); diff --git a/drm/tsconfig.json b/drm/tsconfig.json index 5f846b79..d416c1ae 100644 --- a/drm/tsconfig.json +++ b/drm/tsconfig.json @@ -1,69 +1,11 @@ { + "extends": "../tsconfig.base.json", "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - "lib": ["es6", "dom"], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - // "outDir": "./", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - "paths": {"THEOplayer": ["./THEOplayer/THEOplayer"]}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - - /* Advanced Options */ - "skipLibCheck": true, /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - } + "rootDir": "src", + "outDir": "dist", + "declarationDir": "dist/types" + }, + "include": [ + "src/**/*" + ] } diff --git a/drm/typedoc.json b/drm/typedoc.json new file mode 100644 index 00000000..14821d3f --- /dev/null +++ b/drm/typedoc.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "extends": [ + "../typedoc.base.json" + ], + "entryPoints": [ + "src/index.ts" + ], + "tsconfig": "tsconfig.json", + "readme": "README.md", + "name": "DRM Connectors" +} From ea03192839e590716c4a45b79e8ca35862c1ac7a Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 15:35:03 +0200 Subject: [PATCH 65/85] Add to workspace --- package-lock.json | 18 +++++++++++++++--- package.json | 3 ++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d017d80..1e44c2f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "conviva", "nielsen", "cmcd", - "comscore" + "comscore", + "drm" ], "devDependencies": { "@changesets/cli": "^2.27.1", @@ -60,7 +61,7 @@ }, "conviva": { "name": "@theoplayer/conviva-connector-web", - "version": "2.1.1", + "version": "2.1.3", "license": "MIT", "devDependencies": { "@convivainc/conviva-js-coresdk": "^4.7.4" @@ -76,6 +77,13 @@ } } }, + "drm": { + "version": "1.0.0", + "license": "MIT", + "peerDependencies": { + "theoplayer": "^7.0.0" + } + }, "nielsen": { "name": "@theoplayer/nielsen-connector-web", "version": "1.1.2", @@ -2408,6 +2416,10 @@ "resolved": "conviva", "link": true }, + "node_modules/@theoplayer/drm-connectors-web": { + "resolved": "drm", + "link": true + }, "node_modules/@theoplayer/nielsen-connector-web": { "resolved": "nielsen", "link": true @@ -8737,7 +8749,7 @@ }, "yospace": { "name": "@theoplayer/yospace-connector-web", - "version": "2.2.0", + "version": "2.3.0", "license": "MIT", "peerDependencies": { "theoplayer": "^5.0.0 || ^6.0.0 || ^7.0.0" diff --git a/package.json b/package.json index 14a91e11..56bbe74e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "conviva", "nielsen", "cmcd", - "comscore" + "comscore", + "drm" ], "scripts": { "changeset:version": "changeset version && node .changeset/post-process.js", From cfadfe0d300eb062d48bfe3cd0fa7a5f4480a2f0 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 15:35:09 +0200 Subject: [PATCH 66/85] Remove jest --- drm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drm/package.json b/drm/package.json index f60068e7..32b7f854 100644 --- a/drm/package.json +++ b/drm/package.json @@ -30,7 +30,7 @@ "build": "npm run clean && npm run bundle", "watch": "npm run bundle -- --watch", "serve": "http-server", - "test": "jest" + "test": "echo \"No tests yet\"" }, "author": "THEO Technologies NV", "license": "MIT", From 00127d4e0683f072bc9b873db58db4207435eac1 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 15:35:23 +0200 Subject: [PATCH 67/85] Add exclude --- .idea/web-connectors.iml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/web-connectors.iml b/.idea/web-connectors.iml index 447c428e..e2db7899 100644 --- a/.idea/web-connectors.iml +++ b/.idea/web-connectors.iml @@ -10,6 +10,7 @@ + From 0eae5a62ac567214c86c0a216fc707857039e65e Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 15:36:29 +0200 Subject: [PATCH 68/85] Change version --- drm/package.json | 2 +- package-lock.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drm/package.json b/drm/package.json index 32b7f854..48e508b5 100644 --- a/drm/package.json +++ b/drm/package.json @@ -1,6 +1,6 @@ { "name": "@theoplayer/drm-connectors-web", - "version": "1.0.0", + "version": "0.0.0", "description": "External DRM connectors for the THEOplayer Web SDK", "main": "dist/drm-connectors.umd.js", "repository": { diff --git a/package-lock.json b/package-lock.json index 1e44c2f2..8a2afba9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,7 +78,8 @@ } }, "drm": { - "version": "1.0.0", + "name": "@theoplayer/drm-connectors-web", + "version": "0.0.0", "license": "MIT", "peerDependencies": { "theoplayer": "^7.0.0" From 70d8a520a99896beb7300725fbdd535a43a76eab Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 15:37:15 +0200 Subject: [PATCH 69/85] Run prettier --- comscore/src/comscore/ComScore.d.ts | 506 +++++++++--------- drm/src/index.ts | 80 +-- .../axinomdrm/AxinomDrmConfiguration.ts | 3 +- ...DrmFairplayContentProtectionIntegration.ts | 11 +- ...playContentProtectionIntegrationFactory.ts | 9 +- ...rmPlayReadyContentProtectionIntegration.ts | 10 +- ...eadyContentProtectionIntegrationFactory.ts | 9 +- .../integration/axinomdrm/AxinomDrmUtils.ts | 2 +- ...DrmWidevineContentProtectionIntegration.ts | 10 +- ...vineContentProtectionIntegrationFactory.ts | 9 +- .../azuredrm/AzureDrmConfiguration.ts | 3 +- ...DrmFairplayContentProtectionIntegration.ts | 4 +- ...playContentProtectionIntegrationFactory.ts | 5 +- ...rmPlayReadyContentProtectionIntegration.ts | 8 +- ...eadyContentProtectionIntegrationFactory.ts | 5 +- drm/src/integration/azuredrm/AzureDrmUtils.ts | 2 +- ...DrmWidevineContentProtectionIntegration.ts | 8 +- ...vineContentProtectionIntegrationFactory.ts | 5 +- .../castlabs/CastLabsDrmConfiguration.ts | 4 +- ...DrmFairPlayContentProtectionIntegration.ts | 11 +- ...PlayContentProtectionIntegrationFactory.ts | 5 +- .../integration/castlabs/CastLabsDrmUtils.ts | 8 +- .../comcastdrm/ComcastDrmConfiguration.ts | 4 +- ...DrmFairPlayContentProtectionIntegration.ts | 32 +- ...PlayContentProtectionIntegrationFactory.ts | 5 +- .../integration/comcastdrm/ComcastDrmUtils.ts | 8 +- ...DrmWidevineContentProtectionIntegration.ts | 30 +- ...vineContentProtectionIntegrationFactory.ts | 5 +- .../ezdrm/EzdrmDrmConfiguration.ts | 3 +- ...drmFairplayContentProtectionIntegration.ts | 20 +- ...playContentProtectionIntegrationFactory.ts | 7 +- .../IrdetoControlConfiguration.ts | 3 +- ...rolFairplayContentProtectionIntegration.ts | 51 +- ...playContentProtectionIntegrationFactory.ts | 5 +- .../keyos/KeyOSDrmConfiguration.ts | 3 +- ...DrmFairplayContentProtectionIntegration.ts | 20 +- ...playContentProtectionIntegrationFactory.ts | 9 +- ...rmPlayReadyContentProtectionIntegration.ts | 10 +- drm/src/integration/keyos/KeyOSDrmUtils.ts | 6 +- ...DrmWidevineContentProtectionIntegration.ts | 10 +- ...vineContentProtectionIntegrationFactory.ts | 9 +- ...eadyContentProtectionIntegrationFactory.ts | 9 +- .../nagradrm/NagraDrmConfiguration.ts | 2 +- ...DrmFairPlayContentProtectionIntegration.ts | 46 +- ...PlayContentProtectionIntegrationFactory.ts | 12 +- ...rmPlayReadyContentProtectionIntegration.ts | 37 +- ...eadyContentProtectionIntegrationFactory.ts | 12 +- drm/src/integration/nagradrm/NagraDrmUtils.ts | 6 +- ...DrmWidevineContentProtectionIntegration.ts | 37 +- ...vineContentProtectionIntegrationFactory.ts | 12 +- .../titaniumdrm/TitaniumBaseRegistration.ts | 30 +- ...iumFairplayContentProtectionIntegration.ts | 2 +- ...umPlayReadyContentProtectionIntegration.ts | 4 +- .../integration/titaniumdrm/TitaniumUtils.ts | 11 +- ...iumWidevineContentProtectionIntegration.ts | 4 +- .../VerimatrixCoreDrmConfiguration.ts | 10 +- ...DrmFairplayContentProtectionIntegration.ts | 71 +-- ...playContentProtectionIntegrationFactory.ts | 10 +- ...rmPlayReadyContentProtectionIntegration.ts | 24 +- ...eadyContentProtectionIntegrationFactory.ts | 10 +- ...DrmWidevineContentProtectionIntegration.ts | 40 +- ...vineContentProtectionIntegrationFactory.ts | 10 +- .../VerimatrixCoreIntegrationParameters.ts | 10 +- ...drmFairplayContentProtectionIntegration.ts | 12 +- ...playContentProtectionIntegrationFactory.ts | 7 +- ...rmPlayReadyContentProtectionIntegration.ts | 16 +- ...eadyContentProtectionIntegrationFactory.ts | 9 +- drm/src/integration/vudrm/VudrmUtil.ts | 2 +- ...drmWidevineContentProtectionIntegration.ts | 16 +- ...vineContentProtectionIntegrationFactory.ts | 5 +- drm/src/utils/FairplayUtils.ts | 2 +- drm/src/utils/TypeUtils.ts | 8 +- drm/test/axinomdrm/fairplay.html | 86 +-- drm/test/axinomdrm/playready.html | 84 +-- drm/test/axinomdrm/widevine.html | 84 +-- drm/test/azuredrm/fairplay.html | 86 +-- drm/test/azuredrm/playready.html | 84 +-- drm/test/azuredrm/widevine.html | 84 +-- drm/test/castlabs/fairplay.html | 106 ++-- drm/test/castlabs/playready.html | 97 ++-- drm/test/castlabs/widevine.html | 95 ++-- drm/test/comcastdrm/fairplay.html | 210 ++++---- drm/test/comcastdrm/playready.html | 195 +++---- drm/test/comcastdrm/style.css | 2 +- drm/test/comcastdrm/widevine.html | 262 +++++---- drm/test/ezdrm/fairplay.html | 82 +-- drm/test/irdetocontrol/fairplay.html | 109 ++-- drm/test/irdetocontrol/playready.html | 78 +-- drm/test/irdetocontrol/widevine.html | 78 +-- drm/test/keyos/fairplay.html | 90 ++-- drm/test/keyos/playready.html | 87 +-- drm/test/keyos/widevine.html | 87 +-- drm/test/nagradrm/fairplay.html | 189 +++---- drm/test/nagradrm/playready.html | 211 ++++---- drm/test/nagradrm/style.css | 2 +- drm/test/nagradrm/widevine.html | 211 ++++---- drm/test/titaniumdrm/fairplay.html | 126 ++--- drm/test/titaniumdrm/playready.html | 126 ++--- drm/test/titaniumdrm/widevine.html | 130 ++--- drm/test/verimatrixcoredrm/fairplay.html | 97 ++-- drm/test/verimatrixcoredrm/playready.html | 94 ++-- drm/test/verimatrixcoredrm/widevine.html | 94 ++-- drm/test/vudrm/fairplay.html | 86 +-- drm/test/vudrm/playready.html | 84 +-- drm/test/vudrm/widevine.html | 86 +-- 105 files changed, 2413 insertions(+), 2652 deletions(-) diff --git a/comscore/src/comscore/ComScore.d.ts b/comscore/src/comscore/ComScore.d.ts index de717661..92623965 100644 --- a/comscore/src/comscore/ComScore.d.ts +++ b/comscore/src/comscore/ComScore.d.ts @@ -1,265 +1,263 @@ declare namespace ns_ { namespace analytics { - enum ConnectivityType { - UNKNOWN, - UNAVAILABLE, - DISCONNECTED, - CONNECTED, - ETHERNET, - WIFI, - WWAN, - BLUETOOTH, - EMULATOR - } - - enum PlatformAPIs { - SmartTV, - Netcast, - Cordova, - Trilithium, - AppleTV, - Chromecast, - Xbox, - webOS, - tvOS, - nodejs, - html5, - JSMAF, - Skeleton, - WebBrowser - } - - namespace PlatformApi { - function setPlatformAPI(platformApi: PlatformAPIs): void; - function setPlatformAPI(platformApi: PlatformAPIs, interfaceObject: unknown): void; - function setPlatformApi(platformApi: PlatformAPIs, interfaceObject: unknown): void; - } - - class StreamingAnalytics { - setMediaPlayerName(name: string): void; - setMediaPlayerVersion(version: string): void; - createPlaybackSession(): void - getPlaybackSessionId(): void - loopPlaybackSession(): void - notifyBufferStart(): void - notifyBufferStop(): void - notifyChangePlaybackRate(rate: number): void; - notifyEnd(): void - notifyPause(): void - notifyPlay(): void - notifySeekStart(): void - setDvrWindowLength(length: number): void; - setImplementationId(id: string): void; - setMetadata(metadata: any): void; - setProjectId(id: string): void; - startFromDvrWindowOffset(offset: number): void; - startFromPosition(position: number): void; - startFromSegment(segment: any): void; - constructor(); - } - - namespace StreamingAnalytics { - namespace AdvertisementMetadata { - export enum AdvertisementType { - ON_DEMAND_PRE_ROLL, - ON_DEMAND_MID_ROLL, - ON_DEMAND_POST_ROLL, - LIVE, - BRANDED_ON_DEMAND_PRE_ROLL, - BRANDED_ON_DEMAND_MID_ROLL, - BRANDED_ON_DEMAND_POST_ROLL, - BRANDED_AS_CONTENT, - BRANDED_DURING_LIVE, - OTHER, - } + enum ConnectivityType { + UNKNOWN, + UNAVAILABLE, + DISCONNECTED, + CONNECTED, + ETHERNET, + WIFI, + WWAN, + BLUETOOTH, + EMULATOR + } - export enum AdvertisementDeliveryType { - NATIONAL, - LOCAL, - SYNDICATION - } - } - - class AdvertisementMetadata { - addCustomLabels(labels: any): void; - classifyAsAudioStream(isAudio: boolean): void; - setCallToActionUrl(url: string): void; - setClipUrl(url: string): void; - setDeliveryType(type: StreamingAnalytics.AdvertisementMetadata.AdvertisementDeliveryType): void; - setLength(length: number): void; - setMediaType(type: StreamingAnalytics.AdvertisementMetadata.AdvertisementType): void; - setOwner(owner: string): void; - setPlacementId(id: string): void; - setRelatedContentMetadata(metadata: any): void; - setServer(server: string): void; - setServerCampaignId(id: string): void; - setSiteId(id: string): void; - setTitle(title: string): void; - setUniqueId(id: string): void; - setVideoDimensions(width: number, height: number): void; - - getMetadataLabels(): any; - - - constructor(); - } - - namespace ContentMetadata { - - export enum ContentDeliveryAdvertisementCapability { - NONE, - DYNAMIC_LOAD, - DYNAMIC_REPLACEMENT, - LINEAR_1DAY, - LINEAR_2DAY, - LINEAR_3DAY, - LINEAR_4DAY, - LINEAR_5DAY, - LINEAR_6DAY, - LINEAR_7DAY - } - - export enum ContentDeliveryComposition { - CLEAN, - EMBED - } - - export enum ContentDeliveryMode { - LINEAR, - ON_DEMAND - } - - export enum ContentDeliverySubscriptionType { - ADVERTISING, - PREMIUM, - SUBSCRIPTION, - TRADITIONAL_MVPD, - TRANSACTIONAL, - VIRTUAL_MVPD, - } - - export enum ContentDistributionModel { - EXCLUSIVELY_ONLINE, - TV_AND_ONLINE - } - - export enum ContentFeedType { - EAST_HD, - EAST_SD, - OTHER, - WEST_HD, - WEST_SD - } - - export enum ContentMediaFormat { - EXTRA_EPISODE, - EXTRA_GENERIC, - EXTRA_MOVIE, - FULL_CONTENT_EPISODE, - FULL_CONTENT_GENERIC, - FULL_CONTENT_MOVIE, - PARTIAL_CONTENT_EPISODE, - PARTIAL_CONTENT_GENERIC, - PARTIAL_CONTENT_MOVIE, - PREVIEW_EPISODE, - PREVIEW_GENERIC, - PREVIEW_MOVIE - } - - export enum ContentType { - LONG_FORM_ON_DEMAND, - SHORT_FORM_ON_DEMAND, - LIVE, - USER_GENERATED_SHORT_FORM_ON_DEMAND, - USER_GENERATED_LONG_FORM_ON_DEMAND, - USER_GENERATED_LIVE, - BUMPER, - OTHER, - } + enum PlatformAPIs { + SmartTV, + Netcast, + Cordova, + Trilithium, + AppleTV, + Chromecast, + Xbox, + webOS, + tvOS, + nodejs, + html5, + JSMAF, + Skeleton, + WebBrowser + } + + namespace PlatformApi { + function setPlatformAPI(platformApi: PlatformAPIs): void; + function setPlatformAPI(platformApi: PlatformAPIs, interfaceObject: unknown): void; + function setPlatformApi(platformApi: PlatformAPIs, interfaceObject: unknown): void; } - - class ContentMetadata { - addCustomLabels(labels: any): void; - carryTvAdvertisementLoad(carriesTvAdvertisementLoad: boolean): void; - classifyAsAudioStream(audioStream: boolean): void; - classifyAsCompleteEpisode(completeEpisode: boolean): void; - setClipUrl(url: string): void; - setDateOfDigitalAiring(year: number, month: number, day: number): void; - setDateOfProduction(year: number, month: number, day: number): void; - setDateOfTvAiring(year: number, month: number, day: number): void; - setDeliveryAdvertisementCapability(value: StreamingAnalytics.ContentMetadata.ContentDeliveryAdvertisementCapability): void; - setDeliveryComposition(value: StreamingAnalytics.ContentMetadata.ContentDeliveryComposition): void; - setDeliveryMode(value: StreamingAnalytics.ContentMetadata.ContentDeliveryMode): void; - setDeliverySubscriptionType(value: StreamingAnalytics.ContentMetadata.ContentDeliverySubscriptionType): void; - setDictionaryClassificationC3(value: string): void; - setDictionaryClassificationC4(value: string): void; - setDictionaryClassificationC6(value: string): void; - setDistributionModel(value: StreamingAnalytics.ContentMetadata.ContentDistributionModel): void; - setEpisodeId(id: string): void; - setEpisodeNumber(episodeNumber: string): void; - setEpisodeSeasonNumber(seasonNumber: string): void; - setEpisodeTitle(title: string): void; - setFeedType(value: StreamingAnalytics.ContentMetadata.ContentFeedType): void; - setGenreId(id: string): void; - setGenreName(name: string): void; - setLength(length: number): void; - setMediaFormat(value: StreamingAnalytics.ContentMetadata.ContentMediaFormat): void; - setMediaType(value: StreamingAnalytics.ContentMetadata.ContentType): void; - setNetworkAffiliate(code: string): void; - setPlaylistTitle(title: string): void; - setProgramId(id: string): void; - setProgramTitle(title: string): void; - setPublisherName(name: string): void; - setStationCode(code: string): void; - setStationTitle(title: string): void; - setTimeOfDigitalAiring(hours: number, minutes: number): void; - setTimeOfProduction(hours: number, minutes: number): void; - setTimeOfTvAiring(hours: number, minutes: number): void; - setTotalSegments(total: number): void; - setUniqueId(id: string): void; - setVideoDimensions(width: number, height: number): void; - - getMetadataLabels(): any; - + + class StreamingAnalytics { + setMediaPlayerName(name: string): void; + setMediaPlayerVersion(version: string): void; + createPlaybackSession(): void; + getPlaybackSessionId(): void; + loopPlaybackSession(): void; + notifyBufferStart(): void; + notifyBufferStop(): void; + notifyChangePlaybackRate(rate: number): void; + notifyEnd(): void; + notifyPause(): void; + notifyPlay(): void; + notifySeekStart(): void; + setDvrWindowLength(length: number): void; + setImplementationId(id: string): void; + setMetadata(metadata: any): void; + setProjectId(id: string): void; + startFromDvrWindowOffset(offset: number): void; + startFromPosition(position: number): void; + startFromSegment(segment: any): void; constructor(); + } + + namespace StreamingAnalytics { + namespace AdvertisementMetadata { + export enum AdvertisementType { + ON_DEMAND_PRE_ROLL, + ON_DEMAND_MID_ROLL, + ON_DEMAND_POST_ROLL, + LIVE, + BRANDED_ON_DEMAND_PRE_ROLL, + BRANDED_ON_DEMAND_MID_ROLL, + BRANDED_ON_DEMAND_POST_ROLL, + BRANDED_AS_CONTENT, + BRANDED_DURING_LIVE, + OTHER + } + + export enum AdvertisementDeliveryType { + NATIONAL, + LOCAL, + SYNDICATION + } + } + + class AdvertisementMetadata { + addCustomLabels(labels: any): void; + classifyAsAudioStream(isAudio: boolean): void; + setCallToActionUrl(url: string): void; + setClipUrl(url: string): void; + setDeliveryType(type: StreamingAnalytics.AdvertisementMetadata.AdvertisementDeliveryType): void; + setLength(length: number): void; + setMediaType(type: StreamingAnalytics.AdvertisementMetadata.AdvertisementType): void; + setOwner(owner: string): void; + setPlacementId(id: string): void; + setRelatedContentMetadata(metadata: any): void; + setServer(server: string): void; + setServerCampaignId(id: string): void; + setSiteId(id: string): void; + setTitle(title: string): void; + setUniqueId(id: string): void; + setVideoDimensions(width: number, height: number): void; + + getMetadataLabels(): any; + + constructor(); + } + + namespace ContentMetadata { + export enum ContentDeliveryAdvertisementCapability { + NONE, + DYNAMIC_LOAD, + DYNAMIC_REPLACEMENT, + LINEAR_1DAY, + LINEAR_2DAY, + LINEAR_3DAY, + LINEAR_4DAY, + LINEAR_5DAY, + LINEAR_6DAY, + LINEAR_7DAY + } + + export enum ContentDeliveryComposition { + CLEAN, + EMBED + } + + export enum ContentDeliveryMode { + LINEAR, + ON_DEMAND + } + + export enum ContentDeliverySubscriptionType { + ADVERTISING, + PREMIUM, + SUBSCRIPTION, + TRADITIONAL_MVPD, + TRANSACTIONAL, + VIRTUAL_MVPD + } + + export enum ContentDistributionModel { + EXCLUSIVELY_ONLINE, + TV_AND_ONLINE + } + + export enum ContentFeedType { + EAST_HD, + EAST_SD, + OTHER, + WEST_HD, + WEST_SD + } + export enum ContentMediaFormat { + EXTRA_EPISODE, + EXTRA_GENERIC, + EXTRA_MOVIE, + FULL_CONTENT_EPISODE, + FULL_CONTENT_GENERIC, + FULL_CONTENT_MOVIE, + PARTIAL_CONTENT_EPISODE, + PARTIAL_CONTENT_GENERIC, + PARTIAL_CONTENT_MOVIE, + PREVIEW_EPISODE, + PREVIEW_GENERIC, + PREVIEW_MOVIE + } + + export enum ContentType { + LONG_FORM_ON_DEMAND, + SHORT_FORM_ON_DEMAND, + LIVE, + USER_GENERATED_SHORT_FORM_ON_DEMAND, + USER_GENERATED_LONG_FORM_ON_DEMAND, + USER_GENERATED_LIVE, + BUMPER, + OTHER + } + } + + class ContentMetadata { + addCustomLabels(labels: any): void; + carryTvAdvertisementLoad(carriesTvAdvertisementLoad: boolean): void; + classifyAsAudioStream(audioStream: boolean): void; + classifyAsCompleteEpisode(completeEpisode: boolean): void; + setClipUrl(url: string): void; + setDateOfDigitalAiring(year: number, month: number, day: number): void; + setDateOfProduction(year: number, month: number, day: number): void; + setDateOfTvAiring(year: number, month: number, day: number): void; + setDeliveryAdvertisementCapability( + value: StreamingAnalytics.ContentMetadata.ContentDeliveryAdvertisementCapability + ): void; + setDeliveryComposition(value: StreamingAnalytics.ContentMetadata.ContentDeliveryComposition): void; + setDeliveryMode(value: StreamingAnalytics.ContentMetadata.ContentDeliveryMode): void; + setDeliverySubscriptionType( + value: StreamingAnalytics.ContentMetadata.ContentDeliverySubscriptionType + ): void; + setDictionaryClassificationC3(value: string): void; + setDictionaryClassificationC4(value: string): void; + setDictionaryClassificationC6(value: string): void; + setDistributionModel(value: StreamingAnalytics.ContentMetadata.ContentDistributionModel): void; + setEpisodeId(id: string): void; + setEpisodeNumber(episodeNumber: string): void; + setEpisodeSeasonNumber(seasonNumber: string): void; + setEpisodeTitle(title: string): void; + setFeedType(value: StreamingAnalytics.ContentMetadata.ContentFeedType): void; + setGenreId(id: string): void; + setGenreName(name: string): void; + setLength(length: number): void; + setMediaFormat(value: StreamingAnalytics.ContentMetadata.ContentMediaFormat): void; + setMediaType(value: StreamingAnalytics.ContentMetadata.ContentType): void; + setNetworkAffiliate(code: string): void; + setPlaylistTitle(title: string): void; + setProgramId(id: string): void; + setProgramTitle(title: string): void; + setPublisherName(name: string): void; + setStationCode(code: string): void; + setStationTitle(title: string): void; + setTimeOfDigitalAiring(hours: number, minutes: number): void; + setTimeOfProduction(hours: number, minutes: number): void; + setTimeOfTvAiring(hours: number, minutes: number): void; + setTotalSegments(total: number): void; + setUniqueId(id: string): void; + setVideoDimensions(width: number, height: number): void; + + getMetadataLabels(): any; + + constructor(); + } } - } - - namespace configuration { - function setApplicationName(name: string): void; - - function setApplicationVersion(name: string): void; - - function addClient(config: PublisherConfiguration): void; - - function getPublisherConfiguration(id: string): any; - - function setPersistentLabel(name: string, value: any): void; - - function addPersistentLabels(labels: any): void; - - function enableImplementationValidationMode(): void; - - function enableChildDirectedApplicationMode(): void; - - class PublisherConfiguration { - publisherId: string; - constructor({ }: any) + namespace configuration { + function setApplicationName(name: string): void; + + function setApplicationVersion(name: string): void; + + function addClient(config: PublisherConfiguration): void; + + function getPublisherConfiguration(id: string): any; + + function setPersistentLabel(name: string, value: any): void; + + function addPersistentLabels(labels: any): void; + + function enableImplementationValidationMode(): void; + + function enableChildDirectedApplicationMode(): void; + + class PublisherConfiguration { + publisherId: string; + constructor({}: any); + } } - } - - function notifyHiddenEvent(): void; - - function notifyEnterForeground(): void; - - function notifyExitForeground(): void; - - function close(): void; - - function start(): void; + function notifyHiddenEvent(): void; + + function notifyEnterForeground(): void; + + function notifyExitForeground(): void; + + function close(): void; + + function start(): void; } - } - \ No newline at end of file +} diff --git a/drm/src/index.ts b/drm/src/index.ts index 65b6e5aa..1419ed68 100644 --- a/drm/src/index.ts +++ b/drm/src/index.ts @@ -1,55 +1,29 @@ -import { VudrmWidevineContentProtectionIntegrationFactory } from - './integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory'; -import { VudrmPlayReadyContentProtectionIntegrationFactory } from - './integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory'; -import { VudrmFairplayContentProtectionIntegrationFactory } from - './integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory'; -import { EzdrmFairplayContentProtectionIntegrationFactory } from - './integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory'; -import { AzureDrmWidevineContentProtectionIntegrationFactory } from - './integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory'; -import { AzureDrmPlayReadyContentProtectionIntegrationFactory } from - './integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory'; -import { AzureDrmFairplayContentProtectionIntegrationFactory } from - './integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory'; -import { AxinomDrmWidevineContentProtectionIntegrationFactory } from - './integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory'; -import { AxinomDrmPlayReadyContentProtectionIntegrationFactory } from - './integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory'; -import { AxinomDrmFairplayContentProtectionIntegrationFactory } from - './integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory'; -import { ComcastDrmWidevineContentProtectionIntegrationFactory } from - './integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory'; -import { ComcastDrmFairPlayContentProtectionIntegrationFactory } from - './integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory'; -import { CastLabsDrmFairPlayContentProtectionIntegrationFactory } from - './integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory'; -import { IrdetoControlFairplayContentProtectionIntegrationFactory } from - './integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory'; -import { NagraDrmWidevineContentProtectionIntegrationFactory } from - './integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory'; -import { NagraDrmPlayReadyContentProtectionIntegrationFactory } from - './integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory'; -import { NagraDrmFairPlayContentProtectionIntegrationFactory } from - './integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory'; -import { KeyOSDrmFairplayContentProtectionIntegrationFactory } from - './integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory'; -import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from - './integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory'; -import { KeyOSDrmPlayReadyContentProtectionIntegrationFactory } from - './integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory'; -import { VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory } from - './integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory'; -import { VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory } from - './integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory'; -import { VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory } from - './integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory'; -import { TitaniumWidevineContentProtectionIntegrationFactory } from - './integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory'; -import { TitaniumPlayReadyContentProtectionIntegrationFactory } from - './integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory'; -import { TitaniumFairplayContentProtectionIntegrationFactory } from - './integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory'; +import { VudrmWidevineContentProtectionIntegrationFactory } from './integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory'; +import { VudrmPlayReadyContentProtectionIntegrationFactory } from './integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory'; +import { VudrmFairplayContentProtectionIntegrationFactory } from './integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory'; +import { EzdrmFairplayContentProtectionIntegrationFactory } from './integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory'; +import { AzureDrmWidevineContentProtectionIntegrationFactory } from './integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory'; +import { AzureDrmPlayReadyContentProtectionIntegrationFactory } from './integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory'; +import { AzureDrmFairplayContentProtectionIntegrationFactory } from './integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory'; +import { AxinomDrmWidevineContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory'; +import { AxinomDrmPlayReadyContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory'; +import { AxinomDrmFairplayContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory'; +import { ComcastDrmWidevineContentProtectionIntegrationFactory } from './integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory'; +import { ComcastDrmFairPlayContentProtectionIntegrationFactory } from './integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory'; +import { CastLabsDrmFairPlayContentProtectionIntegrationFactory } from './integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory'; +import { IrdetoControlFairplayContentProtectionIntegrationFactory } from './integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory'; +import { NagraDrmWidevineContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory'; +import { NagraDrmPlayReadyContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory'; +import { NagraDrmFairPlayContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory'; +import { KeyOSDrmFairplayContentProtectionIntegrationFactory } from './integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory'; +import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from './integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory'; +import { KeyOSDrmPlayReadyContentProtectionIntegrationFactory } from './integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory'; +import { VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory } from './integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory'; +import { VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory } from './integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory'; +import { VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory } from './integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory'; +import { TitaniumWidevineContentProtectionIntegrationFactory } from './integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory'; +import { TitaniumPlayReadyContentProtectionIntegrationFactory } from './integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory'; +import { TitaniumFairplayContentProtectionIntegrationFactory } from './integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory'; export { AxinomDrmWidevineContentProtectionIntegrationFactory, @@ -77,7 +51,7 @@ export { CastLabsDrmFairPlayContentProtectionIntegrationFactory, TitaniumWidevineContentProtectionIntegrationFactory, TitaniumPlayReadyContentProtectionIntegrationFactory, - TitaniumFairplayContentProtectionIntegrationFactory, + TitaniumFairplayContentProtectionIntegrationFactory }; export const THEOPLAYER_LICENSE = 'YOUR_LICENSE_HERE'; diff --git a/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts b/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts index db07326b..011d2547 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts @@ -9,7 +9,6 @@ export type AxinomIntegrationId = 'axinom'; * Describes the configuration of the Axinom DRM integration. */ export interface AxinomDrmConfiguration extends DRMConfiguration { - /** * The identifier of the DRM integration. */ @@ -26,5 +25,5 @@ export interface AxinomDrmConfiguration extends DRMConfiguration { *
- Token that will be added to the headers of the license request. */ token: string; - } + }; } diff --git a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts index 759dbd6d..6b213cac 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts @@ -1,15 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource, - CertificateRequest -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'THEOplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; -import { isAxinomDrmDRMConfiguration } from "./AxinomDrmUtils"; +import { isAxinomDrmDRMConfiguration } from './AxinomDrmUtils'; export class AxinomDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: AxinomDrmConfiguration; constructor(configuration: AxinomDrmConfiguration) { diff --git a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts index 024e162b..8058cfb4 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { AxinomDrmConfiguration } from "./AxinomDrmConfiguration"; -import { AxinomDrmFairplayContentProtectionIntegration } from "./AxinomDrmFairplayContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; +import { AxinomDrmFairplayContentProtectionIntegration } from './AxinomDrmFairplayContentProtectionIntegration'; export class AxinomDrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: AxinomDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts index 5cebbd25..5c00aacf 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts @@ -1,14 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; -import { isAxinomDrmDRMConfiguration } from "./AxinomDrmUtils"; +import { isAxinomDrmDRMConfiguration } from './AxinomDrmUtils'; export class AxinomDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: AxinomDrmConfiguration; constructor(configuration: AxinomDrmConfiguration) { diff --git a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts index c293bc67..50de527e 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { AxinomDrmConfiguration } from "./AxinomDrmConfiguration"; -import { AxinomDrmPlayReadyContentProtectionIntegration } from "./AxinomDrmPlayReadyContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; +import { AxinomDrmPlayReadyContentProtectionIntegration } from './AxinomDrmPlayReadyContentProtectionIntegration'; export class AxinomDrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: AxinomDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/axinomdrm/AxinomDrmUtils.ts b/drm/src/integration/axinomdrm/AxinomDrmUtils.ts index feb8c58b..8b70580c 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmUtils.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmUtils.ts @@ -1,4 +1,4 @@ -import { AxinomDrmConfiguration } from "./AxinomDrmConfiguration"; +import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; export function isAxinomDrmDRMConfiguration(configuration: AxinomDrmConfiguration): boolean { return configuration.integrationParameters.token !== undefined; diff --git a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts index 1c635f01..32dd7631 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts @@ -1,14 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; -import { isAxinomDrmDRMConfiguration } from "./AxinomDrmUtils"; +import { isAxinomDrmDRMConfiguration } from './AxinomDrmUtils'; export class AxinomDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: AxinomDrmConfiguration; constructor(configuration: AxinomDrmConfiguration) { diff --git a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts index 2e5a6b0c..800b3625 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { AxinomDrmConfiguration } from "./AxinomDrmConfiguration"; -import { AxinomDrmWidevineContentProtectionIntegration } from "./AxinomDrmWidevineContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; +import { AxinomDrmWidevineContentProtectionIntegration } from './AxinomDrmWidevineContentProtectionIntegration'; export class AxinomDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: AxinomDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/azuredrm/AzureDrmConfiguration.ts b/drm/src/integration/azuredrm/AzureDrmConfiguration.ts index cb1fcd56..84296ef7 100644 --- a/drm/src/integration/azuredrm/AzureDrmConfiguration.ts +++ b/drm/src/integration/azuredrm/AzureDrmConfiguration.ts @@ -9,7 +9,6 @@ export type AzureIntegrationID = 'azure'; * Describes the configuration of the Azure Media Services DRM integration. */ export interface AzureDrmConfiguration extends DRMConfiguration { - /** * The identifier of the DRM integration. */ @@ -26,5 +25,5 @@ export interface AzureDrmConfiguration extends DRMConfiguration { *
- This token will be used for the license request. */ token: string; - } + }; } diff --git a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts index d8ddc9f8..6e1c1857 100644 --- a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts @@ -4,12 +4,12 @@ import { ContentProtectionIntegration, LicenseRequest, LicenseResponse, - MaybeAsync, + MaybeAsync } from 'THEOplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; import { extractContentId, unwrapCkc } from '../../utils/FairplayUtils'; -import { fromStringToUint8Array, fromUint8ArrayToBase64String } from "../../utils/TypeUtils"; +import { fromStringToUint8Array, fromUint8ArrayToBase64String } from '../../utils/TypeUtils'; export class AzureDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: AzureDrmConfiguration; diff --git a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts index 46360907..8e41439d 100644 --- a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts @@ -1,7 +1,4 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { AzureDrmFairplayContentProtectionIntegration } from './AzureDrmFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts index f1428483..517796ac 100644 --- a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts @@ -1,14 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; export class AzureDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: AzureDrmConfiguration; constructor(configuration: AzureDrmConfiguration) { diff --git a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts index b2c75c32..95be4a49 100644 --- a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,7 +1,4 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { AzureDrmPlayReadyContentProtectionIntegration } from './AzureDrmPlayReadyContentProtectionIntegration'; diff --git a/drm/src/integration/azuredrm/AzureDrmUtils.ts b/drm/src/integration/azuredrm/AzureDrmUtils.ts index af4a3c42..eb1f8264 100644 --- a/drm/src/integration/azuredrm/AzureDrmUtils.ts +++ b/drm/src/integration/azuredrm/AzureDrmUtils.ts @@ -2,4 +2,4 @@ import { AzureDrmConfiguration } from './AzureDrmConfiguration'; export function isAzureDrmDRMConfiguration(configuration: AzureDrmConfiguration): boolean { return configuration.integrationParameters.token !== undefined; -} \ No newline at end of file +} diff --git a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts index 6cffc91c..807a1ce2 100644 --- a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts @@ -1,14 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; export class AzureDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: AzureDrmConfiguration; constructor(configuration: AzureDrmConfiguration) { diff --git a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts index 3b7163de..ef999779 100644 --- a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,7 +1,4 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { AzureDrmWidevineContentProtectionIntegration } from './AzureDrmWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts b/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts index 8fbdb71c..cc7e06d6 100644 --- a/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts +++ b/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts @@ -9,7 +9,6 @@ export type DRMTodayIntegrationID = 'castlabs'; * Describes the configuration of the Comcast DRM integration. */ export interface CastLabsDrmConfiguration extends DRMConfiguration { - /** * The identifier of the DRM integration. */ @@ -20,7 +19,6 @@ export interface CastLabsDrmConfiguration extends DRMConfiguration { * ContentProtectionIntegration. */ integrationParameters: { - /** * The Comcast Release Pid. * @@ -41,5 +39,5 @@ export interface CastLabsDrmConfiguration extends DRMConfiguration { *
- This token will be used for the license request. */ userId: string; - } + }; } diff --git a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts index 547ed272..3855b068 100644 --- a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts @@ -1,5 +1,6 @@ import { - BufferSource, CertificateRequest, + BufferSource, + CertificateRequest, ContentProtectionIntegration, LicenseRequest, LicenseResponse, @@ -7,7 +8,7 @@ import { } from 'THEOplayer'; import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; import { unwrapCkc } from '../../utils/FairplayUtils'; -import { fromObjectToBase64String, fromStringToUint8Array, fromUint8ArrayToBase64String } from "../../utils/TypeUtils"; +import { fromObjectToBase64String, fromStringToUint8Array, fromUint8ArrayToBase64String } from '../../utils/TypeUtils'; export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: CastLabsDrmConfiguration; @@ -29,14 +30,14 @@ export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentP ...request.headers, 'dt-custom-data': this.generatedToken! }; - return request + return request; } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { request.headers = { ...request.headers, 'content-type': 'application/x-www-form-urlencoded', - 'dt-custom-data': this.generatedToken!, + 'dt-custom-data': this.generatedToken! }; const body = `spc=${encodeURIComponent(fromUint8ArrayToBase64String(request.body!))}&${encodeURIComponent(this.contentId!)}`; request.body = fromStringToUint8Array(body); @@ -48,7 +49,7 @@ export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentP } extractFairplayContentId(skdUrl: string): string { - this.contentId = skdUrl + this.contentId = skdUrl; return this.contentId; } } diff --git a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts index 17ddca07..404beb17 100644 --- a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts @@ -1,7 +1,4 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; import { CastLabsDrmFairPlayContentProtectionIntegration } from './CastLabsDrmFairPlayContentProtectionIntegration'; diff --git a/drm/src/integration/castlabs/CastLabsDrmUtils.ts b/drm/src/integration/castlabs/CastLabsDrmUtils.ts index 2c2f4da5..8a821be0 100644 --- a/drm/src/integration/castlabs/CastLabsDrmUtils.ts +++ b/drm/src/integration/castlabs/CastLabsDrmUtils.ts @@ -1,7 +1,9 @@ import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; export function isDCastLabsDrmDRMConfiguration(configuration: CastLabsDrmConfiguration): boolean { - return (configuration.integrationParameters.merchant !== undefined && + return ( + configuration.integrationParameters.merchant !== undefined && configuration.integrationParameters.sessionId !== undefined && - configuration.integrationParameters.userId !== undefined); -} \ No newline at end of file + configuration.integrationParameters.userId !== undefined + ); +} diff --git a/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts b/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts index b651fb99..a8d7622d 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts @@ -9,7 +9,6 @@ export type ComcastIntegrationID = 'comcast'; * Describes the configuration of the Comcast DRM integration. */ export interface ComcastDrmConfiguration extends DRMConfiguration { - /** * The identifier of the DRM integration. */ @@ -20,7 +19,6 @@ export interface ComcastDrmConfiguration extends DRMConfiguration { * ContentProtectionIntegration. */ integrationParameters: { - /** * The Comcast Release Pid. * @@ -41,5 +39,5 @@ export interface ComcastDrmConfiguration extends DRMConfiguration { *
- This token will be used for the license request. */ token: string; - } + }; } diff --git a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts index 891c0215..3dd88149 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -1,10 +1,4 @@ -import { - BufferSource, - ContentProtectionIntegration, - LicenseRequest, - LicenseResponse, - MaybeAsync, -} from 'THEOplayer'; +import { BufferSource, ContentProtectionIntegration, LicenseRequest, LicenseResponse, MaybeAsync } from 'THEOplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; import { extractContentId } from '../../utils/FairplayUtils'; @@ -13,8 +7,8 @@ import { fromBase64StringToString, fromObjectToUint8Array, fromUint8ArrayToBase64String, - fromUint8ArrayToObject, -} from "../../utils/TypeUtils"; + fromUint8ArrayToObject +} from '../../utils/TypeUtils'; export class ComcastDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: ComcastDrmConfiguration; @@ -22,8 +16,10 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr constructor(configuration: ComcastDrmConfiguration) { if (!isComcastDrmDRMConfiguration(configuration)) { - throw new Error('The FairPlay ComcastDRM configuration is incorrect.' + - 'Please verify that you have configured a token, releasePid and account.'); + throw new Error( + 'The FairPlay ComcastDRM configuration is incorrect.' + + 'Please verify that you have configured a token, releasePid and account.' + ); } this.contentProtectionConfiguration = configuration; } @@ -32,12 +28,12 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { throw new Error('The FairPlay ComcastDRM license url has not been correctly configured.'); } - const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; + const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; const spcMessage = fromUint8ArrayToBase64String(request.body!); const body = { - "getFairplayLicense": { - "releasePid": releasePid, - "spcMessage": spcMessage + getFairplayLicense: { + releasePid: releasePid, + spcMessage: spcMessage } }; @@ -50,7 +46,6 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr }, body: newBody }; - } onLicenseResponse?(response: LicenseResponse): MaybeAsync { @@ -59,7 +54,10 @@ export class ComcastDrmFairPlayContentProtectionIntegration implements ContentPr } extractFairplayContentId(skdUrl: string): string { - const modifiedContentId = skdUrl.replace('FairPlay', this.contentProtectionConfiguration.integrationParameters.releasePid); + const modifiedContentId = skdUrl.replace( + 'FairPlay', + this.contentProtectionConfiguration.integrationParameters.releasePid + ); this.contentId = extractContentId(modifiedContentId); return this.contentId; } diff --git a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts index 6cc94d61..7d7db1fd 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts @@ -1,7 +1,4 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { ComcastDrmFairPlayContentProtectionIntegration } from './ComcastDrmFairPlayContentProtectionIntegration'; diff --git a/drm/src/integration/comcastdrm/ComcastDrmUtils.ts b/drm/src/integration/comcastdrm/ComcastDrmUtils.ts index 556d0133..4739a9ec 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmUtils.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmUtils.ts @@ -1,7 +1,9 @@ import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; export function isComcastDrmDRMConfiguration(configuration: ComcastDrmConfiguration): boolean { - return (configuration.integrationParameters.token !== undefined && + return ( + configuration.integrationParameters.token !== undefined && configuration.integrationParameters.releasePid !== undefined && - configuration.integrationParameters.account !== undefined); -} \ No newline at end of file + configuration.integrationParameters.account !== undefined + ); +} diff --git a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts index 5f59e182..97ca6196 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts @@ -2,14 +2,16 @@ import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, - BufferSource, LicenseResponse, CertificateRequest, CertificateResponse + BufferSource, + LicenseResponse, + CertificateRequest, + CertificateResponse } from 'THEOplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; -import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToString } from "../../utils/TypeUtils"; +import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToString } from '../../utils/TypeUtils'; export class ComcastDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: ComcastDrmConfiguration; constructor(configuration: ComcastDrmConfiguration) { @@ -20,12 +22,12 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; + const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; const widevineChallenge = fromUint8ArrayToBase64String(request.body!); const body = { - "getWidevineLicense": { - "releasePid": releasePid, - "widevineChallenge": widevineChallenge + getWidevineLicense: { + releasePid: releasePid, + widevineChallenge: widevineChallenge } }; return { @@ -38,20 +40,19 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr onCertificateResponse(response: CertificateResponse): MaybeAsync { const responseAsText = fromUint8ArrayToString(response.body); const responseObject = JSON.parse(responseAsText); - return Uint8Array.from(atob(responseObject.getWidevineLicenseResponse.license), c => c.charCodeAt(0)).buffer; - + return Uint8Array.from(atob(responseObject.getWidevineLicenseResponse.license), (c) => c.charCodeAt(0)).buffer; } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { throw new Error('The Widevine AzureDRM license url has not been correctly configured.'); } - const {token, account, releasePid} = this.contentProtectionConfiguration.integrationParameters; + const { token, account, releasePid } = this.contentProtectionConfiguration.integrationParameters; const widevineChallenge = fromUint8ArrayToBase64String(request.body!); const body = { - "getWidevineLicense": { - "releasePid": releasePid, - "widevineChallenge": widevineChallenge + getWidevineLicense: { + releasePid: releasePid, + widevineChallenge: widevineChallenge } }; return { @@ -64,7 +65,6 @@ export class ComcastDrmWidevineContentProtectionIntegration implements ContentPr onLicenseResponse?(response: LicenseResponse): MaybeAsync { const responseAsText = fromUint8ArrayToString(response.body); const responseObject = JSON.parse(responseAsText); - return Uint8Array.from(atob(responseObject.getWidevineLicenseResponse.license), c => c.charCodeAt(0)).buffer; + return Uint8Array.from(atob(responseObject.getWidevineLicenseResponse.license), (c) => c.charCodeAt(0)).buffer; } - } diff --git a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts index 28eddd4c..4e6887e8 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,7 +1,4 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { ComcastDrmWidevineContentProtectionIntegration } from './ComcastDrmWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts b/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts index 0690891c..c601b411 100644 --- a/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts +++ b/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from "THEOplayer"; +import { DRMConfiguration } from 'THEOplayer'; /** * The identifier of the Ezdrm integration. @@ -19,7 +19,6 @@ export type EzdrmIntegrationID = 'ezdrm'; * ``` */ export interface EzdrmDrmConfiguration extends DRMConfiguration { - /** * The identifier of the DRM integration. */ diff --git a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts index 59ed66e1..4d5e272d 100644 --- a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts @@ -1,14 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource, CertificateRequest -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'THEOplayer'; import { EzdrmDrmConfiguration } from './EzdrmDrmConfiguration'; -import { extractContentId } from "../../utils/FairplayUtils"; +import { extractContentId } from '../../utils/FairplayUtils'; export class EzdrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { - static readonly DEFAULT_CERTIFICATE_URL = 'insert default certificate url here'; static readonly DEFAULT_LICENSE_URL = 'insert default license url here'; @@ -20,21 +14,23 @@ export class EzdrmFairplayContentProtectionIntegration implements ContentProtect } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - request.url = this.contentProtectionConfiguration.fairplay?.certificateURL ?? + request.url = + this.contentProtectionConfiguration.fairplay?.certificateURL ?? EzdrmFairplayContentProtectionIntegration.DEFAULT_CERTIFICATE_URL; request.headers = { ...request.headers, - 'Content-Type': 'application/octet-stream', + 'Content-Type': 'application/octet-stream' }; return request; } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? + request.url = + this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? EzdrmFairplayContentProtectionIntegration.DEFAULT_LICENSE_URL; request.headers = { ...request.headers, - 'Content-Type': 'application/octet-stream', + 'Content-Type': 'application/octet-stream' }; return request; } diff --git a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts index cf196cfc..7c354a44 100644 --- a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { EzdrmDrmConfiguration } from './EzdrmDrmConfiguration'; -import { EzdrmFairplayContentProtectionIntegration } from "./EzdrmFairplayContentProtectionIntegration"; +import { EzdrmFairplayContentProtectionIntegration } from './EzdrmFairplayContentProtectionIntegration'; export class EzdrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: EzdrmDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts b/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts index 43d6ce94..081eba87 100644 --- a/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts +++ b/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts @@ -9,7 +9,6 @@ export type IrdetoControlIntegrationID = 'irdetocontrol'; * Describes the configuration of the Irdeto Control DRM integration. */ export interface IrdetoControlConfiguration extends DRMConfiguration { - /** * The identifier of the DRM integration. */ @@ -34,5 +33,5 @@ export interface IrdetoControlConfiguration extends DRMConfiguration { *
- This Application ID will be used for the certificate request. */ applicationId?: string; - } + }; } diff --git a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts index c78ec3e1..a5a52a0d 100644 --- a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts @@ -22,8 +22,15 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten throw new Error('The FairPlay Irdeto Control certificate url has not been correctly configured.'); } request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; - if (!this.hasQueryParameter(request.url, "applicationId") && this.contentProtectionConfiguration.integrationParameters?.applicationId) { - request.url = this.appendQueryParameter(request.url, "applicationId", this.contentProtectionConfiguration.integrationParameters?.applicationId); + if ( + !this.hasQueryParameter(request.url, 'applicationId') && + this.contentProtectionConfiguration.integrationParameters?.applicationId + ) { + request.url = this.appendQueryParameter( + request.url, + 'applicationId', + this.contentProtectionConfiguration.integrationParameters?.applicationId + ); } return request; } @@ -33,18 +40,26 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten throw new Error('The FairPlay Irdeto DRM license url has not been correctly configured.'); } request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; - if (!this.hasQueryParameter(request.url, "contentId")) { + if (!this.hasQueryParameter(request.url, 'contentId')) { if (this.contentProtectionConfiguration.integrationParameters?.contentId) { - request.url = this.appendQueryParameter(request.url, "contentId", this.contentProtectionConfiguration.integrationParameters?.contentId); + request.url = this.appendQueryParameter( + request.url, + 'contentId', + this.contentProtectionConfiguration.integrationParameters?.contentId + ); } else if (this.contentId) { - request.url = this.appendQueryParameter(request.url, "contentId", this.contentId); + request.url = this.appendQueryParameter(request.url, 'contentId', this.contentId); } } - if (!this.hasQueryParameter(request.url, "keyId")) { + if (!this.hasQueryParameter(request.url, 'keyId')) { if (this.contentProtectionConfiguration.integrationParameters?.keyId) { - request.url = this.appendQueryParameter(request.url, "keyId", this.contentProtectionConfiguration.integrationParameters?.keyId); + request.url = this.appendQueryParameter( + request.url, + 'keyId', + this.contentProtectionConfiguration.integrationParameters?.keyId + ); } else if (this.keyId) { - request.url = this.appendQueryParameter(request.url, "keyId", this.keyId); + request.url = this.appendQueryParameter(request.url, 'keyId', this.keyId); } } return request; @@ -55,12 +70,12 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten } extractFairplayContentId(skdUrl: string): string { - const parameters = skdUrl.split("?")[1].split("&"); + const parameters = skdUrl.split('?')[1].split('&'); for (let i = 0; i < parameters.length; i++) { - const pair = parameters[i].split("="); - if (pair[0] == "contentId") { + const pair = parameters[i].split('='); + if (pair[0] == 'contentId') { this.contentId = pair[1]; - } else if (pair[0] == "keyId") { + } else if (pair[0] == 'keyId') { this.keyId = pair[1]; } } @@ -68,13 +83,13 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten } hasQueryParameter(url: string, parameter: string): boolean { - const queryParameters = url.split("?"); + const queryParameters = url.split('?'); if (!queryParameters || !queryParameters[1]) { return false; } - const pairs = queryParameters[1].split("&"); + const pairs = queryParameters[1].split('&'); for (let i = 0; i < pairs.length; i++) { - const pair = pairs[i].split("="); + const pair = pairs[i].split('='); if (pair[0] == parameter) { return true; } @@ -83,11 +98,11 @@ export class IrdetoControlFairplayContentProtectionIntegration implements Conten } appendQueryParameter(url: string, key: string, value: string | undefined): string { - const queryParameters = url.split("?"); + const queryParameters = url.split('?'); if (!queryParameters || !queryParameters[1]) { - return (url + "?" + key + "=" + value); + return url + '?' + key + '=' + value; } else { - return (url + "&" + key + "=" + value); + return url + '&' + key + '=' + value; } } } diff --git a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts index 624b2e7e..a9b24626 100644 --- a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts @@ -1,7 +1,4 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { IrdetoControlConfiguration } from './IrdetoControlConfiguration'; import { IrdetoControlFairplayContentProtectionIntegration } from './IrdetoControlFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/keyos/KeyOSDrmConfiguration.ts b/drm/src/integration/keyos/KeyOSDrmConfiguration.ts index 6cae01e5..63da2b4a 100644 --- a/drm/src/integration/keyos/KeyOSDrmConfiguration.ts +++ b/drm/src/integration/keyos/KeyOSDrmConfiguration.ts @@ -9,7 +9,6 @@ export type KeyOSIntegrationId = 'keyos_buydrm'; * Describes the configuration of the KeyOS BuyDRM DRM integration. */ export interface KeyOSDrmConfiguration extends DRMConfiguration { - /** * The identifier of the DRM integration. */ @@ -26,5 +25,5 @@ export interface KeyOSDrmConfiguration extends DRMConfiguration { *
- Token that will be added to the headers of the license request. */ 'x-keyos-authorization': string; - } + }; } diff --git a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts index e5852e0e..2dde2bc0 100644 --- a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -3,19 +3,19 @@ import { LicenseRequest, MaybeAsync, BufferSource, - CertificateRequest, LicenseResponse + CertificateRequest, + LicenseResponse } from 'THEOplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; -import { isKeyOSDrmDRMConfiguration, extractContentId } from "./KeyOSDrmUtils"; +import { isKeyOSDrmDRMConfiguration, extractContentId } from './KeyOSDrmUtils'; import { - fromBase64StringToUint8Array, fromStringToUint8Array, + fromBase64StringToUint8Array, + fromStringToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToUtf8String -} from "../../utils/TypeUtils"; - +} from '../../utils/TypeUtils'; export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: KeyOSDrmConfiguration; private contentId: string | undefined = undefined; @@ -54,12 +54,12 @@ export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProt } onLicenseResponse?(response: LicenseResponse): MaybeAsync { - const bodyAsString = fromUint8ArrayToUtf8String(response.body) - let keyText = bodyAsString.trim() + const bodyAsString = fromUint8ArrayToUtf8String(response.body); + let keyText = bodyAsString.trim(); if (keyText.substr(0, 5) === '' && keyText.substr(-6) === '') { - keyText = keyText.slice(5, -6) + keyText = keyText.slice(5, -6); } - return fromBase64StringToUint8Array(keyText) + return fromBase64StringToUint8Array(keyText); } extractFairplayContentId(skdUrl: string): string { diff --git a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts index 5f8f9e16..b23d66cc 100644 --- a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; -import { KeyOSDrmFairplayContentProtectionIntegration } from "./KeyOSDrmFairplayContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; +import { KeyOSDrmFairplayContentProtectionIntegration } from './KeyOSDrmFairplayContentProtectionIntegration'; export class KeyOSDrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: KeyOSDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts index 41f934d9..0cb84950 100644 --- a/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts @@ -1,14 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; -import { isKeyOSDrmDRMConfiguration } from "./KeyOSDrmUtils"; +import { isKeyOSDrmDRMConfiguration } from './KeyOSDrmUtils'; export class KeyOSDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: KeyOSDrmConfiguration; constructor(configuration: KeyOSDrmConfiguration) { diff --git a/drm/src/integration/keyos/KeyOSDrmUtils.ts b/drm/src/integration/keyos/KeyOSDrmUtils.ts index afc951ee..f1138182 100644 --- a/drm/src/integration/keyos/KeyOSDrmUtils.ts +++ b/drm/src/integration/keyos/KeyOSDrmUtils.ts @@ -1,14 +1,14 @@ -import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; +import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; export function isKeyOSDrmDRMConfiguration(configuration: KeyOSDrmConfiguration): boolean { return configuration.integrationParameters['x-keyos-authorization'] !== undefined; } export function extractContentId(skdUrl: string): string { - if (skdUrl.indexOf("skd") > 0 || skdUrl.indexOf("http") > 0) { + if (skdUrl.indexOf('skd') > 0 || skdUrl.indexOf('http') > 0) { skdUrl = skdUrl.substring(1); } const link = document.createElement('a'); link.href = skdUrl; return link.hostname; -} \ No newline at end of file +} diff --git a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts index 194d2717..b16c6310 100644 --- a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts @@ -1,14 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; -import { isKeyOSDrmDRMConfiguration } from "./KeyOSDrmUtils"; +import { isKeyOSDrmDRMConfiguration } from './KeyOSDrmUtils'; export class KeyOSDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: KeyOSDrmConfiguration; constructor(configuration: KeyOSDrmConfiguration) { diff --git a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts index e5eb68c2..69e5b56c 100644 --- a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; -import { KeyOSDrmWidevineContentProtectionIntegration } from "./KeyOSDrmWidevineContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; +import { KeyOSDrmWidevineContentProtectionIntegration } from './KeyOSDrmWidevineContentProtectionIntegration'; export class KeyOSDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: KeyOSDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts index 649814fe..79067608 100644 --- a/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { KeyOSDrmConfiguration } from "./KeyOSDrmConfiguration"; -import { KeyOSDrmPlayReadyContentProtectionIntegration } from "./KeyOSDrmPlayReadyContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; +import { KeyOSDrmPlayReadyContentProtectionIntegration } from './KeyOSDrmPlayReadyContentProtectionIntegration'; export class KeyOSDrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: KeyOSDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/nagradrm/NagraDrmConfiguration.ts b/drm/src/integration/nagradrm/NagraDrmConfiguration.ts index 25d024b5..b61a21a0 100644 --- a/drm/src/integration/nagradrm/NagraDrmConfiguration.ts +++ b/drm/src/integration/nagradrm/NagraDrmConfiguration.ts @@ -3,7 +3,7 @@ import { DRMConfiguration } from 'THEOplayer'; /** * The identifier of the Nagra integration. */ -export type NagraIntegrationId = "nagra"; +export type NagraIntegrationId = 'nagra'; /** * Describes the configuration of the Axinom DRM integration. diff --git a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts index dd32f99f..9a3d638a 100644 --- a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts @@ -6,60 +6,44 @@ import { BufferSource, CertificateRequest } from 'THEOplayer'; -import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; -import { isNagraDrmDRMConfiguration } from "./NagraDrmUtils"; -import { - fromBase64StringToArrayBuffer, - fromBase64StringToString, - fromUint8ArrayToObject, -} from "../../utils/TypeUtils"; +import { NagraDrmConfiguration } from './NagraDrmConfiguration'; +import { isNagraDrmDRMConfiguration } from './NagraDrmUtils'; +import { fromBase64StringToArrayBuffer, fromBase64StringToString, fromUint8ArrayToObject } from '../../utils/TypeUtils'; -export class NagraDrmFairPlayContentProtectionIntegration - implements ContentProtectionIntegration { +export class NagraDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: NagraDrmConfiguration; private contentId: string | undefined = undefined; constructor(configuration: NagraDrmConfiguration) { if (!isNagraDrmDRMConfiguration(configuration)) { - throw new Error("The Nagra token has not been correctly configured."); + throw new Error('The Nagra token has not been correctly configured.'); } this.contentProtectionConfiguration = configuration; } - onCertificateRequest( - request: CertificateRequest - ): MaybeAsync | BufferSource> { + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { if (!this.contentProtectionConfiguration.fairplay?.certificateURL) { - throw new Error( - "The Nagra certificate url has not been correctly configured." - ); + throw new Error('The Nagra certificate url has not been correctly configured.'); } request.url = this.contentProtectionConfiguration.fairplay?.certificateURL; request.headers = { ...request.headers, - "nv-authorizations": this.contentProtectionConfiguration - .integrationParameters.token, - "content-type": "application/octet-stream" + 'nv-authorizations': this.contentProtectionConfiguration.integrationParameters.token, + 'content-type': 'application/octet-stream' }; return request; } - onLicenseRequest( - request: LicenseRequest - ): MaybeAsync | BufferSource> { + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { if (!this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL) { - throw new Error( - "The Nagra Fairplay license url has not been correctly configured." - ); + throw new Error('The Nagra Fairplay license url has not been correctly configured.'); } request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL; request.headers = { ...request.headers, - "nv-authorizations": this.contentProtectionConfiguration - .integrationParameters.token, - "nv-tenant-id": this.contentProtectionConfiguration.integrationParameters - .tenantId, - "content-type": "application/octet-stream" + 'nv-authorizations': this.contentProtectionConfiguration.integrationParameters.token, + 'nv-tenant-id': this.contentProtectionConfiguration.integrationParameters.tenantId, + 'content-type': 'application/octet-stream' }; return request; } @@ -70,7 +54,7 @@ export class NagraDrmFairPlayContentProtectionIntegration } extractFairplayContentId(skdUrl: string): string { - this.contentId = fromBase64StringToString(skdUrl.split("skd://")[1].split("?")[0]); + this.contentId = fromBase64StringToString(skdUrl.split('skd://')[1].split('?')[0]); return this.contentId; } } diff --git a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts index f390504f..71a9ac9d 100644 --- a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts @@ -1,12 +1,8 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; -import { NagraDrmFairPlayContentProtectionIntegration } from "./NagraDrmFairPlayContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { NagraDrmConfiguration } from './NagraDrmConfiguration'; +import { NagraDrmFairPlayContentProtectionIntegration } from './NagraDrmFairPlayContentProtectionIntegration'; -export class NagraDrmFairPlayContentProtectionIntegrationFactory - implements ContentProtectionIntegrationFactory { +export class NagraDrmFairPlayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: NagraDrmConfiguration): ContentProtectionIntegration { return new NagraDrmFairPlayContentProtectionIntegration(configuration); } diff --git a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts index 8e58d7c8..d961642b 100644 --- a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts @@ -1,49 +1,34 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - CertificateRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; -import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; -import { isNagraDrmDRMConfiguration } from "./NagraDrmUtils"; +import { ContentProtectionIntegration, LicenseRequest, CertificateRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { NagraDrmConfiguration } from './NagraDrmConfiguration'; +import { isNagraDrmDRMConfiguration } from './NagraDrmUtils'; -export class NagraDrmPlayReadyContentProtectionIntegration - implements ContentProtectionIntegration { +export class NagraDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: NagraDrmConfiguration; constructor(configuration: NagraDrmConfiguration) { if (!isNagraDrmDRMConfiguration(configuration)) { - throw new Error("The Nagra token has not been correctly configured."); + throw new Error('The Nagra token has not been correctly configured.'); } this.contentProtectionConfiguration = configuration; } - onCertificateRequest( - request: CertificateRequest - ): MaybeAsync | BufferSource> { + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { request.headers = { ...request.headers, - "nv-authorizations": this.contentProtectionConfiguration - .integrationParameters.token, - "Content-Type": "application/octet-stream" + 'nv-authorizations': this.contentProtectionConfiguration.integrationParameters.token, + 'Content-Type': 'application/octet-stream' }; return request; } - onLicenseRequest( - request: LicenseRequest - ): MaybeAsync | BufferSource> { + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { if (!this.contentProtectionConfiguration.playready?.licenseAcquisitionURL) { - throw new Error( - "The PlayReady Nagra license url has not been correctly configured." - ); + throw new Error('The PlayReady Nagra license url has not been correctly configured.'); } request.url = this.contentProtectionConfiguration.playready?.licenseAcquisitionURL; request.headers = { ...request.headers, - "X-AxDRM-Message": this.contentProtectionConfiguration - .integrationParameters.token + 'X-AxDRM-Message': this.contentProtectionConfiguration.integrationParameters.token }; return request; } diff --git a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts index ebd09852..472cd3ad 100644 --- a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,12 +1,8 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; -import { NagraDrmPlayReadyContentProtectionIntegration } from "./NagraDrmPlayReadyContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { NagraDrmConfiguration } from './NagraDrmConfiguration'; +import { NagraDrmPlayReadyContentProtectionIntegration } from './NagraDrmPlayReadyContentProtectionIntegration'; -export class NagraDrmPlayReadyContentProtectionIntegrationFactory - implements ContentProtectionIntegrationFactory { +export class NagraDrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: NagraDrmConfiguration): ContentProtectionIntegration { return new NagraDrmPlayReadyContentProtectionIntegration(configuration); } diff --git a/drm/src/integration/nagradrm/NagraDrmUtils.ts b/drm/src/integration/nagradrm/NagraDrmUtils.ts index 255fbae9..fa6c7f9a 100644 --- a/drm/src/integration/nagradrm/NagraDrmUtils.ts +++ b/drm/src/integration/nagradrm/NagraDrmUtils.ts @@ -1,7 +1,5 @@ -import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; +import { NagraDrmConfiguration } from './NagraDrmConfiguration'; -export function isNagraDrmDRMConfiguration( - configuration: NagraDrmConfiguration -): boolean { +export function isNagraDrmDRMConfiguration(configuration: NagraDrmConfiguration): boolean { return configuration.integrationParameters.token !== undefined; } diff --git a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts index b050e285..13c5a934 100644 --- a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts @@ -1,49 +1,34 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - CertificateRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; -import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; -import { isNagraDrmDRMConfiguration } from "./NagraDrmUtils"; +import { ContentProtectionIntegration, LicenseRequest, CertificateRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { NagraDrmConfiguration } from './NagraDrmConfiguration'; +import { isNagraDrmDRMConfiguration } from './NagraDrmUtils'; -export class NagraDrmWidevineContentProtectionIntegration - implements ContentProtectionIntegration { +export class NagraDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: NagraDrmConfiguration; constructor(configuration: NagraDrmConfiguration) { if (!isNagraDrmDRMConfiguration(configuration)) { - throw new Error("The Nagra token has not been correctly configured."); + throw new Error('The Nagra token has not been correctly configured.'); } this.contentProtectionConfiguration = configuration; } - onCertificateRequest( - request: CertificateRequest - ): MaybeAsync | BufferSource> { + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { request.headers = { ...request.headers, - "nv-authorizations": this.contentProtectionConfiguration - .integrationParameters.token, - "Content-Type": "application/octet-stream" + 'nv-authorizations': this.contentProtectionConfiguration.integrationParameters.token, + 'Content-Type': 'application/octet-stream' }; return request; } - onLicenseRequest( - request: LicenseRequest - ): MaybeAsync | BufferSource> { + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { if (!this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL) { - throw new Error( - "The Widevine Nagra license url has not been correctly configured." - ); + throw new Error('The Widevine Nagra license url has not been correctly configured.'); } request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL; request.headers = { ...request.headers, - "nv-authorizations": this.contentProtectionConfiguration - .integrationParameters.token + 'nv-authorizations': this.contentProtectionConfiguration.integrationParameters.token }; return request; } diff --git a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts index de37d371..231f5741 100644 --- a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,12 +1,8 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import { NagraDrmConfiguration } from "./NagraDrmConfiguration"; -import { NagraDrmWidevineContentProtectionIntegration } from "./NagraDrmWidevineContentProtectionIntegration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { NagraDrmConfiguration } from './NagraDrmConfiguration'; +import { NagraDrmWidevineContentProtectionIntegration } from './NagraDrmWidevineContentProtectionIntegration'; -export class NagraDrmWidevineContentProtectionIntegrationFactory - implements ContentProtectionIntegrationFactory { +export class NagraDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: NagraDrmConfiguration): ContentProtectionIntegration { return new NagraDrmWidevineContentProtectionIntegration(configuration); } diff --git a/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts b/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts index 32b8588f..f7dcdbea 100644 --- a/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts @@ -4,7 +4,7 @@ import type { DeviceBasedTitaniumIntegrationParameters } from './TitaniumIntegra import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; import type { ContentProtectionError } from 'THEOplayer'; import { ErrorCode } from 'THEOplayer'; -import { fromObjectToBase64String } from "../../utils/TypeUtils"; +import { fromObjectToBase64String } from '../../utils/TypeUtils'; export interface TitaniumDeviceAuthorizationData { LatensRegistration: TitaniumLatensRegistration; @@ -62,12 +62,12 @@ export const TITANIUM_CDM_DESCRIPTIONS: { [cdmType: string /* TitaniumCDMType_*/ DRMProvider: 'Apple', DRMType: 'FairPlay', DRMVersion: '1.0' - }, + } }; export function getTitaniumDeviceAuthorizationData( integrationParameters: DeviceBasedTitaniumIntegrationParameters, - cdmType: TitaniumCDMType, + cdmType: TitaniumCDMType ): TitaniumDeviceAuthorizationData { const cdmDescription: TitaniumCDMDescription = TITANIUM_CDM_DESCRIPTIONS[cdmType]; const accountName = integrationParameters.accountName; @@ -92,14 +92,14 @@ export function getTitaniumDeviceAuthorizationData( DRMType: cdmDescription.DRMType, DeviceVendor: navigator.vendor, DeviceModel: navigator.vendorSub - }, - }, + } + } }; } export function createErrorForMalformedDeviceInfoConfiguration( configuration: TitaniumDrmConfiguration, - cdmType: TitaniumCDMType, + cdmType: TitaniumCDMType ): ContentProtectionError { let message = `Invalid Titanium ${cdmType} DRM configuration.`; if (!configuration.integrationParameters.accountName) { @@ -111,18 +111,21 @@ export function createErrorForMalformedDeviceInfoConfiguration( } throw { code: ErrorCode.CONTENT_PROTECTION_CONFIGURATION_INVALID, - message: message, + message: message } as ContentProtectionError; } -export function createErrorForMalformedTokenConfiguration(configuration: TitaniumDrmConfiguration, cdmType: TitaniumCDMType): ContentProtectionError { +export function createErrorForMalformedTokenConfiguration( + configuration: TitaniumDrmConfiguration, + cdmType: TitaniumCDMType +): ContentProtectionError { let message = `Invalid Titanium ${cdmType} DRM configuration.`; if (!configuration.integrationParameters.authToken) { message = `Invalid Titanium ${cdmType} DRM configuration, authToken is not set.`; } throw { code: ErrorCode.CONTENT_PROTECTION_CONFIGURATION_INVALID, - message: message, + message: message } as ContentProtectionError; } @@ -144,17 +147,20 @@ export function createTitaniumDeviceHeader(configuration: TitaniumDrmConfigurati } } -export function createTitaniumHeaders(configuration: TitaniumDrmConfiguration, cdmType: TitaniumCDMType): { [key: string]: string } { +export function createTitaniumHeaders( + configuration: TitaniumDrmConfiguration, + cdmType: TitaniumCDMType +): { [key: string]: string } { const hasAuthToken = isTokenBasedTitaniumDRMConfiguration(configuration.integrationParameters); if (hasAuthToken) { return { 'content-type': 'application/octet-stream', - Authorization: createTitaniumAuthHeader(configuration, cdmType), + Authorization: createTitaniumAuthHeader(configuration, cdmType) }; } else { return { 'content-type': 'application/octet-stream', - 'X-TITANIUM-DRM-CDATA': createTitaniumDeviceHeader(configuration, cdmType), + 'X-TITANIUM-DRM-CDATA': createTitaniumDeviceHeader(configuration, cdmType) }; } } diff --git a/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts index 341aa9bc..b1279cb5 100644 --- a/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts @@ -16,7 +16,7 @@ export class TitaniumFairplayContentProtectionIntegration implements ContentProt onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { request.headers = { ...request.headers, - ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.FAIRPLAY), + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.FAIRPLAY) }; return request; } diff --git a/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts index 890a0957..4cef77f9 100644 --- a/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts @@ -17,7 +17,7 @@ export class TitaniumPlayReadyContentProtectionIntegration implements ContentPro onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { request.headers = { ...request.headers, - ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE), + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE) }; return request; } @@ -25,7 +25,7 @@ export class TitaniumPlayReadyContentProtectionIntegration implements ContentPro onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { request.headers = { ...request.headers, - ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE), + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE) }; return request; } diff --git a/drm/src/integration/titaniumdrm/TitaniumUtils.ts b/drm/src/integration/titaniumdrm/TitaniumUtils.ts index 8e4eea16..0bfacca0 100644 --- a/drm/src/integration/titaniumdrm/TitaniumUtils.ts +++ b/drm/src/integration/titaniumdrm/TitaniumUtils.ts @@ -2,23 +2,26 @@ import type { DeviceBasedTitaniumIntegrationParameters, TitaniumIntegrationParameters, - TokenBasedTitaniumIntegrationParameters, + TokenBasedTitaniumIntegrationParameters } from './TitaniumIntegrationParameters'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; export function isTitaniumDRMConfiguration(configuration: TitaniumDrmConfiguration): boolean { const integrationParameters = configuration.integrationParameters; - return isTokenBasedTitaniumDRMConfiguration(integrationParameters) || isDeviceBasedTitaniumDRMConfiguration(integrationParameters); + return ( + isTokenBasedTitaniumDRMConfiguration(integrationParameters) || + isDeviceBasedTitaniumDRMConfiguration(integrationParameters) + ); } export function isTokenBasedTitaniumDRMConfiguration( - integrationParameters: TitaniumIntegrationParameters, + integrationParameters: TitaniumIntegrationParameters ): integrationParameters is TokenBasedTitaniumIntegrationParameters { return integrationParameters.authToken !== undefined; } export function isDeviceBasedTitaniumDRMConfiguration( - integrationParameters: TitaniumIntegrationParameters, + integrationParameters: TitaniumIntegrationParameters ): integrationParameters is DeviceBasedTitaniumIntegrationParameters { return ( integrationParameters.accountName !== undefined && diff --git a/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts index 4e385e63..2d41607d 100644 --- a/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts @@ -17,7 +17,7 @@ export class TitaniumWidevineContentProtectionIntegration implements ContentProt onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { request.headers = { ...request.headers, - ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE), + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE) }; return request; } @@ -25,7 +25,7 @@ export class TitaniumWidevineContentProtectionIntegration implements ContentProt onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { request.headers = { ...request.headers, - ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE), + ...createTitaniumHeaders(this.contentProtectionConfiguration, TitaniumCDMType.WIDEVINE) }; return request; } diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts index 79164eb8..47a16d2c 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts @@ -20,10 +20,10 @@ export type VerimatrixCoreDrmIntegrationID = 'verimatrixcoredrmCustom'; * ``` */ export interface VerimatrixCoreDrmConfiguration extends DRMConfiguration { - /** - * The identifier of the DRM integration. - */ - integration: VerimatrixCoreDrmIntegrationID; + /** + * The identifier of the DRM integration. + */ + integration: VerimatrixCoreDrmIntegrationID; - integrationParameters: VerimatrixCoreIntegrationParameters; + integrationParameters: VerimatrixCoreIntegrationParameters; } diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts index e5690bd2..5d6f014d 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts @@ -1,43 +1,48 @@ import type { ContentProtectionIntegration, LicenseRequest, LicenseResponse, MaybeAsync } from 'THEOplayer'; import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; -import { fromBase64StringToUint8Array, fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToObject } from '../../utils/TypeUtils'; +import { + fromBase64StringToUint8Array, + fromObjectToUint8Array, + fromUint8ArrayToBase64String, + fromUint8ArrayToObject +} from '../../utils/TypeUtils'; export class VerimatrixCoreDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { - static readonly DEFAULT_LICENSE_URL = 'insert default license url here'; + static readonly DEFAULT_LICENSE_URL = 'insert default license url here'; - private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; + private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; - constructor(configuration: VerimatrixCoreDrmConfiguration) { - this.contentProtectionConfiguration = configuration; - } + constructor(configuration: VerimatrixCoreDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + } - onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - const spcMessage = fromUint8ArrayToBase64String(request.body!); - const bodyObject = { - spc: spcMessage, - }; - const bodyData = fromObjectToUint8Array(bodyObject); - request.url = - this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? - VerimatrixCoreDrmFairplayContentProtectionIntegration.DEFAULT_LICENSE_URL; - request.headers = { - 'content-type': 'application/json', - Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '', - }; - request.body = bodyData; - return request; - } + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + const spcMessage = fromUint8ArrayToBase64String(request.body!); + const bodyObject = { + spc: spcMessage + }; + const bodyData = fromObjectToUint8Array(bodyObject); + request.url = + this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? + VerimatrixCoreDrmFairplayContentProtectionIntegration.DEFAULT_LICENSE_URL; + request.headers = { + 'content-type': 'application/json', + Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '' + }; + request.body = bodyData; + return request; + } - onLicenseResponse?(response: LicenseResponse): MaybeAsync { - const responseObject = fromUint8ArrayToObject(response.body); - return fromBase64StringToUint8Array(responseObject.ckc); - } + onLicenseResponse?(response: LicenseResponse): MaybeAsync { + const responseObject = fromUint8ArrayToObject(response.body); + return fromBase64StringToUint8Array(responseObject.ckc); + } - extractFairplayContentId(skdUrl: string): string { - // drop params in url - const chunks = skdUrl.split('?'); - const sdkUrlWithoutParams = chunks[0]; - // drop the 'skd://' part - return sdkUrlWithoutParams.substring(6, sdkUrlWithoutParams.length); - } + extractFairplayContentId(skdUrl: string): string { + // drop params in url + const chunks = skdUrl.split('?'); + const sdkUrlWithoutParams = chunks[0]; + // drop the 'skd://' part + return sdkUrlWithoutParams.substring(6, sdkUrlWithoutParams.length); + } } diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts index 98fe7c28..24c37e4f 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts @@ -2,8 +2,10 @@ import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; import { VerimatrixCoreDrmFairplayContentProtectionIntegration } from './VerimatrixCoreDrmFairplayContentProtectionIntegration'; -export class VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { - return new VerimatrixCoreDrmFairplayContentProtectionIntegration(configuration); - } +export class VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory + implements ContentProtectionIntegrationFactory +{ + build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { + return new VerimatrixCoreDrmFairplayContentProtectionIntegration(configuration); + } } diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts index c9e85483..395ccffb 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts @@ -2,18 +2,18 @@ import type { ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'T import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; export class VerimatrixCoreDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; + private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; - constructor(configuration: VerimatrixCoreDrmConfiguration) { - this.contentProtectionConfiguration = configuration; - } + constructor(configuration: VerimatrixCoreDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + } - onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - request.headers = { - ...request.headers, - 'content-type': 'application/octet-stream', - Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '', - }; - return request; - } + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + 'content-type': 'application/octet-stream', + Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '' + }; + return request; + } } diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts index e08f686a..4591e3c9 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -2,8 +2,10 @@ import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; import { VerimatrixCoreDrmPlayReadyContentProtectionIntegration } from './VerimatrixCoreDrmPlayReadyContentProtectionIntegration'; -export class VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { - return new VerimatrixCoreDrmPlayReadyContentProtectionIntegration(configuration); - } +export class VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory + implements ContentProtectionIntegrationFactory +{ + build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { + return new VerimatrixCoreDrmPlayReadyContentProtectionIntegration(configuration); + } } diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts index 00ebd546..c903722e 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts @@ -2,27 +2,27 @@ import type { CertificateRequest, ContentProtectionIntegration, LicenseRequest, import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; export class VerimatrixCoreDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { - private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; + private readonly contentProtectionConfiguration: VerimatrixCoreDrmConfiguration; - constructor(configuration: VerimatrixCoreDrmConfiguration) { - this.contentProtectionConfiguration = configuration; - } + constructor(configuration: VerimatrixCoreDrmConfiguration) { + this.contentProtectionConfiguration = configuration; + } - onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - request.headers = { - ...request.headers, - 'content-type': 'application/octet-stream', - Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '', - }; - return request; - } + onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + 'content-type': 'application/octet-stream', + Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '' + }; + return request; + } - onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - request.headers = { - ...request.headers, - 'content-type': 'application/octet-stream', - Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '', - }; - return request; - } + onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { + request.headers = { + ...request.headers, + 'content-type': 'application/octet-stream', + Authorization: this.contentProtectionConfiguration.integrationParameters.drmToken ?? '' + }; + return request; + } } diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts index e8b59e42..abf5008e 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts @@ -2,8 +2,10 @@ import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; import { VerimatrixCoreDrmWidevineContentProtectionIntegration } from './VerimatrixCoreDrmWidevineContentProtectionIntegration'; -export class VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { - return new VerimatrixCoreDrmWidevineContentProtectionIntegration(configuration); - } +export class VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory + implements ContentProtectionIntegrationFactory +{ + build(configuration: VerimatrixCoreDrmConfiguration): ContentProtectionIntegration { + return new VerimatrixCoreDrmWidevineContentProtectionIntegration(configuration); + } } diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts index 86b1039b..20c4f16e 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts @@ -1,7 +1,7 @@ export interface VerimatrixCoreIntegrationParameters { - /** - * The drm token. - * - */ - drmToken?: string; + /** + * The drm token. + * + */ + drmToken?: string; } diff --git a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts index 392fe164..d86bfc0f 100644 --- a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts @@ -3,7 +3,8 @@ import { LicenseRequest, MaybeAsync, BufferSource, - CertificateRequest, utils + CertificateRequest, + utils } from 'THEOplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; @@ -11,7 +12,6 @@ import { extractContentId } from '../../utils/FairplayUtils'; import { fromObjectToUint8Array, fromUint8ArrayToBase64String } from '../../utils/TypeUtils'; export class VudrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { - static readonly DEFAULT_CERTIFICATE_URL = 'https://fairplay-license.drm.technology/certificate'; static readonly DEFAULT_LICENSE_URL = 'https://fairplay-license.drm.technology/license'; @@ -26,7 +26,8 @@ export class VudrmFairplayContentProtectionIntegration implements ContentProtect } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - request.url = this.contentProtectionConfiguration.fairplay?.certificateURL ?? + request.url = + this.contentProtectionConfiguration.fairplay?.certificateURL ?? VudrmFairplayContentProtectionIntegration.DEFAULT_CERTIFICATE_URL; request.headers = { ...request.headers, @@ -37,7 +38,8 @@ export class VudrmFairplayContentProtectionIntegration implements ContentProtect } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - request.url = this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? + request.url = + this.contentProtectionConfiguration.fairplay?.licenseAcquisitionURL ?? VudrmFairplayContentProtectionIntegration.DEFAULT_LICENSE_URL; const licenseParameters = { token: this.contentProtectionConfiguration.integrationParameters.token, @@ -47,7 +49,7 @@ export class VudrmFairplayContentProtectionIntegration implements ContentProtect request.headers = { 'Content-Type': 'application/json', 'x-vudrm-token': this.contentProtectionConfiguration.integrationParameters.token - } + }; request.body = fromObjectToUint8Array(licenseParameters); return request; } diff --git a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts index f500eedc..40f389b1 100644 --- a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; -import { VudrmFairplayContentProtectionIntegration } from "./VudrmFairplayContentProtectionIntegration"; +import { VudrmFairplayContentProtectionIntegration } from './VudrmFairplayContentProtectionIntegration'; export class VudrmFairplayContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: VudrmDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts index a73c9fe1..ed00d33a 100644 --- a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts @@ -1,14 +1,8 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; import { isVudrmDRMConfiguration } from './VudrmUtil'; -import { VudrmDrmConfiguration } from "./VudrmDrmConfiguration"; +import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; export class VudrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { - static DEFAULT_LICENSE_URL = 'https://playready-license.drm.technology/rightsmanager.asmx'; private readonly contentProtectionConfiguration: VudrmDrmConfiguration; @@ -21,8 +15,10 @@ export class VudrmPlayReadyContentProtectionIntegration implements ContentProtec } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - const url = new URL(this.contentProtectionConfiguration.playready?.licenseAcquisitionURL ?? - VudrmPlayReadyContentProtectionIntegration.DEFAULT_LICENSE_URL); + const url = new URL( + this.contentProtectionConfiguration.playready?.licenseAcquisitionURL ?? + VudrmPlayReadyContentProtectionIntegration.DEFAULT_LICENSE_URL + ); if (this.contentProtectionConfiguration.playready?.queryParameters) { for (const key of Object.keys(this.contentProtectionConfiguration.playready.queryParameters)) { url.searchParams.set(key, this.contentProtectionConfiguration.playready.queryParameters[key]); diff --git a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts index 6d521cb5..efa314c9 100644 --- a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,9 +1,6 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; -import {VudrmPlayReadyContentProtectionIntegration} from './VudrmPlayReadyContentProtectionIntegration'; -import { VudrmDrmConfiguration } from "./VudrmDrmConfiguration"; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { VudrmPlayReadyContentProtectionIntegration } from './VudrmPlayReadyContentProtectionIntegration'; +import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; export class VudrmPlayReadyContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { build(configuration: VudrmDrmConfiguration): ContentProtectionIntegration { diff --git a/drm/src/integration/vudrm/VudrmUtil.ts b/drm/src/integration/vudrm/VudrmUtil.ts index 15cd0098..313df4e2 100644 --- a/drm/src/integration/vudrm/VudrmUtil.ts +++ b/drm/src/integration/vudrm/VudrmUtil.ts @@ -1,4 +1,4 @@ -import { VudrmDrmConfiguration } from "./VudrmDrmConfiguration"; +import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; export function isVudrmDRMConfiguration(configuration: VudrmDrmConfiguration): boolean { return configuration.integrationParameters.token !== undefined; diff --git a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts index 774ba292..af98f24e 100644 --- a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts @@ -1,15 +1,9 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource, CertificateRequest -} from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'THEOplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; import { fromObjectToUint8Array, fromUint8ArrayToNumberArray } from '../../utils/TypeUtils'; export class VudrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { - static readonly DEFAULT_LICENSE_URL = 'https://widevine-proxy.drm.technology/proxy'; private readonly contentProtectionConfiguration: VudrmDrmConfiguration; @@ -25,18 +19,20 @@ export class VudrmWidevineContentProtectionIntegration implements ContentProtect const token = this.contentProtectionConfiguration.integrationParameters.token; const drmInfo = fromUint8ArrayToNumberArray(body); const kid = this.contentProtectionConfiguration.integrationParameters.keyId; - return fromObjectToUint8Array({token, drm_info: drmInfo, kid}); + return fromObjectToUint8Array({ token, drm_info: drmInfo, kid }); } onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL ?? + request.url = + this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL ?? VudrmWidevineContentProtectionIntegration.DEFAULT_LICENSE_URL; request.body = this.wrapRequestBody(request.body!); return request; } onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - request.url = this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL ?? + request.url = + this.contentProtectionConfiguration.widevine?.licenseAcquisitionURL ?? VudrmWidevineContentProtectionIntegration.DEFAULT_LICENSE_URL; request.body = this.wrapRequestBody(request.body!); return request; diff --git a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts index 4d720978..f180c27a 100644 --- a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts @@ -1,7 +1,4 @@ -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory -} from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; import { VudrmWidevineContentProtectionIntegration } from './VudrmWidevineContentProtectionIntegration'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; diff --git a/drm/src/utils/FairplayUtils.ts b/drm/src/utils/FairplayUtils.ts index 2cc4e9df..78d4fa3f 100644 --- a/drm/src/utils/FairplayUtils.ts +++ b/drm/src/utils/FairplayUtils.ts @@ -1,4 +1,4 @@ -import { fromBase64StringToUint8Array, fromUint8ArrayToString } from "./TypeUtils"; +import { fromBase64StringToUint8Array, fromUint8ArrayToString } from './TypeUtils'; export function extractContentId(skdUrl: string): string { const questionMarkIndex = skdUrl.indexOf('?'); diff --git a/drm/src/utils/TypeUtils.ts b/drm/src/utils/TypeUtils.ts index a3b4df79..23b0e8b1 100644 --- a/drm/src/utils/TypeUtils.ts +++ b/drm/src/utils/TypeUtils.ts @@ -1,10 +1,10 @@ import { utils } from 'THEOplayer'; -export function fromObjectToUint8Array(obj: {[key: string]: any}): Uint8Array { +export function fromObjectToUint8Array(obj: { [key: string]: any }): Uint8Array { return new TextEncoder().encode(JSON.stringify(obj)); } -export function fromObjectToBase64String(obj: {[key: string]: any}): string { +export function fromObjectToBase64String(obj: { [key: string]: any }): string { return fromStringToBase64String(JSON.stringify(obj)); } @@ -21,7 +21,7 @@ export function fromBase64StringToString(str: string): string { } export function fromBase64StringToArrayBuffer(str: string): ArrayBuffer { - return Uint8Array.from(fromBase64StringToString(str), c => c.charCodeAt(0)).buffer; + return Uint8Array.from(fromBase64StringToString(str), (c) => c.charCodeAt(0)).buffer; } export function fromUint8ArrayToNumberArray(array: Uint8Array): number[] { @@ -40,7 +40,7 @@ export function fromUint8ArrayToString(array: Uint8Array): string { return new TextDecoder().decode(array); } -export function fromUint8ArrayToObject(array: Uint8Array): {[key: string]: any} { +export function fromUint8ArrayToObject(array: Uint8Array): { [key: string]: any } { return JSON.parse(new TextDecoder().decode(array)); } diff --git a/drm/test/axinomdrm/fairplay.html b/drm/test/axinomdrm/fairplay.html index 38d99573..58108463 100644 --- a/drm/test/axinomdrm/fairplay.html +++ b/drm/test/axinomdrm/fairplay.html @@ -1,49 +1,49 @@ - + - - - Axinom Fairplay Test - - - - - -

- + + + +
+ - + ] + }; + + diff --git a/drm/test/axinomdrm/playready.html b/drm/test/axinomdrm/playready.html index 75c275a4..cf357757 100644 --- a/drm/test/axinomdrm/playready.html +++ b/drm/test/axinomdrm/playready.html @@ -1,48 +1,48 @@ - + - - - Axinom PlayReady Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/axinomdrm/widevine.html b/drm/test/axinomdrm/widevine.html index 56b9468e..eb187812 100644 --- a/drm/test/axinomdrm/widevine.html +++ b/drm/test/axinomdrm/widevine.html @@ -1,48 +1,48 @@ - + - - - Axinom Widevine Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/azuredrm/fairplay.html b/drm/test/azuredrm/fairplay.html index 6e1af3b1..ec003a5f 100644 --- a/drm/test/azuredrm/fairplay.html +++ b/drm/test/azuredrm/fairplay.html @@ -1,48 +1,48 @@ - + - - - Azure drm FairPlay Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/azuredrm/playready.html b/drm/test/azuredrm/playready.html index b0f7ee3e..c8d56231 100644 --- a/drm/test/azuredrm/playready.html +++ b/drm/test/azuredrm/playready.html @@ -1,47 +1,47 @@ - + - - - Azure drm PlayReady Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/azuredrm/widevine.html b/drm/test/azuredrm/widevine.html index 84b8397b..b86967d7 100644 --- a/drm/test/azuredrm/widevine.html +++ b/drm/test/azuredrm/widevine.html @@ -1,47 +1,47 @@ - + - - - Azure drm Widevine Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/castlabs/fairplay.html b/drm/test/castlabs/fairplay.html index dbf4d79e..23e9b35d 100644 --- a/drm/test/castlabs/fairplay.html +++ b/drm/test/castlabs/fairplay.html @@ -1,58 +1,58 @@ - + - - - CastLabs FairPlay Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/castlabs/playready.html b/drm/test/castlabs/playready.html index 73f994ac..c786702d 100644 --- a/drm/test/castlabs/playready.html +++ b/drm/test/castlabs/playready.html @@ -1,47 +1,56 @@ - + - - - CastLabs PlayReady Test - - - - - -

This example uses the integration documented at https://docs.theoplayer.com/how-to-guides/04-drm/02-castlabs-drmtoday/00-introduction.md.

-
- + + + +

+ This example uses the integration documented at + https://docs.theoplayer.com/how-to-guides/04-drm/02-castlabs-drmtoday/00-introduction.md. +

+
+ - + const src = ''; + const licenseAcquisitionURL = ''; + const merchant = ''; + const sessionId = ''; + const userId = ''; + + player.source = { + sources: [ + { + src: src, + type: 'application/dash+xml', + contentProtection: { + integration: 'drmtoday', + merchant: merchant, + sessionId: sessionId, + userId: userId, + widevine: { + licenseAcquisitionURL: licenseAcquisitionURL + }, + preferredKeySystems: ['playready', 'widevine', 'fairplay'] + } + } + ] + }; + + diff --git a/drm/test/castlabs/widevine.html b/drm/test/castlabs/widevine.html index 9db2f7bf..ce47262b 100644 --- a/drm/test/castlabs/widevine.html +++ b/drm/test/castlabs/widevine.html @@ -1,47 +1,56 @@ - + - - - CastLabs Widevine Test - - - - - -

This example uses the integration documented at https://docs.theoplayer.com/how-to-guides/04-drm/02-castlabs-drmtoday/00-introduction.md.

-
- + + + +

+ This example uses the integration documented at + https://docs.theoplayer.com/how-to-guides/04-drm/02-castlabs-drmtoday/00-introduction.md. +

+
+ - + player.source = { + sources: [ + { + src: src, + type: 'application/dash+xml', + contentProtection: { + integration: 'drmtoday', + merchant: merchant, + sessionId: sessionId, + userId: userId, + widevine: { + licenseAcquisitionURL: licenseAcquisitionURL + }, + preferredKeySystems: ['widevine', 'playready', 'fairplay'] + } + } + ] + }; + + diff --git a/drm/test/comcastdrm/fairplay.html b/drm/test/comcastdrm/fairplay.html index 1c22d6b3..32a884c1 100644 --- a/drm/test/comcastdrm/fairplay.html +++ b/drm/test/comcastdrm/fairplay.html @@ -1,123 +1,103 @@ - + - - - Comcast DRM FairPlay Test - - - - - - -
-
-

Comcast DRM FairPlay

-

Enter valid data below, and hit play. Only use this test player on FairPlay-enabled platforms, such as Safari.

- - - - - - - - - - - - - -
-
-
-
-
- + + + +
+
+

Comcast DRM FairPlay

+

+ Enter valid data below, and hit play. Only use this test player on FairPlay-enabled platforms, such + as Safari. +

+ + + + + + + + + + + + + +
+
+
+
+
+ - + + diff --git a/drm/test/comcastdrm/playready.html b/drm/test/comcastdrm/playready.html index befa3a6f..2ce3e14c 100644 --- a/drm/test/comcastdrm/playready.html +++ b/drm/test/comcastdrm/playready.html @@ -1,114 +1,97 @@ - + - - - Comcast DRM PlayReady Test - - - - - - -
-
-

Comcast DRM PlayReady

-

Enter valid data below, and hit play. Only use this test player on PlayReady-enabled platforms, such as Edge.

- - - - - - - - - - - - - -
-
-
-
-
- + + + +
+
+

Comcast DRM PlayReady

+

+ Enter valid data below, and hit play. Only use this test player on PlayReady-enabled platforms, such + as Edge. +

+ + + + + + + + + + + + + +
+
+
+
+
+ - + + diff --git a/drm/test/comcastdrm/style.css b/drm/test/comcastdrm/style.css index 7c0c429c..0ad72499 100644 --- a/drm/test/comcastdrm/style.css +++ b/drm/test/comcastdrm/style.css @@ -7,7 +7,7 @@ padding: 5px; } -input[type="text"] { +input[type='text'] { width: 100%; } diff --git a/drm/test/comcastdrm/widevine.html b/drm/test/comcastdrm/widevine.html index d1f381b0..2b45abf3 100644 --- a/drm/test/comcastdrm/widevine.html +++ b/drm/test/comcastdrm/widevine.html @@ -1,74 +1,52 @@ - + - - - Comcast DRM Widevine Test - - - - - - -
-
-

Comcast DRM Widevine

-

Enter valid data below, and hit play. Only use this test player on Widevine-enabled platforms, such as Chrome.

- - - - - - - - - - - - - -
-
-
-
-
- + + + +
+
+

Comcast DRM Widevine

+

+ Enter valid data below, and hit play. Only use this test player on Widevine-enabled platforms, such + as Chrome. +

+ + + + + + + + + + + + + +
+
+
+
+
+ - + configureStreamFromForm(); + + diff --git a/drm/test/ezdrm/fairplay.html b/drm/test/ezdrm/fairplay.html index 9fa9ebe7..6bfe2237 100644 --- a/drm/test/ezdrm/fairplay.html +++ b/drm/test/ezdrm/fairplay.html @@ -1,45 +1,45 @@ - + - - - Ezdrm Fairplay Test - - - - - -
- + + + +
+ - + player.source = { + sources: [ + { + src: 'insert manifest url here', + contentProtection: { + fairplay: { + certificateURL: 'insert certificate url here', + licenseAcquisitionURL: 'insert license url here' + }, + preferredKeySystems: ['fairplay', 'widevine', 'playready'], + integration: 'ezdrm' + } + } + ] + }; + + diff --git a/drm/test/irdetocontrol/fairplay.html b/drm/test/irdetocontrol/fairplay.html index 5e97cd6a..8348fbe0 100644 --- a/drm/test/irdetocontrol/fairplay.html +++ b/drm/test/irdetocontrol/fairplay.html @@ -1,58 +1,59 @@ - + - - - Irdeto Control FairPlay Test - - - - - -
- + + + +
+ - + const streamSrc = '.m3u8'; + const applicationId = ''; + const contentId = ''; + const keyId = ''; + player.source = { + sources: [ + { + src: streamSrc, + type: 'application/x-mpegurl', + contentProtection: { + fairplay: { + certificateURL: '?applicationId=' + applicationId, + licenseAcquisitionURL: + '?contentId=' + contentId + '&keyId=' + keyId + // headers: { + // "Authorization": "Bearer " // when using JWT + // } + }, + preferredKeySystems: ['fairplay', 'widevine', 'playready'], + integration: 'irdetocontrol' + // integrationParameters: { // you can pass the key-value parameters here instead of directly through the certificate and license URL + // contentId: contentId, + // keyId: keyId, + // applicationId: applicationId + // } + } + } + ] + }; + + diff --git a/drm/test/irdetocontrol/playready.html b/drm/test/irdetocontrol/playready.html index 26935b85..d986976f 100644 --- a/drm/test/irdetocontrol/playready.html +++ b/drm/test/irdetocontrol/playready.html @@ -1,42 +1,42 @@ - + - - - Irdeto Control PlayReady Test - - - - - -
- + + + +
+ - + const streamSrc = '.mpd'; + const contentId = ''; + player.source = { + sources: [ + { + src: streamSrc, + type: 'application/dash+xml', + contentProtection: { + playready: { + licenseAcquisitionURL: '?contentId=' + contentId + // headers: { + // "Authorization": "Bearer " // when using JWT + // } + } + } + } + ] + }; + + diff --git a/drm/test/irdetocontrol/widevine.html b/drm/test/irdetocontrol/widevine.html index 94bcf430..e79f108c 100644 --- a/drm/test/irdetocontrol/widevine.html +++ b/drm/test/irdetocontrol/widevine.html @@ -1,42 +1,42 @@ - + - - - Irdeto Control Widevine Test - - - - - -
- + + + +
+ - + const streamSrc = '.mpd'; + const contentId = ''; + player.source = { + sources: [ + { + src: streamSrc, + type: 'application/dash+xml', + contentProtection: { + widevine: { + licenseAcquisitionURL: '?contentId=' + contentId + // headers: { + // "Authorization": "Bearer " // when using JWT + // } + } + } + } + ] + }; + + diff --git a/drm/test/keyos/fairplay.html b/drm/test/keyos/fairplay.html index 2a674a16..f07a186c 100644 --- a/drm/test/keyos/fairplay.html +++ b/drm/test/keyos/fairplay.html @@ -1,49 +1,51 @@ - + - - - KeyOS drm FairPlay Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/keyos/playready.html b/drm/test/keyos/playready.html index 511d21d3..bdb8ec77 100644 --- a/drm/test/keyos/playready.html +++ b/drm/test/keyos/playready.html @@ -1,48 +1,49 @@ - + - - - KeyOS drm PlayReady Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/keyos/widevine.html b/drm/test/keyos/widevine.html index ce94d4a7..ff0639d8 100644 --- a/drm/test/keyos/widevine.html +++ b/drm/test/keyos/widevine.html @@ -1,48 +1,49 @@ - + - - - KeyOS drm Widevine Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/nagradrm/fairplay.html b/drm/test/nagradrm/fairplay.html index 33e3385e..013d5684 100644 --- a/drm/test/nagradrm/fairplay.html +++ b/drm/test/nagradrm/fairplay.html @@ -1,115 +1,94 @@ - - THEOplayer Web SDK Nagra FairPlay - - - - - - + + THEOplayer Web SDK Nagra FairPlay + + + + + + - + +
+
+
+
+
+

Enter valid data below, and hit play.

+ + + + + + + + + + + +
+
-
-
-
-
-
-

Enter valid data below, and hit play.

- - - - - - - - - - - -
-
+ - + + diff --git a/drm/test/nagradrm/playready.html b/drm/test/nagradrm/playready.html index 922182e5..bafac8bf 100644 --- a/drm/test/nagradrm/playready.html +++ b/drm/test/nagradrm/playready.html @@ -1,124 +1,109 @@ - - THEOplayer Web SDK Nagra PlayReady - - - - - - + + THEOplayer Web SDK Nagra PlayReady + + + + + + - + +
+
+
+
+
+

Enter valid data below, and hit play.

+ + + + + + + +
+
-
-
-
-
-
-

Enter valid data below, and hit play.

- - - - - - - -
-
+ - + + diff --git a/drm/test/nagradrm/style.css b/drm/test/nagradrm/style.css index 22a6b036..7a566ba0 100644 --- a/drm/test/nagradrm/style.css +++ b/drm/test/nagradrm/style.css @@ -7,7 +7,7 @@ padding: 5px; } -input[type="text"] { +input[type='text'] { width: 100%; } diff --git a/drm/test/nagradrm/widevine.html b/drm/test/nagradrm/widevine.html index a6a0bd91..1fdd6e84 100644 --- a/drm/test/nagradrm/widevine.html +++ b/drm/test/nagradrm/widevine.html @@ -1,124 +1,109 @@ - - THEOplayer Web SDK Nagra Widevine - - - - - - + + THEOplayer Web SDK Nagra Widevine + + + + + + - + +
+
+
+
+
+

Enter valid data below, and hit play.

+ + + + + + + +
+
-
-
-
-
-
-

Enter valid data below, and hit play.

- - - - - - - -
-
+ - + + diff --git a/drm/test/titaniumdrm/fairplay.html b/drm/test/titaniumdrm/fairplay.html index cdd1701d..65867af2 100644 --- a/drm/test/titaniumdrm/fairplay.html +++ b/drm/test/titaniumdrm/fairplay.html @@ -1,69 +1,69 @@ - + - - - Titanium DRM Fairplay Test Using AuthToken or device parameters - - - - - -
- + + + +
+ - + // // Alternatively, use device parameters instead of an authToken + // player.source = { + // sources: [ + // { + // src: 'insert manifest url here', + // contentProtection: { + // fairplay: { + // certificate: 'insert raw certificate', + // certificateUrl: 'or optional certificateUrl', + // licenseAcquisitionURL: 'insert license url here' + // }, + // integration: 'titaniumdrm', + // integrationParameters: { + // accountName: 'replace with accountName', + // customerName: 'replace with customerName', + // friendlyName: 'replace with friendlyName', + // portalId: 'replace with portalId' + // } + // } + // } + // ], + // }; + + diff --git a/drm/test/titaniumdrm/playready.html b/drm/test/titaniumdrm/playready.html index 2573d98a..4766ef30 100644 --- a/drm/test/titaniumdrm/playready.html +++ b/drm/test/titaniumdrm/playready.html @@ -1,69 +1,69 @@ - + - - - Titanium DRM PlayReady Test using AuthToken or device parameters - - - - - -
- + + + +
+ - + // // Alternatively, use device parameters instead of an authToken + // player.source = { + // sources: [ + // { + // src: 'insert manifest url here', + // contentProtection: { + // widevine: { + // licenseAcquisitionURL: 'insert license url here' + // }, + // preferredKeySystems: ['playready'], + // integration: 'titaniumdrm', + // integrationParameters: { + // accountName: 'replace with accountName', + // customerName: 'replace with customerName', + // friendlyName: 'replace with friendlyName', + // portalId: 'replace with portalId' + // } + // } + // } + // ], + // }; + + diff --git a/drm/test/titaniumdrm/widevine.html b/drm/test/titaniumdrm/widevine.html index fb94b276..8128614e 100644 --- a/drm/test/titaniumdrm/widevine.html +++ b/drm/test/titaniumdrm/widevine.html @@ -1,71 +1,71 @@ - + - - - Titanium DRM Widevine Test Using AuthToken or device parameters - - - - - -
- + + + +
+ - + // // Alternatively, use device parameters instead of an authToken + // player.source = { + // sources: [ + // { + // src: 'insert manifest url here', + // contentProtection: { + // widevine: { + // persistentState: 'required', + // licenseAcquisitionURL: 'insert license url here' + // }, + // preferredKeySystems: ['widevine'], + // integration: 'titaniumdrm', + // integrationParameters: { + // accountName: 'replace with accountName', + // customerName: 'replace with customerName', + // friendlyName: 'replace with friendlyName', + // portalId: 'replace with portalId' + // } + // } + // } + // ], + // }; + + diff --git a/drm/test/verimatrixcoredrm/fairplay.html b/drm/test/verimatrixcoredrm/fairplay.html index e9b1ba7e..d99b15f2 100644 --- a/drm/test/verimatrixcoredrm/fairplay.html +++ b/drm/test/verimatrixcoredrm/fairplay.html @@ -1,53 +1,54 @@ - + - - - Verimatrix Core DRM FairPlay Test - - - - - -
- + + + +
+ - + player.source = { + sources: [ + { + src: src, + type: 'application/x-mpegurl', + contentProtection: { + fairplay: { + licenseAcquisitionURL: licenseAcquisitionURL, + certificateURL: certificateURL + }, + integration: 'verimatrixcore', + integrationParameters: { + drmToken + }, + preferredKeySystems: ['fairplay', 'widevine', 'playready'] + } + } + ] + }; + + diff --git a/drm/test/verimatrixcoredrm/playready.html b/drm/test/verimatrixcoredrm/playready.html index 15d7b51a..45e172dc 100644 --- a/drm/test/verimatrixcoredrm/playready.html +++ b/drm/test/verimatrixcoredrm/playready.html @@ -1,52 +1,52 @@ - + - - - Verimatrix Core DRM PlayReady Test - - - - - -
- + + + +
+ - + player.source = { + sources: [ + { + src: src, + type: 'application/dash+xml', + contentProtection: { + playready: { + licenseAcquisitionURL: licenseAcquisitionURL + }, + integration: 'verimatrixcore', + integrationParameters: { + drmToken + }, + preferredKeySystems: ['playready', 'widevine', 'fairplay'] + } + } + ] + }; + + diff --git a/drm/test/verimatrixcoredrm/widevine.html b/drm/test/verimatrixcoredrm/widevine.html index 1eb1c025..559c0fed 100644 --- a/drm/test/verimatrixcoredrm/widevine.html +++ b/drm/test/verimatrixcoredrm/widevine.html @@ -1,52 +1,52 @@ - + - - - Verimatrix Core DRM Widevine Test - - - - - -
- + + + +
+ - + player.source = { + sources: [ + { + src: src, + type: 'application/dash+xml', + contentProtection: { + widevine: { + licenseAcquisitionURL: licenseAcquisitionURL + }, + integration: 'verimatrixcore', + integrationParameters: { + drmToken + }, + preferredKeySystems: ['widevine', 'playready', 'fairplay'] + } + } + ] + }; + + diff --git a/drm/test/vudrm/fairplay.html b/drm/test/vudrm/fairplay.html index 10cb0718..6a2bc123 100644 --- a/drm/test/vudrm/fairplay.html +++ b/drm/test/vudrm/fairplay.html @@ -1,48 +1,48 @@ - + - - - Vudrm Fairplay Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/vudrm/playready.html b/drm/test/vudrm/playready.html index 442d3f83..2ee4466d 100644 --- a/drm/test/vudrm/playready.html +++ b/drm/test/vudrm/playready.html @@ -1,47 +1,47 @@ - + - - - Vudrm PlayReady Test - - - - - -
- + + + +
+ - + ] + }; + + diff --git a/drm/test/vudrm/widevine.html b/drm/test/vudrm/widevine.html index da94dfb8..78a700ff 100644 --- a/drm/test/vudrm/widevine.html +++ b/drm/test/vudrm/widevine.html @@ -1,48 +1,48 @@ - + - - - Vudrm Widevine Test - - - - - -
- + + + +
+ - + ] + }; + + From c69583850ccad65ceddc2106cd37a475fb86a168 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 15:52:23 +0200 Subject: [PATCH 70/85] Fix lint issues --- .../ComcastDrmFairPlayContentProtectionIntegration.ts | 1 - drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts | 2 +- .../vudrm/VudrmFairplayContentProtectionIntegration.ts | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts index 3dd88149..690edb55 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -4,7 +4,6 @@ import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; import { extractContentId } from '../../utils/FairplayUtils'; import { fromBase64StringToArrayBuffer, - fromBase64StringToString, fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToObject diff --git a/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts b/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts index f7dcdbea..3a88e6a1 100644 --- a/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts @@ -37,7 +37,7 @@ export interface TitaniumCDMDescription { export enum TitaniumCDMType { WIDEVINE = 'Widevine', PLAYREADY = 'PlayreadyV2', - PLAYREADY_v2 = 'PlayreadyV2', + PLAYREADY_v2 = TitaniumCDMType.PLAYREADY, PLAYREADY_v3 = 'PlayreadyV3', FAIRPLAY = 'Fairplay' } diff --git a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts index d86bfc0f..b6b8eaad 100644 --- a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts @@ -3,8 +3,7 @@ import { LicenseRequest, MaybeAsync, BufferSource, - CertificateRequest, - utils + CertificateRequest } from 'THEOplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; From 56f2627e1a01682d5bfc5088d0cb94937e276e03 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 17:01:36 +0200 Subject: [PATCH 71/85] Fix imports --- drm/README.md | 6 +++--- drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts | 2 +- .../AxinomDrmFairplayContentProtectionIntegration.ts | 2 +- .../AxinomDrmFairplayContentProtectionIntegrationFactory.ts | 2 +- .../AxinomDrmPlayReadyContentProtectionIntegration.ts | 2 +- ...AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts | 2 +- .../AxinomDrmWidevineContentProtectionIntegration.ts | 2 +- .../AxinomDrmWidevineContentProtectionIntegrationFactory.ts | 2 +- drm/src/integration/azuredrm/AzureDrmConfiguration.ts | 2 +- .../AzureDrmFairplayContentProtectionIntegration.ts | 2 +- .../AzureDrmFairplayContentProtectionIntegrationFactory.ts | 2 +- .../AzureDrmPlayReadyContentProtectionIntegration.ts | 2 +- .../AzureDrmPlayReadyContentProtectionIntegrationFactory.ts | 2 +- .../AzureDrmWidevineContentProtectionIntegration.ts | 2 +- .../AzureDrmWidevineContentProtectionIntegrationFactory.ts | 2 +- drm/src/integration/castlabs/CastLabsDrmConfiguration.ts | 2 +- .../CastLabsDrmFairPlayContentProtectionIntegration.ts | 2 +- ...astLabsDrmFairPlayContentProtectionIntegrationFactory.ts | 2 +- drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts | 2 +- .../ComcastDrmFairPlayContentProtectionIntegration.ts | 2 +- ...ComcastDrmFairPlayContentProtectionIntegrationFactory.ts | 2 +- .../ComcastDrmWidevineContentProtectionIntegration.ts | 2 +- ...ComcastDrmWidevineContentProtectionIntegrationFactory.ts | 2 +- drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts | 2 +- .../ezdrm/EzdrmFairplayContentProtectionIntegration.ts | 2 +- .../EzdrmFairplayContentProtectionIntegrationFactory.ts | 2 +- .../integration/irdetocontrol/IrdetoControlConfiguration.ts | 2 +- .../IrdetoControlFairplayContentProtectionIntegration.ts | 2 +- ...etoControlFairplayContentProtectionIntegrationFactory.ts | 2 +- drm/src/integration/keyos/KeyOSDrmConfiguration.ts | 2 +- .../keyos/KeyOSDrmFairplayContentProtectionIntegration.ts | 2 +- .../KeyOSDrmFairplayContentProtectionIntegrationFactory.ts | 2 +- .../keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts | 2 +- .../keyos/KeyOSDrmWidevineContentProtectionIntegration.ts | 2 +- .../KeyOSDrmWidevineContentProtectionIntegrationFactory.ts | 2 +- .../keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts | 2 +- drm/src/integration/nagradrm/NagraDrmConfiguration.ts | 2 +- .../NagraDrmFairPlayContentProtectionIntegration.ts | 2 +- .../NagraDrmFairPlayContentProtectionIntegrationFactory.ts | 2 +- .../NagraDrmPlayReadyContentProtectionIntegration.ts | 2 +- .../NagraDrmPlayReadyContentProtectionIntegrationFactory.ts | 2 +- .../NagraDrmWidevineContentProtectionIntegration.ts | 2 +- .../NagraDrmWidevineContentProtectionIntegrationFactory.ts | 2 +- drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts | 4 ++-- drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts | 2 +- .../TitaniumFairplayContentProtectionIntegration.ts | 2 +- .../TitaniumFairplayContentProtectionIntegrationFactory.ts | 2 +- .../TitaniumPlayReadyContentProtectionIntegration.ts | 4 ++-- .../TitaniumPlayReadyContentProtectionIntegrationFactory.ts | 2 +- .../TitaniumWidevineContentProtectionIntegration.ts | 4 ++-- .../TitaniumWidevineContentProtectionIntegrationFactory.ts | 2 +- .../verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts | 2 +- ...VerimatrixCoreDrmFairplayContentProtectionIntegration.ts | 2 +- ...rixCoreDrmFairplayContentProtectionIntegrationFactory.ts | 2 +- ...erimatrixCoreDrmPlayReadyContentProtectionIntegration.ts | 2 +- ...ixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts | 2 +- ...VerimatrixCoreDrmWidevineContentProtectionIntegration.ts | 2 +- ...rixCoreDrmWidevineContentProtectionIntegrationFactory.ts | 2 +- drm/src/integration/vudrm/VudrmDrmConfiguration.ts | 2 +- .../vudrm/VudrmFairplayContentProtectionIntegration.ts | 2 +- .../VudrmFairplayContentProtectionIntegrationFactory.ts | 2 +- .../vudrm/VudrmPlayReadyContentProtectionIntegration.ts | 2 +- .../VudrmPlayReadyContentProtectionIntegrationFactory.ts | 2 +- .../vudrm/VudrmWidevineContentProtectionIntegration.ts | 2 +- .../VudrmWidevineContentProtectionIntegrationFactory.ts | 2 +- drm/src/utils/TypeUtils.ts | 2 +- 66 files changed, 71 insertions(+), 71 deletions(-) diff --git a/drm/README.md b/drm/README.md index 858d2cc4..ca4ef9b5 100644 --- a/drm/README.md +++ b/drm/README.md @@ -45,7 +45,7 @@ import { CertificateResponse, LicenseRequest, LicenseResponse -} from 'THEOplayer'; +} from 'theoplayer'; import { CustomDRMConfiguration } from './CustomDRMConfiguration'; export class CustomContentProtectionIntegration implements ContentProtectionIntegration { @@ -84,7 +84,7 @@ Optional parameters needed for certificate or license requests, such as tokens, object that is passed when creating instances of the `CustomContentProtectionIntegration` class. ```ts -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; export interface CustomDRMConfiguration extends DRMConfiguration { integrationParameters: { @@ -108,7 +108,7 @@ import { ContentProtectionIntegration, ContentProtectionIntegrationFactory, DRMConfiguration -} from 'THEOplayer'; +} from 'theoplayer'; import { CustomContentProtectionIntegration } from './CustomContentProtectionIntegration'; export class CustomContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { diff --git a/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts b/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts index 011d2547..91f54466 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the Axinom integration. diff --git a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts index 6b213cac..bbebd5c6 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'theoplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; import { isAxinomDrmDRMConfiguration } from './AxinomDrmUtils'; diff --git a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts index 8058cfb4..9c0f98ea 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; import { AxinomDrmFairplayContentProtectionIntegration } from './AxinomDrmFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts index 5c00aacf..a76e3e16 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; import { isAxinomDrmDRMConfiguration } from './AxinomDrmUtils'; diff --git a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts index 50de527e..cff52341 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; import { AxinomDrmPlayReadyContentProtectionIntegration } from './AxinomDrmPlayReadyContentProtectionIntegration'; diff --git a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts index 32dd7631..2ca29274 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; import { isAxinomDrmDRMConfiguration } from './AxinomDrmUtils'; diff --git a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts index 800b3625..a9ca6bbf 100644 --- a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { AxinomDrmConfiguration } from './AxinomDrmConfiguration'; import { AxinomDrmWidevineContentProtectionIntegration } from './AxinomDrmWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/azuredrm/AzureDrmConfiguration.ts b/drm/src/integration/azuredrm/AzureDrmConfiguration.ts index 84296ef7..8f847686 100644 --- a/drm/src/integration/azuredrm/AzureDrmConfiguration.ts +++ b/drm/src/integration/azuredrm/AzureDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the Azure Media Services integration. diff --git a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts index 6e1c1857..e109ceae 100644 --- a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts @@ -5,7 +5,7 @@ import { LicenseRequest, LicenseResponse, MaybeAsync -} from 'THEOplayer'; +} from 'theoplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; import { extractContentId, unwrapCkc } from '../../utils/FairplayUtils'; diff --git a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts index 8e41439d..763ae3c7 100644 --- a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { AzureDrmFairplayContentProtectionIntegration } from './AzureDrmFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts index 517796ac..4361fcda 100644 --- a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; diff --git a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts index 95be4a49..e5927581 100644 --- a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { AzureDrmPlayReadyContentProtectionIntegration } from './AzureDrmPlayReadyContentProtectionIntegration'; diff --git a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts index 807a1ce2..462b8808 100644 --- a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; diff --git a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts index ef999779..6d820ddb 100644 --- a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { AzureDrmWidevineContentProtectionIntegration } from './AzureDrmWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts b/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts index cc7e06d6..8e775816 100644 --- a/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts +++ b/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the Comcast DRM integration. diff --git a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts index 3855b068..12cf88f7 100644 --- a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts @@ -5,7 +5,7 @@ import { LicenseRequest, LicenseResponse, MaybeAsync -} from 'THEOplayer'; +} from 'theoplayer'; import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; import { unwrapCkc } from '../../utils/FairplayUtils'; import { fromObjectToBase64String, fromStringToUint8Array, fromUint8ArrayToBase64String } from '../../utils/TypeUtils'; diff --git a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts index 404beb17..2dcb65d8 100644 --- a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; import { CastLabsDrmFairPlayContentProtectionIntegration } from './CastLabsDrmFairPlayContentProtectionIntegration'; diff --git a/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts b/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts index a8d7622d..dc30fb87 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the Comcast DRM integration. diff --git a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts index 690edb55..5a6076c6 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { BufferSource, ContentProtectionIntegration, LicenseRequest, LicenseResponse, MaybeAsync } from 'THEOplayer'; +import { BufferSource, ContentProtectionIntegration, LicenseRequest, LicenseResponse, MaybeAsync } from 'theoplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; import { extractContentId } from '../../utils/FairplayUtils'; diff --git a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts index 7d7db1fd..24947c95 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { ComcastDrmFairPlayContentProtectionIntegration } from './ComcastDrmFairPlayContentProtectionIntegration'; diff --git a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts index 97ca6196..1a2a1b35 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts @@ -6,7 +6,7 @@ import { LicenseResponse, CertificateRequest, CertificateResponse -} from 'THEOplayer'; +} from 'theoplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToString } from '../../utils/TypeUtils'; diff --git a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts index 4e6887e8..43dfd6d5 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { ComcastDrmWidevineContentProtectionIntegration } from './ComcastDrmWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts b/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts index c601b411..e7a2bc49 100644 --- a/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts +++ b/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the Ezdrm integration. diff --git a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts index 4d5e272d..5541ae8b 100644 --- a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'theoplayer'; import { EzdrmDrmConfiguration } from './EzdrmDrmConfiguration'; import { extractContentId } from '../../utils/FairplayUtils'; diff --git a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts index 7c354a44..e9b14fe0 100644 --- a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { EzdrmDrmConfiguration } from './EzdrmDrmConfiguration'; import { EzdrmFairplayContentProtectionIntegration } from './EzdrmFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts b/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts index 081eba87..9ef21896 100644 --- a/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts +++ b/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the Irdeto Control integration. diff --git a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts index a5a52a0d..1e84e285 100644 --- a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts @@ -5,7 +5,7 @@ import { LicenseRequest, LicenseResponse, MaybeAsync -} from 'THEOplayer'; +} from 'theoplayer'; import { IrdetoControlConfiguration } from './IrdetoControlConfiguration'; export class IrdetoControlFairplayContentProtectionIntegration implements ContentProtectionIntegration { diff --git a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts index a9b24626..b485a5af 100644 --- a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { IrdetoControlConfiguration } from './IrdetoControlConfiguration'; import { IrdetoControlFairplayContentProtectionIntegration } from './IrdetoControlFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/keyos/KeyOSDrmConfiguration.ts b/drm/src/integration/keyos/KeyOSDrmConfiguration.ts index 63da2b4a..59d6e956 100644 --- a/drm/src/integration/keyos/KeyOSDrmConfiguration.ts +++ b/drm/src/integration/keyos/KeyOSDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the KeyOS BuyDRM integration. diff --git a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts index 2dde2bc0..41d45794 100644 --- a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -5,7 +5,7 @@ import { BufferSource, CertificateRequest, LicenseResponse -} from 'THEOplayer'; +} from 'theoplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; import { isKeyOSDrmDRMConfiguration, extractContentId } from './KeyOSDrmUtils'; import { diff --git a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts index b23d66cc..92d0bc53 100644 --- a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; import { KeyOSDrmFairplayContentProtectionIntegration } from './KeyOSDrmFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts index 0cb84950..bfd2fbdc 100644 --- a/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; import { isKeyOSDrmDRMConfiguration } from './KeyOSDrmUtils'; diff --git a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts index b16c6310..6acb01d6 100644 --- a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; import { isKeyOSDrmDRMConfiguration } from './KeyOSDrmUtils'; diff --git a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts index 69e5b56c..121c3f93 100644 --- a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; import { KeyOSDrmWidevineContentProtectionIntegration } from './KeyOSDrmWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts index 79067608..20a33177 100644 --- a/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { KeyOSDrmConfiguration } from './KeyOSDrmConfiguration'; import { KeyOSDrmPlayReadyContentProtectionIntegration } from './KeyOSDrmPlayReadyContentProtectionIntegration'; diff --git a/drm/src/integration/nagradrm/NagraDrmConfiguration.ts b/drm/src/integration/nagradrm/NagraDrmConfiguration.ts index b61a21a0..20714ca5 100644 --- a/drm/src/integration/nagradrm/NagraDrmConfiguration.ts +++ b/drm/src/integration/nagradrm/NagraDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the Nagra integration. diff --git a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts index 9a3d638a..000beb1e 100644 --- a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts @@ -5,7 +5,7 @@ import { MaybeAsync, BufferSource, CertificateRequest -} from 'THEOplayer'; +} from 'theoplayer'; import { NagraDrmConfiguration } from './NagraDrmConfiguration'; import { isNagraDrmDRMConfiguration } from './NagraDrmUtils'; import { fromBase64StringToArrayBuffer, fromBase64StringToString, fromUint8ArrayToObject } from '../../utils/TypeUtils'; diff --git a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts index 71a9ac9d..362f4a1e 100644 --- a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { NagraDrmConfiguration } from './NagraDrmConfiguration'; import { NagraDrmFairPlayContentProtectionIntegration } from './NagraDrmFairPlayContentProtectionIntegration'; diff --git a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts index d961642b..68fa1d5e 100644 --- a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, CertificateRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, CertificateRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { NagraDrmConfiguration } from './NagraDrmConfiguration'; import { isNagraDrmDRMConfiguration } from './NagraDrmUtils'; diff --git a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts index 472cd3ad..610cb408 100644 --- a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { NagraDrmConfiguration } from './NagraDrmConfiguration'; import { NagraDrmPlayReadyContentProtectionIntegration } from './NagraDrmPlayReadyContentProtectionIntegration'; diff --git a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts index 13c5a934..26c0d949 100644 --- a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, CertificateRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, CertificateRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { NagraDrmConfiguration } from './NagraDrmConfiguration'; import { isNagraDrmDRMConfiguration } from './NagraDrmUtils'; diff --git a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts index 231f5741..1b13eee8 100644 --- a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { NagraDrmConfiguration } from './NagraDrmConfiguration'; import { NagraDrmWidevineContentProtectionIntegration } from './NagraDrmWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts b/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts index 3a88e6a1..42aa3426 100644 --- a/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts @@ -2,8 +2,8 @@ import { isDeviceBasedTitaniumDRMConfiguration, isTokenBasedTitaniumDRMConfiguration } from './TitaniumUtils'; import type { DeviceBasedTitaniumIntegrationParameters } from './TitaniumIntegrationParameters'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; -import type { ContentProtectionError } from 'THEOplayer'; -import { ErrorCode } from 'THEOplayer'; +import type { ContentProtectionError } from 'theoplayer'; +import { ErrorCode } from 'theoplayer'; import { fromObjectToBase64String } from '../../utils/TypeUtils'; export interface TitaniumDeviceAuthorizationData { diff --git a/drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts b/drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts index f4a2d1f4..bff0d3fc 100644 --- a/drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts @@ -1,4 +1,4 @@ -import type { DRMConfiguration } from 'THEOplayer'; +import type { DRMConfiguration } from 'theoplayer'; import type { TitaniumIntegrationParameters } from './TitaniumIntegrationParameters'; export type TitaniumIntegrationID = 'titaniumdrm'; diff --git a/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts index b1279cb5..a523c99a 100644 --- a/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts @@ -1,6 +1,6 @@ import { isTitaniumDRMConfiguration } from './TitaniumUtils'; import { createTitaniumHeaders, TitaniumCDMType } from './TitaniumBaseRegistration'; -import type { ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'theoplayer'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; export class TitaniumFairplayContentProtectionIntegration implements ContentProtectionIntegration { diff --git a/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts index 2214924b..ebe893cb 100644 --- a/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { TitaniumFairplayContentProtectionIntegration } from './TitaniumFairplayContentProtectionIntegration'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; diff --git a/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts index 4cef77f9..d3f43acf 100644 --- a/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts @@ -1,8 +1,8 @@ import { isTitaniumDRMConfiguration } from './TitaniumUtils'; import { createTitaniumHeaders, TitaniumCDMType } from './TitaniumBaseRegistration'; -import type { BufferSource, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { BufferSource, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'theoplayer'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; -import { CertificateRequest } from 'THEOplayer'; +import { CertificateRequest } from 'theoplayer'; export class TitaniumPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: TitaniumDrmConfiguration; diff --git a/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts index 2c27f66d..8454c8d3 100644 --- a/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; import { TitaniumPlayReadyContentProtectionIntegration } from './TitaniumPlayReadyContentProtectionIntegration'; diff --git a/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts b/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts index 2d41607d..9c90d317 100644 --- a/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts @@ -1,8 +1,8 @@ import { isTitaniumDRMConfiguration } from './TitaniumUtils'; import { createTitaniumHeaders, TitaniumCDMType } from './TitaniumBaseRegistration'; -import type { BufferSource, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { BufferSource, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'theoplayer'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; -import type { CertificateRequest } from 'THEOplayer'; +import type { CertificateRequest } from 'theoplayer'; export class TitaniumWidevineContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: TitaniumDrmConfiguration; diff --git a/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts index f34c01d1..41f1275d 100644 --- a/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; import { TitaniumWidevineContentProtectionIntegration } from './TitaniumWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts index 47a16d2c..a4fa3b6f 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts @@ -1,4 +1,4 @@ -import type { DRMConfiguration } from 'THEOplayer'; +import type { DRMConfiguration } from 'theoplayer'; import type { VerimatrixCoreIntegrationParameters } from './VerimatrixCoreIntegrationParameters'; /** diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts index 5d6f014d..c28b123a 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import type { ContentProtectionIntegration, LicenseRequest, LicenseResponse, MaybeAsync } from 'THEOplayer'; +import type { ContentProtectionIntegration, LicenseRequest, LicenseResponse, MaybeAsync } from 'theoplayer'; import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; import { fromBase64StringToUint8Array, diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts index 24c37e4f..43a13b39 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; import { VerimatrixCoreDrmFairplayContentProtectionIntegration } from './VerimatrixCoreDrmFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts index 395ccffb..f9d67be6 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import type { ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'theoplayer'; import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; export class VerimatrixCoreDrmPlayReadyContentProtectionIntegration implements ContentProtectionIntegration { diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts index 4591e3c9..58177c53 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; import { VerimatrixCoreDrmPlayReadyContentProtectionIntegration } from './VerimatrixCoreDrmPlayReadyContentProtectionIntegration'; diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts index c903722e..b4d54f3d 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import type { CertificateRequest, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'THEOplayer'; +import type { CertificateRequest, ContentProtectionIntegration, LicenseRequest, MaybeAsync } from 'theoplayer'; import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; export class VerimatrixCoreDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts index abf5008e..3dcc3897 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import type { VerimatrixCoreDrmConfiguration } from './VerimatrixCoreDrmConfiguration'; import { VerimatrixCoreDrmWidevineContentProtectionIntegration } from './VerimatrixCoreDrmWidevineContentProtectionIntegration'; diff --git a/drm/src/integration/vudrm/VudrmDrmConfiguration.ts b/drm/src/integration/vudrm/VudrmDrmConfiguration.ts index ada1ef51..54a8baaf 100644 --- a/drm/src/integration/vudrm/VudrmDrmConfiguration.ts +++ b/drm/src/integration/vudrm/VudrmDrmConfiguration.ts @@ -1,4 +1,4 @@ -import { DRMConfiguration } from 'THEOplayer'; +import { DRMConfiguration } from 'theoplayer'; /** * The identifier of the Vudrm integration. diff --git a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts index b6b8eaad..8fb33321 100644 --- a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts +++ b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts @@ -4,7 +4,7 @@ import { MaybeAsync, BufferSource, CertificateRequest -} from 'THEOplayer'; +} from 'theoplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; import { extractContentId } from '../../utils/FairplayUtils'; diff --git a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts index 40f389b1..d975c2e0 100644 --- a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { VudrmFairplayContentProtectionIntegration } from './VudrmFairplayContentProtectionIntegration'; diff --git a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts index ed00d33a..83c48711 100644 --- a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts +++ b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource } from 'theoplayer'; import { isVudrmDRMConfiguration } from './VudrmUtil'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; diff --git a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts index efa314c9..e59efcc8 100644 --- a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { VudrmPlayReadyContentProtectionIntegration } from './VudrmPlayReadyContentProtectionIntegration'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; diff --git a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts index af98f24e..838505c2 100644 --- a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts +++ b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'THEOplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'theoplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; import { fromObjectToUint8Array, fromUint8ArrayToNumberArray } from '../../utils/TypeUtils'; diff --git a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts index f180c27a..dfffdddb 100644 --- a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts +++ b/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts @@ -1,4 +1,4 @@ -import { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'THEOplayer'; +import type { ContentProtectionIntegration, ContentProtectionIntegrationFactory } from 'theoplayer'; import { VudrmWidevineContentProtectionIntegration } from './VudrmWidevineContentProtectionIntegration'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; diff --git a/drm/src/utils/TypeUtils.ts b/drm/src/utils/TypeUtils.ts index 23b0e8b1..08c84f27 100644 --- a/drm/src/utils/TypeUtils.ts +++ b/drm/src/utils/TypeUtils.ts @@ -1,4 +1,4 @@ -import { utils } from 'THEOplayer'; +import { utils } from 'theoplayer'; export function fromObjectToUint8Array(obj: { [key: string]: any }): Uint8Array { return new TextEncoder().encode(JSON.stringify(obj)); From e2daae8d6621682d9fadb9bfd59e6797ac029488 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 17:01:45 +0200 Subject: [PATCH 72/85] Remove license --- drm/src/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/drm/src/index.ts b/drm/src/index.ts index 1419ed68..a566f369 100644 --- a/drm/src/index.ts +++ b/drm/src/index.ts @@ -53,5 +53,3 @@ export { TitaniumPlayReadyContentProtectionIntegrationFactory, TitaniumFairplayContentProtectionIntegrationFactory }; - -export const THEOPLAYER_LICENSE = 'YOUR_LICENSE_HERE'; From 31f56232f985064a90eefda740576c79abe7a055 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 17:11:27 +0200 Subject: [PATCH 73/85] Moves --- drm/src/{integration => }/axinomdrm/AxinomDrmConfiguration.ts | 0 .../AxinomDrmFairplayContentProtectionIntegration.ts | 0 .../AxinomDrmFairplayContentProtectionIntegrationFactory.ts | 0 .../AxinomDrmPlayReadyContentProtectionIntegration.ts | 0 .../AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/axinomdrm/AxinomDrmUtils.ts | 0 .../AxinomDrmWidevineContentProtectionIntegration.ts | 0 .../AxinomDrmWidevineContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/azuredrm/AzureDrmConfiguration.ts | 0 .../azuredrm/AzureDrmFairplayContentProtectionIntegration.ts | 4 ++-- .../AzureDrmFairplayContentProtectionIntegrationFactory.ts | 0 .../azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts | 0 .../AzureDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/azuredrm/AzureDrmUtils.ts | 0 .../azuredrm/AzureDrmWidevineContentProtectionIntegration.ts | 0 .../AzureDrmWidevineContentProtectionIntegrationFactory.ts | 0 .../{integration => }/castlabs/CastLabsDrmConfiguration.ts | 0 .../CastLabsDrmFairPlayContentProtectionIntegration.ts | 4 ++-- .../CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/castlabs/CastLabsDrmUtils.ts | 2 +- .../{integration => }/comcastdrm/ComcastDrmConfiguration.ts | 0 .../ComcastDrmFairPlayContentProtectionIntegration.ts | 4 ++-- .../ComcastDrmFairPlayContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/comcastdrm/ComcastDrmUtils.ts | 0 .../ComcastDrmWidevineContentProtectionIntegration.ts | 2 +- .../ComcastDrmWidevineContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/ezdrm/EzdrmDrmConfiguration.ts | 0 .../ezdrm/EzdrmFairplayContentProtectionIntegration.ts | 2 +- .../ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts | 0 .../irdetocontrol/IrdetoControlConfiguration.ts | 0 .../IrdetoControlFairplayContentProtectionIntegration.ts | 0 ...rdetoControlFairplayContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/keyos/KeyOSDrmConfiguration.ts | 0 .../keyos/KeyOSDrmFairplayContentProtectionIntegration.ts | 2 +- .../KeyOSDrmFairplayContentProtectionIntegrationFactory.ts | 0 .../keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts | 0 .../KeyOSDrmPlayReadyContentProtectionIntegrationFactory.ts} | 0 drm/src/{integration => }/keyos/KeyOSDrmUtils.ts | 0 .../keyos/KeyOSDrmWidevineContentProtectionIntegration.ts | 0 .../KeyOSDrmWidevineContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/nagradrm/NagraDrmConfiguration.ts | 0 .../nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts | 2 +- .../NagraDrmFairPlayContentProtectionIntegrationFactory.ts | 0 .../nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts | 0 .../NagraDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/nagradrm/NagraDrmUtils.ts | 0 .../nagradrm/NagraDrmWidevineContentProtectionIntegration.ts | 0 .../NagraDrmWidevineContentProtectionIntegrationFactory.ts | 0 .../{integration => }/titaniumdrm/TitaniumBaseRegistration.ts | 3 +-- .../{integration => }/titaniumdrm/TitaniumDrmConfiguration.ts | 0 .../TitaniumFairplayContentProtectionIntegration.ts | 0 .../TitaniumFairplayContentProtectionIntegrationFactory.ts | 0 .../titaniumdrm/TitaniumIntegrationParameters.ts | 0 .../TitaniumPlayReadyContentProtectionIntegration.ts | 0 .../TitaniumPlayReadyContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/titaniumdrm/TitaniumUtils.ts | 1 - .../TitaniumWidevineContentProtectionIntegration.ts | 0 .../TitaniumWidevineContentProtectionIntegrationFactory.ts | 0 .../verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts | 0 .../VerimatrixCoreDrmFairplayContentProtectionIntegration.ts | 2 +- ...atrixCoreDrmFairplayContentProtectionIntegrationFactory.ts | 0 .../VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts | 0 ...trixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts | 0 .../VerimatrixCoreDrmWidevineContentProtectionIntegration.ts | 0 ...atrixCoreDrmWidevineContentProtectionIntegrationFactory.ts | 0 .../verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts | 0 drm/src/{integration => }/vudrm/VudrmDrmConfiguration.ts | 0 .../vudrm/VudrmFairplayContentProtectionIntegration.ts | 4 ++-- .../vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts | 0 .../vudrm/VudrmPlayReadyContentProtectionIntegration.ts | 0 .../VudrmPlayReadyContentProtectionIntegrationFactory.ts | 0 drm/src/{integration => }/vudrm/VudrmUtil.ts | 0 .../vudrm/VudrmWidevineContentProtectionIntegration.ts | 2 +- .../vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts | 0 74 files changed, 16 insertions(+), 18 deletions(-) rename drm/src/{integration => }/axinomdrm/AxinomDrmConfiguration.ts (100%) rename drm/src/{integration => }/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/axinomdrm/AxinomDrmUtils.ts (100%) rename drm/src/{integration => }/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/azuredrm/AzureDrmConfiguration.ts (100%) rename drm/src/{integration => }/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts (96%) rename drm/src/{integration => }/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/azuredrm/AzureDrmUtils.ts (100%) rename drm/src/{integration => }/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/castlabs/CastLabsDrmConfiguration.ts (100%) rename drm/src/{integration => }/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts (94%) rename drm/src/{integration => }/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/castlabs/CastLabsDrmUtils.ts (75%) rename drm/src/{integration => }/comcastdrm/ComcastDrmConfiguration.ts (100%) rename drm/src/{integration => }/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts (96%) rename drm/src/{integration => }/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/comcastdrm/ComcastDrmUtils.ts (100%) rename drm/src/{integration => }/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts (98%) rename drm/src/{integration => }/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/ezdrm/EzdrmDrmConfiguration.ts (100%) rename drm/src/{integration => }/ezdrm/EzdrmFairplayContentProtectionIntegration.ts (96%) rename drm/src/{integration => }/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/irdetocontrol/IrdetoControlConfiguration.ts (100%) rename drm/src/{integration => }/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/keyos/KeyOSDrmConfiguration.ts (100%) rename drm/src/{integration => }/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts (98%) rename drm/src/{integration => }/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts (100%) rename drm/src/{integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts => keyos/KeyOSDrmPlayReadyContentProtectionIntegrationFactory.ts} (100%) rename drm/src/{integration => }/keyos/KeyOSDrmUtils.ts (100%) rename drm/src/{integration => }/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/nagradrm/NagraDrmConfiguration.ts (100%) rename drm/src/{integration => }/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts (97%) rename drm/src/{integration => }/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/nagradrm/NagraDrmUtils.ts (100%) rename drm/src/{integration => }/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/titaniumdrm/TitaniumBaseRegistration.ts (98%) rename drm/src/{integration => }/titaniumdrm/TitaniumDrmConfiguration.ts (100%) rename drm/src/{integration => }/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/titaniumdrm/TitaniumIntegrationParameters.ts (100%) rename drm/src/{integration => }/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/titaniumdrm/TitaniumUtils.ts (97%) rename drm/src/{integration => }/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts (100%) rename drm/src/{integration => }/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts (98%) rename drm/src/{integration => }/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts (100%) rename drm/src/{integration => }/vudrm/VudrmDrmConfiguration.ts (100%) rename drm/src/{integration => }/vudrm/VudrmFairplayContentProtectionIntegration.ts (96%) rename drm/src/{integration => }/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/vudrm/VudrmPlayReadyContentProtectionIntegration.ts (100%) rename drm/src/{integration => }/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts (100%) rename drm/src/{integration => }/vudrm/VudrmUtil.ts (100%) rename drm/src/{integration => }/vudrm/VudrmWidevineContentProtectionIntegration.ts (98%) rename drm/src/{integration => }/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts (100%) diff --git a/drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts b/drm/src/axinomdrm/AxinomDrmConfiguration.ts similarity index 100% rename from drm/src/integration/axinomdrm/AxinomDrmConfiguration.ts rename to drm/src/axinomdrm/AxinomDrmConfiguration.ts diff --git a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts b/drm/src/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts rename to drm/src/axinomdrm/AxinomDrmFairplayContentProtectionIntegration.ts diff --git a/drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts b/drm/src/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegration.ts diff --git a/drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/axinomdrm/AxinomDrmUtils.ts b/drm/src/axinomdrm/AxinomDrmUtils.ts similarity index 100% rename from drm/src/integration/axinomdrm/AxinomDrmUtils.ts rename to drm/src/axinomdrm/AxinomDrmUtils.ts diff --git a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts b/drm/src/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts rename to drm/src/axinomdrm/AxinomDrmWidevineContentProtectionIntegration.ts diff --git a/drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/azuredrm/AzureDrmConfiguration.ts b/drm/src/azuredrm/AzureDrmConfiguration.ts similarity index 100% rename from drm/src/integration/azuredrm/AzureDrmConfiguration.ts rename to drm/src/azuredrm/AzureDrmConfiguration.ts diff --git a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts b/drm/src/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts similarity index 96% rename from drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts rename to drm/src/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts index e109ceae..89501765 100644 --- a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/azuredrm/AzureDrmFairplayContentProtectionIntegration.ts @@ -8,8 +8,8 @@ import { } from 'theoplayer'; import { AzureDrmConfiguration } from './AzureDrmConfiguration'; import { isAzureDrmDRMConfiguration } from './AzureDrmUtils'; -import { extractContentId, unwrapCkc } from '../../utils/FairplayUtils'; -import { fromStringToUint8Array, fromUint8ArrayToBase64String } from '../../utils/TypeUtils'; +import { extractContentId, unwrapCkc } from '../utils/FairplayUtils'; +import { fromStringToUint8Array, fromUint8ArrayToBase64String } from '../utils/TypeUtils'; export class AzureDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: AzureDrmConfiguration; diff --git a/drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts b/drm/src/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/azuredrm/AzureDrmPlayReadyContentProtectionIntegration.ts diff --git a/drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/azuredrm/AzureDrmUtils.ts b/drm/src/azuredrm/AzureDrmUtils.ts similarity index 100% rename from drm/src/integration/azuredrm/AzureDrmUtils.ts rename to drm/src/azuredrm/AzureDrmUtils.ts diff --git a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts b/drm/src/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts rename to drm/src/azuredrm/AzureDrmWidevineContentProtectionIntegration.ts diff --git a/drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/castlabs/CastLabsDrmConfiguration.ts b/drm/src/castlabs/CastLabsDrmConfiguration.ts similarity index 100% rename from drm/src/integration/castlabs/CastLabsDrmConfiguration.ts rename to drm/src/castlabs/CastLabsDrmConfiguration.ts diff --git a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts b/drm/src/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts similarity index 94% rename from drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts rename to drm/src/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts index 12cf88f7..1cfaa4e5 100644 --- a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/castlabs/CastLabsDrmFairPlayContentProtectionIntegration.ts @@ -7,8 +7,8 @@ import { MaybeAsync } from 'theoplayer'; import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; -import { unwrapCkc } from '../../utils/FairplayUtils'; -import { fromObjectToBase64String, fromStringToUint8Array, fromUint8ArrayToBase64String } from '../../utils/TypeUtils'; +import { unwrapCkc } from '../utils/FairplayUtils'; +import { fromObjectToBase64String, fromStringToUint8Array, fromUint8ArrayToBase64String } from '../utils/TypeUtils'; export class CastLabsDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: CastLabsDrmConfiguration; diff --git a/drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts rename to drm/src/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/castlabs/CastLabsDrmUtils.ts b/drm/src/castlabs/CastLabsDrmUtils.ts similarity index 75% rename from drm/src/integration/castlabs/CastLabsDrmUtils.ts rename to drm/src/castlabs/CastLabsDrmUtils.ts index 8a821be0..51d2034e 100644 --- a/drm/src/integration/castlabs/CastLabsDrmUtils.ts +++ b/drm/src/castlabs/CastLabsDrmUtils.ts @@ -1,6 +1,6 @@ import { CastLabsDrmConfiguration } from './CastLabsDrmConfiguration'; -export function isDCastLabsDrmDRMConfiguration(configuration: CastLabsDrmConfiguration): boolean { +export function isCastLabsDrmDRMConfiguration(configuration: CastLabsDrmConfiguration): boolean { return ( configuration.integrationParameters.merchant !== undefined && configuration.integrationParameters.sessionId !== undefined && diff --git a/drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts b/drm/src/comcastdrm/ComcastDrmConfiguration.ts similarity index 100% rename from drm/src/integration/comcastdrm/ComcastDrmConfiguration.ts rename to drm/src/comcastdrm/ComcastDrmConfiguration.ts diff --git a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts b/drm/src/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts similarity index 96% rename from drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts rename to drm/src/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts index 5a6076c6..d113a175 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/comcastdrm/ComcastDrmFairPlayContentProtectionIntegration.ts @@ -1,13 +1,13 @@ import { BufferSource, ContentProtectionIntegration, LicenseRequest, LicenseResponse, MaybeAsync } from 'theoplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; -import { extractContentId } from '../../utils/FairplayUtils'; +import { extractContentId } from '../utils/FairplayUtils'; import { fromBase64StringToArrayBuffer, fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToObject -} from '../../utils/TypeUtils'; +} from '../utils/TypeUtils'; export class ComcastDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: ComcastDrmConfiguration; diff --git a/drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts rename to drm/src/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/comcastdrm/ComcastDrmUtils.ts b/drm/src/comcastdrm/ComcastDrmUtils.ts similarity index 100% rename from drm/src/integration/comcastdrm/ComcastDrmUtils.ts rename to drm/src/comcastdrm/ComcastDrmUtils.ts diff --git a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts b/drm/src/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts similarity index 98% rename from drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts rename to drm/src/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts index 1a2a1b35..c6de68fa 100644 --- a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts +++ b/drm/src/comcastdrm/ComcastDrmWidevineContentProtectionIntegration.ts @@ -9,7 +9,7 @@ import { } from 'theoplayer'; import { ComcastDrmConfiguration } from './ComcastDrmConfiguration'; import { isComcastDrmDRMConfiguration } from './ComcastDrmUtils'; -import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToString } from '../../utils/TypeUtils'; +import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToString } from '../utils/TypeUtils'; export class ComcastDrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: ComcastDrmConfiguration; diff --git a/drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts b/drm/src/ezdrm/EzdrmDrmConfiguration.ts similarity index 100% rename from drm/src/integration/ezdrm/EzdrmDrmConfiguration.ts rename to drm/src/ezdrm/EzdrmDrmConfiguration.ts diff --git a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts b/drm/src/ezdrm/EzdrmFairplayContentProtectionIntegration.ts similarity index 96% rename from drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts rename to drm/src/ezdrm/EzdrmFairplayContentProtectionIntegration.ts index 5541ae8b..90516ed3 100644 --- a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegration.ts +++ b/drm/src/ezdrm/EzdrmFairplayContentProtectionIntegration.ts @@ -1,6 +1,6 @@ import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'theoplayer'; import { EzdrmDrmConfiguration } from './EzdrmDrmConfiguration'; -import { extractContentId } from '../../utils/FairplayUtils'; +import { extractContentId } from '../utils/FairplayUtils'; export class EzdrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { static readonly DEFAULT_CERTIFICATE_URL = 'insert default certificate url here'; diff --git a/drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts b/drm/src/irdetocontrol/IrdetoControlConfiguration.ts similarity index 100% rename from drm/src/integration/irdetocontrol/IrdetoControlConfiguration.ts rename to drm/src/irdetocontrol/IrdetoControlConfiguration.ts diff --git a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts b/drm/src/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts rename to drm/src/irdetocontrol/IrdetoControlFairplayContentProtectionIntegration.ts diff --git a/drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts b/drm/src/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts rename to drm/src/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/keyos/KeyOSDrmConfiguration.ts b/drm/src/keyos/KeyOSDrmConfiguration.ts similarity index 100% rename from drm/src/integration/keyos/KeyOSDrmConfiguration.ts rename to drm/src/keyos/KeyOSDrmConfiguration.ts diff --git a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts b/drm/src/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts similarity index 98% rename from drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts rename to drm/src/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts index 41d45794..92182cbf 100644 --- a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/keyos/KeyOSDrmFairplayContentProtectionIntegration.ts @@ -13,7 +13,7 @@ import { fromStringToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToUtf8String -} from '../../utils/TypeUtils'; +} from '../utils/TypeUtils'; export class KeyOSDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: KeyOSDrmConfiguration; diff --git a/drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts b/drm/src/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/keyos/KeyOSDrmPlayReadyContentProtectionIntegration.ts diff --git a/drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/keyos/KeyOSDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/keyos/KeyOSDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/keyos/KeyOSDrmUtils.ts b/drm/src/keyos/KeyOSDrmUtils.ts similarity index 100% rename from drm/src/integration/keyos/KeyOSDrmUtils.ts rename to drm/src/keyos/KeyOSDrmUtils.ts diff --git a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts b/drm/src/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts rename to drm/src/keyos/KeyOSDrmWidevineContentProtectionIntegration.ts diff --git a/drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/nagradrm/NagraDrmConfiguration.ts b/drm/src/nagradrm/NagraDrmConfiguration.ts similarity index 100% rename from drm/src/integration/nagradrm/NagraDrmConfiguration.ts rename to drm/src/nagradrm/NagraDrmConfiguration.ts diff --git a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts b/drm/src/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts similarity index 97% rename from drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts rename to drm/src/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts index 000beb1e..1964d3e9 100644 --- a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts +++ b/drm/src/nagradrm/NagraDrmFairPlayContentProtectionIntegration.ts @@ -8,7 +8,7 @@ import { } from 'theoplayer'; import { NagraDrmConfiguration } from './NagraDrmConfiguration'; import { isNagraDrmDRMConfiguration } from './NagraDrmUtils'; -import { fromBase64StringToArrayBuffer, fromBase64StringToString, fromUint8ArrayToObject } from '../../utils/TypeUtils'; +import { fromBase64StringToArrayBuffer, fromBase64StringToString, fromUint8ArrayToObject } from '../utils/TypeUtils'; export class NagraDrmFairPlayContentProtectionIntegration implements ContentProtectionIntegration { private readonly contentProtectionConfiguration: NagraDrmConfiguration; diff --git a/drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts b/drm/src/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts rename to drm/src/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts b/drm/src/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/nagradrm/NagraDrmPlayReadyContentProtectionIntegration.ts diff --git a/drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/nagradrm/NagraDrmUtils.ts b/drm/src/nagradrm/NagraDrmUtils.ts similarity index 100% rename from drm/src/integration/nagradrm/NagraDrmUtils.ts rename to drm/src/nagradrm/NagraDrmUtils.ts diff --git a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts b/drm/src/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts rename to drm/src/nagradrm/NagraDrmWidevineContentProtectionIntegration.ts diff --git a/drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts b/drm/src/titaniumdrm/TitaniumBaseRegistration.ts similarity index 98% rename from drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts rename to drm/src/titaniumdrm/TitaniumBaseRegistration.ts index 42aa3426..feda3db2 100644 --- a/drm/src/integration/titaniumdrm/TitaniumBaseRegistration.ts +++ b/drm/src/titaniumdrm/TitaniumBaseRegistration.ts @@ -1,10 +1,9 @@ -/* eslint-disable no-unused-vars */ import { isDeviceBasedTitaniumDRMConfiguration, isTokenBasedTitaniumDRMConfiguration } from './TitaniumUtils'; import type { DeviceBasedTitaniumIntegrationParameters } from './TitaniumIntegrationParameters'; import type { TitaniumDrmConfiguration } from './TitaniumDrmConfiguration'; import type { ContentProtectionError } from 'theoplayer'; import { ErrorCode } from 'theoplayer'; -import { fromObjectToBase64String } from '../../utils/TypeUtils'; +import { fromObjectToBase64String } from '../utils/TypeUtils'; export interface TitaniumDeviceAuthorizationData { LatensRegistration: TitaniumLatensRegistration; diff --git a/drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts b/drm/src/titaniumdrm/TitaniumDrmConfiguration.ts similarity index 100% rename from drm/src/integration/titaniumdrm/TitaniumDrmConfiguration.ts rename to drm/src/titaniumdrm/TitaniumDrmConfiguration.ts diff --git a/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts b/drm/src/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts rename to drm/src/titaniumdrm/TitaniumFairplayContentProtectionIntegration.ts diff --git a/drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts b/drm/src/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts rename to drm/src/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts b/drm/src/titaniumdrm/TitaniumIntegrationParameters.ts similarity index 100% rename from drm/src/integration/titaniumdrm/TitaniumIntegrationParameters.ts rename to drm/src/titaniumdrm/TitaniumIntegrationParameters.ts diff --git a/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts b/drm/src/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts rename to drm/src/titaniumdrm/TitaniumPlayReadyContentProtectionIntegration.ts diff --git a/drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/titaniumdrm/TitaniumUtils.ts b/drm/src/titaniumdrm/TitaniumUtils.ts similarity index 97% rename from drm/src/integration/titaniumdrm/TitaniumUtils.ts rename to drm/src/titaniumdrm/TitaniumUtils.ts index 0bfacca0..be994fd3 100644 --- a/drm/src/integration/titaniumdrm/TitaniumUtils.ts +++ b/drm/src/titaniumdrm/TitaniumUtils.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-undef */ import type { DeviceBasedTitaniumIntegrationParameters, TitaniumIntegrationParameters, diff --git a/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts b/drm/src/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts rename to drm/src/titaniumdrm/TitaniumWidevineContentProtectionIntegration.ts diff --git a/drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts b/drm/src/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts rename to drm/src/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts b/drm/src/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts similarity index 100% rename from drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts rename to drm/src/verimatrixcoredrm/VerimatrixCoreDrmConfiguration.ts diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts b/drm/src/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts similarity index 98% rename from drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts rename to drm/src/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts index c28b123a..133ddbb4 100644 --- a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts +++ b/drm/src/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegration.ts @@ -5,7 +5,7 @@ import { fromObjectToUint8Array, fromUint8ArrayToBase64String, fromUint8ArrayToObject -} from '../../utils/TypeUtils'; +} from '../utils/TypeUtils'; export class VerimatrixCoreDrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { static readonly DEFAULT_LICENSE_URL = 'insert default license url here'; diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts b/drm/src/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts rename to drm/src/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegration.ts diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts b/drm/src/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts rename to drm/src/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegration.ts diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts b/drm/src/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts similarity index 100% rename from drm/src/integration/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts rename to drm/src/verimatrixcoredrm/VerimatrixCoreIntegrationParameters.ts diff --git a/drm/src/integration/vudrm/VudrmDrmConfiguration.ts b/drm/src/vudrm/VudrmDrmConfiguration.ts similarity index 100% rename from drm/src/integration/vudrm/VudrmDrmConfiguration.ts rename to drm/src/vudrm/VudrmDrmConfiguration.ts diff --git a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts b/drm/src/vudrm/VudrmFairplayContentProtectionIntegration.ts similarity index 96% rename from drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts rename to drm/src/vudrm/VudrmFairplayContentProtectionIntegration.ts index 8fb33321..60b0fc5e 100644 --- a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegration.ts +++ b/drm/src/vudrm/VudrmFairplayContentProtectionIntegration.ts @@ -7,8 +7,8 @@ import { } from 'theoplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; -import { extractContentId } from '../../utils/FairplayUtils'; -import { fromObjectToUint8Array, fromUint8ArrayToBase64String } from '../../utils/TypeUtils'; +import { extractContentId } from '../utils/FairplayUtils'; +import { fromObjectToUint8Array, fromUint8ArrayToBase64String } from '../utils/TypeUtils'; export class VudrmFairplayContentProtectionIntegration implements ContentProtectionIntegration { static readonly DEFAULT_CERTIFICATE_URL = 'https://fairplay-license.drm.technology/certificate'; diff --git a/drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts b/drm/src/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts rename to drm/src/vudrm/VudrmFairplayContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts b/drm/src/vudrm/VudrmPlayReadyContentProtectionIntegration.ts similarity index 100% rename from drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegration.ts rename to drm/src/vudrm/VudrmPlayReadyContentProtectionIntegration.ts diff --git a/drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts b/drm/src/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts rename to drm/src/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory.ts diff --git a/drm/src/integration/vudrm/VudrmUtil.ts b/drm/src/vudrm/VudrmUtil.ts similarity index 100% rename from drm/src/integration/vudrm/VudrmUtil.ts rename to drm/src/vudrm/VudrmUtil.ts diff --git a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts b/drm/src/vudrm/VudrmWidevineContentProtectionIntegration.ts similarity index 98% rename from drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts rename to drm/src/vudrm/VudrmWidevineContentProtectionIntegration.ts index 838505c2..699d63ee 100644 --- a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts +++ b/drm/src/vudrm/VudrmWidevineContentProtectionIntegration.ts @@ -1,7 +1,7 @@ import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'theoplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; -import { fromObjectToUint8Array, fromUint8ArrayToNumberArray } from '../../utils/TypeUtils'; +import { fromObjectToUint8Array, fromUint8ArrayToNumberArray } from '../utils/TypeUtils'; export class VudrmWidevineContentProtectionIntegration implements ContentProtectionIntegration { static readonly DEFAULT_LICENSE_URL = 'https://widevine-proxy.drm.technology/proxy'; diff --git a/drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts b/drm/src/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts similarity index 100% rename from drm/src/integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts rename to drm/src/vudrm/VudrmWidevineContentProtectionIntegrationFactory.ts From d6174049a8fd2ec272783209a5204caf68c0e080 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 17:16:53 +0200 Subject: [PATCH 74/85] Prettier --- .../vudrm/VudrmFairplayContentProtectionIntegration.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drm/src/vudrm/VudrmFairplayContentProtectionIntegration.ts b/drm/src/vudrm/VudrmFairplayContentProtectionIntegration.ts index 60b0fc5e..ea05dc84 100644 --- a/drm/src/vudrm/VudrmFairplayContentProtectionIntegration.ts +++ b/drm/src/vudrm/VudrmFairplayContentProtectionIntegration.ts @@ -1,10 +1,4 @@ -import { - ContentProtectionIntegration, - LicenseRequest, - MaybeAsync, - BufferSource, - CertificateRequest -} from 'theoplayer'; +import { ContentProtectionIntegration, LicenseRequest, MaybeAsync, BufferSource, CertificateRequest } from 'theoplayer'; import { VudrmDrmConfiguration } from './VudrmDrmConfiguration'; import { isVudrmDRMConfiguration } from './VudrmUtil'; import { extractContentId } from '../utils/FairplayUtils'; From a712594265e035260845290150bc4b4a101e381d Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 17:17:09 +0200 Subject: [PATCH 75/85] Export everything with barrel files --- drm/src/axinomdrm/barrel.ts | 9 ++++ drm/src/azuredrm/barrel.ts | 9 ++++ drm/src/castlabs/barrel.ts | 5 +++ drm/src/comcastdrm/barrel.ts | 7 +++ drm/src/ezdrm/barrel.ts | 4 ++ drm/src/index.ts | 66 +++++------------------------ drm/src/irdetocontrol/barrel.ts | 4 ++ drm/src/keyos/barrel.ts | 9 ++++ drm/src/nagradrm/barrel.ts | 9 ++++ drm/src/titaniumdrm/barrel.ts | 11 +++++ drm/src/verimatrixcoredrm/barrel.ts | 9 ++++ drm/src/vudrm/barrel.ts | 9 ++++ 12 files changed, 96 insertions(+), 55 deletions(-) create mode 100644 drm/src/axinomdrm/barrel.ts create mode 100644 drm/src/azuredrm/barrel.ts create mode 100644 drm/src/castlabs/barrel.ts create mode 100644 drm/src/comcastdrm/barrel.ts create mode 100644 drm/src/ezdrm/barrel.ts create mode 100644 drm/src/irdetocontrol/barrel.ts create mode 100644 drm/src/keyos/barrel.ts create mode 100644 drm/src/nagradrm/barrel.ts create mode 100644 drm/src/titaniumdrm/barrel.ts create mode 100644 drm/src/verimatrixcoredrm/barrel.ts create mode 100644 drm/src/vudrm/barrel.ts diff --git a/drm/src/axinomdrm/barrel.ts b/drm/src/axinomdrm/barrel.ts new file mode 100644 index 00000000..e1445306 --- /dev/null +++ b/drm/src/axinomdrm/barrel.ts @@ -0,0 +1,9 @@ +export * from './AxinomDrmConfiguration'; +export * from './AxinomDrmUtils'; + +export * from './AxinomDrmFairplayContentProtectionIntegration'; +export * from './AxinomDrmFairplayContentProtectionIntegrationFactory'; +export * from './AxinomDrmPlayReadyContentProtectionIntegration'; +export * from './AxinomDrmPlayReadyContentProtectionIntegrationFactory'; +export * from './AxinomDrmWidevineContentProtectionIntegration'; +export * from './AxinomDrmWidevineContentProtectionIntegrationFactory'; diff --git a/drm/src/azuredrm/barrel.ts b/drm/src/azuredrm/barrel.ts new file mode 100644 index 00000000..03e6850b --- /dev/null +++ b/drm/src/azuredrm/barrel.ts @@ -0,0 +1,9 @@ +export * from './AzureDrmConfiguration'; +export * from './AzureDrmUtils'; + +export * from './AzureDrmFairplayContentProtectionIntegration'; +export * from './AzureDrmFairplayContentProtectionIntegrationFactory'; +export * from './AzureDrmPlayReadyContentProtectionIntegration'; +export * from './AzureDrmPlayReadyContentProtectionIntegrationFactory'; +export * from './AzureDrmWidevineContentProtectionIntegration'; +export * from './AzureDrmWidevineContentProtectionIntegrationFactory'; diff --git a/drm/src/castlabs/barrel.ts b/drm/src/castlabs/barrel.ts new file mode 100644 index 00000000..e87ca4a1 --- /dev/null +++ b/drm/src/castlabs/barrel.ts @@ -0,0 +1,5 @@ +export * from './CastLabsDrmConfiguration'; +export * from './CastLabsDrmUtils'; + +export * from './CastLabsDrmFairPlayContentProtectionIntegration'; +export * from './CastLabsDrmFairPlayContentProtectionIntegrationFactory'; diff --git a/drm/src/comcastdrm/barrel.ts b/drm/src/comcastdrm/barrel.ts new file mode 100644 index 00000000..8750d736 --- /dev/null +++ b/drm/src/comcastdrm/barrel.ts @@ -0,0 +1,7 @@ +export * from './ComcastDrmConfiguration'; +export * from './ComcastDrmUtils'; + +export * from './ComcastDrmFairPlayContentProtectionIntegration'; +export * from './ComcastDrmFairPlayContentProtectionIntegrationFactory'; +export * from './ComcastDrmWidevineContentProtectionIntegration'; +export * from './ComcastDrmWidevineContentProtectionIntegrationFactory'; diff --git a/drm/src/ezdrm/barrel.ts b/drm/src/ezdrm/barrel.ts new file mode 100644 index 00000000..6be7935b --- /dev/null +++ b/drm/src/ezdrm/barrel.ts @@ -0,0 +1,4 @@ +export * from './EzdrmDrmConfiguration'; + +export * from './EzdrmFairplayContentProtectionIntegration'; +export * from './EzdrmFairplayContentProtectionIntegrationFactory'; diff --git a/drm/src/index.ts b/drm/src/index.ts index a566f369..9f02fa3a 100644 --- a/drm/src/index.ts +++ b/drm/src/index.ts @@ -1,55 +1,11 @@ -import { VudrmWidevineContentProtectionIntegrationFactory } from './integration/vudrm/VudrmWidevineContentProtectionIntegrationFactory'; -import { VudrmPlayReadyContentProtectionIntegrationFactory } from './integration/vudrm/VudrmPlayReadyContentProtectionIntegrationFactory'; -import { VudrmFairplayContentProtectionIntegrationFactory } from './integration/vudrm/VudrmFairplayContentProtectionIntegrationFactory'; -import { EzdrmFairplayContentProtectionIntegrationFactory } from './integration/ezdrm/EzdrmFairplayContentProtectionIntegrationFactory'; -import { AzureDrmWidevineContentProtectionIntegrationFactory } from './integration/azuredrm/AzureDrmWidevineContentProtectionIntegrationFactory'; -import { AzureDrmPlayReadyContentProtectionIntegrationFactory } from './integration/azuredrm/AzureDrmPlayReadyContentProtectionIntegrationFactory'; -import { AzureDrmFairplayContentProtectionIntegrationFactory } from './integration/azuredrm/AzureDrmFairplayContentProtectionIntegrationFactory'; -import { AxinomDrmWidevineContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmWidevineContentProtectionIntegrationFactory'; -import { AxinomDrmPlayReadyContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmPlayReadyContentProtectionIntegrationFactory'; -import { AxinomDrmFairplayContentProtectionIntegrationFactory } from './integration/axinomdrm/AxinomDrmFairplayContentProtectionIntegrationFactory'; -import { ComcastDrmWidevineContentProtectionIntegrationFactory } from './integration/comcastdrm/ComcastDrmWidevineContentProtectionIntegrationFactory'; -import { ComcastDrmFairPlayContentProtectionIntegrationFactory } from './integration/comcastdrm/ComcastDrmFairPlayContentProtectionIntegrationFactory'; -import { CastLabsDrmFairPlayContentProtectionIntegrationFactory } from './integration/castlabs/CastLabsDrmFairPlayContentProtectionIntegrationFactory'; -import { IrdetoControlFairplayContentProtectionIntegrationFactory } from './integration/irdetocontrol/IrdetoControlFairplayContentProtectionIntegrationFactory'; -import { NagraDrmWidevineContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmWidevineContentProtectionIntegrationFactory'; -import { NagraDrmPlayReadyContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmPlayReadyContentProtectionIntegrationFactory'; -import { NagraDrmFairPlayContentProtectionIntegrationFactory } from './integration/nagradrm/NagraDrmFairPlayContentProtectionIntegrationFactory'; -import { KeyOSDrmFairplayContentProtectionIntegrationFactory } from './integration/keyos/KeyOSDrmFairplayContentProtectionIntegrationFactory'; -import { KeyOSDrmWidevineContentProtectionIntegrationFactory } from './integration/keyos/KeyOSDrmWidevineContentProtectionIntegrationFactory'; -import { KeyOSDrmPlayReadyContentProtectionIntegrationFactory } from './integration/keyos/keyOSDrmPlayReadyContentProtectionIntegrationFactory'; -import { VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory } from './integration/verimatrixcoredrm/VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory'; -import { VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory } from './integration/verimatrixcoredrm/VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory'; -import { VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory } from './integration/verimatrixcoredrm/VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory'; -import { TitaniumWidevineContentProtectionIntegrationFactory } from './integration/titaniumdrm/TitaniumWidevineContentProtectionIntegrationFactory'; -import { TitaniumPlayReadyContentProtectionIntegrationFactory } from './integration/titaniumdrm/TitaniumPlayReadyContentProtectionIntegrationFactory'; -import { TitaniumFairplayContentProtectionIntegrationFactory } from './integration/titaniumdrm/TitaniumFairplayContentProtectionIntegrationFactory'; - -export { - AxinomDrmWidevineContentProtectionIntegrationFactory, - AxinomDrmPlayReadyContentProtectionIntegrationFactory, - AxinomDrmFairplayContentProtectionIntegrationFactory, - VudrmWidevineContentProtectionIntegrationFactory, - VudrmPlayReadyContentProtectionIntegrationFactory, - VudrmFairplayContentProtectionIntegrationFactory, - EzdrmFairplayContentProtectionIntegrationFactory, - AzureDrmWidevineContentProtectionIntegrationFactory, - AzureDrmPlayReadyContentProtectionIntegrationFactory, - AzureDrmFairplayContentProtectionIntegrationFactory, - ComcastDrmWidevineContentProtectionIntegrationFactory, - ComcastDrmFairPlayContentProtectionIntegrationFactory, - IrdetoControlFairplayContentProtectionIntegrationFactory, - NagraDrmWidevineContentProtectionIntegrationFactory, - NagraDrmPlayReadyContentProtectionIntegrationFactory, - NagraDrmFairPlayContentProtectionIntegrationFactory, - KeyOSDrmWidevineContentProtectionIntegrationFactory, - KeyOSDrmFairplayContentProtectionIntegrationFactory, - KeyOSDrmPlayReadyContentProtectionIntegrationFactory, - VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory, - VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory, - VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory, - CastLabsDrmFairPlayContentProtectionIntegrationFactory, - TitaniumWidevineContentProtectionIntegrationFactory, - TitaniumPlayReadyContentProtectionIntegrationFactory, - TitaniumFairplayContentProtectionIntegrationFactory -}; +export * from './axinomdrm/barrel'; +export * from './azuredrm/barrel'; +export * from './castlabs/barrel'; +export * from './comcastdrm/barrel'; +export * from './ezdrm/barrel'; +export * from './irdetocontrol/barrel'; +export * from './keyos/barrel'; +export * from './nagradrm/barrel'; +export * from './titaniumdrm/barrel'; +export * from './verimatrixcoredrm/barrel'; +export * from './vudrm/barrel'; diff --git a/drm/src/irdetocontrol/barrel.ts b/drm/src/irdetocontrol/barrel.ts new file mode 100644 index 00000000..68a4c946 --- /dev/null +++ b/drm/src/irdetocontrol/barrel.ts @@ -0,0 +1,4 @@ +export * from './IrdetoControlConfiguration'; + +export * from './IrdetoControlFairplayContentProtectionIntegration'; +export * from './IrdetoControlFairplayContentProtectionIntegrationFactory'; diff --git a/drm/src/keyos/barrel.ts b/drm/src/keyos/barrel.ts new file mode 100644 index 00000000..9456f625 --- /dev/null +++ b/drm/src/keyos/barrel.ts @@ -0,0 +1,9 @@ +export * from './KeyOSDrmConfiguration'; +export * from './KeyOSDrmUtils'; + +export * from './KeyOSDrmFairplayContentProtectionIntegration'; +export * from './KeyOSDrmFairplayContentProtectionIntegrationFactory'; +export * from './KeyOSDrmPlayReadyContentProtectionIntegration'; +export * from './KeyOSDrmPlayReadyContentProtectionIntegrationFactory'; +export * from './KeyOSDrmWidevineContentProtectionIntegration'; +export * from './KeyOSDrmWidevineContentProtectionIntegrationFactory'; diff --git a/drm/src/nagradrm/barrel.ts b/drm/src/nagradrm/barrel.ts new file mode 100644 index 00000000..56ac4b35 --- /dev/null +++ b/drm/src/nagradrm/barrel.ts @@ -0,0 +1,9 @@ +export * from './NagraDrmConfiguration'; +export * from './NagraDrmUtils'; + +export * from './NagraDrmFairPlayContentProtectionIntegration'; +export * from './NagraDrmFairPlayContentProtectionIntegrationFactory'; +export * from './NagraDrmPlayReadyContentProtectionIntegration'; +export * from './NagraDrmPlayReadyContentProtectionIntegrationFactory'; +export * from './NagraDrmWidevineContentProtectionIntegration'; +export * from './NagraDrmWidevineContentProtectionIntegrationFactory'; diff --git a/drm/src/titaniumdrm/barrel.ts b/drm/src/titaniumdrm/barrel.ts new file mode 100644 index 00000000..140c664f --- /dev/null +++ b/drm/src/titaniumdrm/barrel.ts @@ -0,0 +1,11 @@ +export * from './TitaniumBaseRegistration'; +export * from './TitaniumDrmConfiguration'; +export * from './TitaniumIntegrationParameters'; +export * from './TitaniumUtils'; + +export * from './TitaniumFairplayContentProtectionIntegration'; +export * from './TitaniumFairplayContentProtectionIntegrationFactory'; +export * from './TitaniumPlayReadyContentProtectionIntegration'; +export * from './TitaniumPlayReadyContentProtectionIntegrationFactory'; +export * from './TitaniumWidevineContentProtectionIntegration'; +export * from './TitaniumWidevineContentProtectionIntegrationFactory'; diff --git a/drm/src/verimatrixcoredrm/barrel.ts b/drm/src/verimatrixcoredrm/barrel.ts new file mode 100644 index 00000000..0f1ca0d3 --- /dev/null +++ b/drm/src/verimatrixcoredrm/barrel.ts @@ -0,0 +1,9 @@ +export * from './VerimatrixCoreDrmConfiguration'; +export * from './VerimatrixCoreIntegrationParameters'; + +export * from './VerimatrixCoreDrmFairplayContentProtectionIntegration'; +export * from './VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory'; +export * from './VerimatrixCoreDrmPlayReadyContentProtectionIntegration'; +export * from './VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory'; +export * from './VerimatrixCoreDrmWidevineContentProtectionIntegration'; +export * from './VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory'; diff --git a/drm/src/vudrm/barrel.ts b/drm/src/vudrm/barrel.ts new file mode 100644 index 00000000..b113c5c7 --- /dev/null +++ b/drm/src/vudrm/barrel.ts @@ -0,0 +1,9 @@ +export * from './VudrmDrmConfiguration'; +export * from './VudrmUtil'; + +export * from './VudrmFairplayContentProtectionIntegration'; +export * from './VudrmFairplayContentProtectionIntegrationFactory'; +export * from './VudrmPlayReadyContentProtectionIntegration'; +export * from './VudrmPlayReadyContentProtectionIntegrationFactory'; +export * from './VudrmWidevineContentProtectionIntegration'; +export * from './VudrmWidevineContentProtectionIntegrationFactory'; From 4bb68e2bfcced7906cd62908c50f1ce726423cd1 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 17:25:56 +0200 Subject: [PATCH 76/85] Update example pages --- drm/README.md | 4 ++-- drm/package.json | 2 +- drm/test/axinomdrm/fairplay.html | 12 ++++++------ drm/test/axinomdrm/playready.html | 10 +++++----- drm/test/axinomdrm/widevine.html | 10 +++++----- drm/test/azuredrm/fairplay.html | 10 +++++----- drm/test/azuredrm/playready.html | 10 +++++----- drm/test/azuredrm/widevine.html | 10 +++++----- drm/test/castlabs/fairplay.html | 10 +++++----- drm/test/castlabs/playready.html | 8 ++++---- drm/test/castlabs/widevine.html | 8 ++++---- drm/test/comcastdrm/fairplay.html | 9 ++++----- drm/test/comcastdrm/playready.html | 8 ++++---- drm/test/comcastdrm/widevine.html | 10 +++++----- drm/test/ezdrm/fairplay.html | 10 +++++----- drm/test/irdetocontrol/fairplay.html | 10 +++++----- drm/test/irdetocontrol/playready.html | 8 ++++---- drm/test/irdetocontrol/widevine.html | 8 ++++---- drm/test/keyos/fairplay.html | 10 +++++----- drm/test/keyos/playready.html | 10 +++++----- drm/test/keyos/widevine.html | 10 +++++----- drm/test/nagradrm/fairplay.html | 10 +++++----- drm/test/nagradrm/playready.html | 10 +++++----- drm/test/nagradrm/widevine.html | 10 +++++----- drm/test/titaniumdrm/fairplay.html | 10 +++++----- drm/test/titaniumdrm/playready.html | 10 +++++----- drm/test/titaniumdrm/widevine.html | 10 +++++----- drm/test/verimatrixcoredrm/fairplay.html | 10 +++++----- drm/test/verimatrixcoredrm/playready.html | 10 +++++----- drm/test/verimatrixcoredrm/widevine.html | 10 +++++----- drm/test/vudrm/fairplay.html | 10 +++++----- drm/test/vudrm/playready.html | 10 +++++----- drm/test/vudrm/widevine.html | 10 +++++----- 33 files changed, 153 insertions(+), 154 deletions(-) diff --git a/drm/README.md b/drm/README.md index ca4ef9b5..3e4cc079 100644 --- a/drm/README.md +++ b/drm/README.md @@ -139,7 +139,7 @@ with THEOplayer by specifying a unique `integrationId`, such as `'custom_wv'` in THEOplayer.registerContentProtectionIntegration( 'custom_wv', 'widevine', - new ContentProtectionIntegrations.CustomContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.CustomContentProtectionIntegrationFactory() ); ``` The object `ContentProtectionIntegrations` is provided by the library `dist/bundle.js` and gives access to all exports from `src/index.ts`. @@ -172,7 +172,7 @@ passed during registration, an instance of `CustomContentProtectionIntegration` THEOplayer.registerContentProtectionIntegration( 'custom_wv', 'widevine', - new ContentProtectionIntegrations.CustomContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.CustomContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/package.json b/drm/package.json index 48e508b5..6f066b48 100644 --- a/drm/package.json +++ b/drm/package.json @@ -29,7 +29,7 @@ "bundle": "rollup -c rollup.config.mjs", "build": "npm run clean && npm run bundle", "watch": "npm run bundle -- --watch", - "serve": "http-server", + "serve": "http-server ../", "test": "echo \"No tests yet\"" }, "author": "THEO Technologies NV", diff --git a/drm/test/axinomdrm/fairplay.html b/drm/test/axinomdrm/fairplay.html index 58108463..958290b0 100644 --- a/drm/test/axinomdrm/fairplay.html +++ b/drm/test/axinomdrm/fairplay.html @@ -3,9 +3,9 @@ Axinom Fairplay Test - - - + + +
@@ -15,8 +15,8 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, - libraryLocation: '/THEOplayer/' + license: 'insert-your-license-here', + libraryLocation: '../../../node_modules/theoplayer/' }); const contentProtectionIdentifier = 'axinom'; @@ -24,7 +24,7 @@ THEOplayer.registerContentProtectionIntegration( contentProtectionIdentifier, 'fairplay', - new ContentProtectionIntegrations.AxinomDrmFairplayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.AxinomDrmFairplayContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/axinomdrm/playready.html b/drm/test/axinomdrm/playready.html index cf357757..aec75211 100644 --- a/drm/test/axinomdrm/playready.html +++ b/drm/test/axinomdrm/playready.html @@ -3,9 +3,9 @@ Axinom PlayReady Test - - - + + +
@@ -15,7 +15,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); @@ -24,7 +24,7 @@ THEOplayer.registerContentProtectionIntegration( contentProtectionIdentifier, 'playready', - new ContentProtectionIntegrations.AxinomDrmPlayReadyContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.AxinomDrmPlayReadyContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/axinomdrm/widevine.html b/drm/test/axinomdrm/widevine.html index eb187812..cef19856 100644 --- a/drm/test/axinomdrm/widevine.html +++ b/drm/test/axinomdrm/widevine.html @@ -3,9 +3,9 @@ Axinom Widevine Test - - - + + +
@@ -15,7 +15,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); @@ -24,7 +24,7 @@ THEOplayer.registerContentProtectionIntegration( contentProtectionIdentifier, 'widevine', - new ContentProtectionIntegrations.AxinomDrmWidevineContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.AxinomDrmWidevineContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/azuredrm/fairplay.html b/drm/test/azuredrm/fairplay.html index ec003a5f..b0ea83c3 100644 --- a/drm/test/azuredrm/fairplay.html +++ b/drm/test/azuredrm/fairplay.html @@ -3,9 +3,9 @@ Azure drm FairPlay Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'azure', 'fairplay', - new ContentProtectionIntegrations.AzureDrmFairplayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.AzureDrmFairplayContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/azuredrm/playready.html b/drm/test/azuredrm/playready.html index c8d56231..b26dde7f 100644 --- a/drm/test/azuredrm/playready.html +++ b/drm/test/azuredrm/playready.html @@ -3,9 +3,9 @@ Azure drm PlayReady Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'azure', 'playready', - new ContentProtectionIntegrations.AzureDrmPlayReadyContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.AzureDrmPlayReadyContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/azuredrm/widevine.html b/drm/test/azuredrm/widevine.html index b86967d7..a2e94d84 100644 --- a/drm/test/azuredrm/widevine.html +++ b/drm/test/azuredrm/widevine.html @@ -3,9 +3,9 @@ Azure drm Widevine Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'azure', 'widevine', - new ContentProtectionIntegrations.AzureDrmWidevineContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.AzureDrmWidevineContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/castlabs/fairplay.html b/drm/test/castlabs/fairplay.html index 23e9b35d..8c288780 100644 --- a/drm/test/castlabs/fairplay.html +++ b/drm/test/castlabs/fairplay.html @@ -3,9 +3,9 @@ CastLabs FairPlay Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'castlabs', 'fairplay', - new ContentProtectionIntegrations.CastLabsDrmFairPlayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.CastLabsDrmFairPlayContentProtectionIntegrationFactory() ); const src = ''; diff --git a/drm/test/castlabs/playready.html b/drm/test/castlabs/playready.html index c786702d..c9807e8f 100644 --- a/drm/test/castlabs/playready.html +++ b/drm/test/castlabs/playready.html @@ -3,9 +3,9 @@ CastLabs PlayReady Test - - - + + +

@@ -23,7 +23,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); diff --git a/drm/test/castlabs/widevine.html b/drm/test/castlabs/widevine.html index ce47262b..68fe401e 100644 --- a/drm/test/castlabs/widevine.html +++ b/drm/test/castlabs/widevine.html @@ -3,9 +3,9 @@ CastLabs Widevine Test - - - + + +

@@ -23,7 +23,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); diff --git a/drm/test/comcastdrm/fairplay.html b/drm/test/comcastdrm/fairplay.html index 32a884c1..50671ff1 100644 --- a/drm/test/comcastdrm/fairplay.html +++ b/drm/test/comcastdrm/fairplay.html @@ -3,10 +3,9 @@ Comcast DRM FairPlay Test - - - + +

@@ -41,14 +40,14 @@

Comcast DRM FairPlay

fluid: true }, mutedAutoplay: true, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'comcast', 'fairplay', - new ContentProtectionIntegrations.ComcastDrmFairPlayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.ComcastDrmFairPlayContentProtectionIntegrationFactory() ); let configureStream = function (src, token, releasePid, account, region, certificateURL) { diff --git a/drm/test/comcastdrm/playready.html b/drm/test/comcastdrm/playready.html index 2ce3e14c..2a3e1c00 100644 --- a/drm/test/comcastdrm/playready.html +++ b/drm/test/comcastdrm/playready.html @@ -3,10 +3,10 @@ Comcast DRM PlayReady Test - - - + + +
@@ -45,7 +45,7 @@

Comcast DRM PlayReady

fluid: true }, mutedAutoplay: true, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/' }); diff --git a/drm/test/comcastdrm/widevine.html b/drm/test/comcastdrm/widevine.html index 2b45abf3..c8d7c19b 100644 --- a/drm/test/comcastdrm/widevine.html +++ b/drm/test/comcastdrm/widevine.html @@ -3,10 +3,10 @@ Comcast DRM Widevine Test - - - + + +
@@ -41,7 +41,7 @@

Comcast DRM Widevine

fluid: true }, mutedAutoplay: true, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/' }); @@ -92,7 +92,7 @@

Comcast DRM Widevine

THEOplayer.registerContentProtectionIntegration( 'comcast', 'widevine', - new ContentProtectionIntegrations.ComcastDrmWidevineContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.ComcastDrmWidevineContentProtectionIntegrationFactory() ); const licenseAcquisitionURL = 'https://widevine.entitlement' + diff --git a/drm/test/ezdrm/fairplay.html b/drm/test/ezdrm/fairplay.html index 6bfe2237..cfba4e2c 100644 --- a/drm/test/ezdrm/fairplay.html +++ b/drm/test/ezdrm/fairplay.html @@ -3,9 +3,9 @@ Ezdrm Fairplay Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'ezdrm', 'fairplay', - new ContentProtectionIntegrations.EzdrmFairplayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.EzdrmFairplayContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/irdetocontrol/fairplay.html b/drm/test/irdetocontrol/fairplay.html index 8348fbe0..5913f5e6 100644 --- a/drm/test/irdetocontrol/fairplay.html +++ b/drm/test/irdetocontrol/fairplay.html @@ -3,9 +3,9 @@ Irdeto Control FairPlay Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'irdetocontrol', 'fairplay', - new ContentProtectionIntegrations.IrdetoControlFairplayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.IrdetoControlFairplayContentProtectionIntegrationFactory() ); const streamSrc = '.m3u8'; diff --git a/drm/test/irdetocontrol/playready.html b/drm/test/irdetocontrol/playready.html index d986976f..d56e1949 100644 --- a/drm/test/irdetocontrol/playready.html +++ b/drm/test/irdetocontrol/playready.html @@ -3,9 +3,9 @@ Irdeto Control PlayReady Test - - - + + +
@@ -15,7 +15,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); diff --git a/drm/test/irdetocontrol/widevine.html b/drm/test/irdetocontrol/widevine.html index e79f108c..66c148c9 100644 --- a/drm/test/irdetocontrol/widevine.html +++ b/drm/test/irdetocontrol/widevine.html @@ -3,9 +3,9 @@ Irdeto Control Widevine Test - - - + + +
@@ -15,7 +15,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); diff --git a/drm/test/keyos/fairplay.html b/drm/test/keyos/fairplay.html index f07a186c..163806ea 100644 --- a/drm/test/keyos/fairplay.html +++ b/drm/test/keyos/fairplay.html @@ -3,9 +3,9 @@ KeyOS drm FairPlay Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'keyos_buydrm', 'fairplay', - new ContentProtectionIntegrations.KeyOSDrmFairplayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.KeyOSDrmFairplayContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/keyos/playready.html b/drm/test/keyos/playready.html index bdb8ec77..d01e6568 100644 --- a/drm/test/keyos/playready.html +++ b/drm/test/keyos/playready.html @@ -3,9 +3,9 @@ KeyOS drm PlayReady Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'keyos_buydrm', 'playready', - new ContentProtectionIntegrations.KeyOSDrmPlayReadyContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.KeyOSDrmPlayReadyContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/keyos/widevine.html b/drm/test/keyos/widevine.html index ff0639d8..12770d3d 100644 --- a/drm/test/keyos/widevine.html +++ b/drm/test/keyos/widevine.html @@ -3,9 +3,9 @@ KeyOS drm Widevine Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'keyos_buydrm', 'widevine', - new ContentProtectionIntegrations.KeyOSDrmWidevineContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.KeyOSDrmWidevineContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/nagradrm/fairplay.html b/drm/test/nagradrm/fairplay.html index 013d5684..9fb78ba8 100644 --- a/drm/test/nagradrm/fairplay.html +++ b/drm/test/nagradrm/fairplay.html @@ -2,10 +2,10 @@ THEOplayer Web SDK Nagra FairPlay - - - + < + + @@ -37,7 +37,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); @@ -46,7 +46,7 @@ window.THEOplayer.registerContentProtectionIntegration( contentProtectionIdentifier, 'fairplay', - new ContentProtectionIntegrations.NagraDrmFairPlayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.NagraDrmFairPlayContentProtectionIntegrationFactory() ); player.source = { sources: [ diff --git a/drm/test/nagradrm/playready.html b/drm/test/nagradrm/playready.html index bafac8bf..85451ee7 100644 --- a/drm/test/nagradrm/playready.html +++ b/drm/test/nagradrm/playready.html @@ -2,10 +2,10 @@ THEOplayer Web SDK Nagra PlayReady - - - + + + @@ -33,7 +33,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); @@ -64,7 +64,7 @@ window.THEOplayer.registerContentProtectionIntegration( contentProtectionIdentifier, 'playready', - new ContentProtectionIntegrations.NagraDrmPlayReadyContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.NagraDrmPlayReadyContentProtectionIntegrationFactory() ); player.source = { sources: [ diff --git a/drm/test/nagradrm/widevine.html b/drm/test/nagradrm/widevine.html index 1fdd6e84..e080d434 100644 --- a/drm/test/nagradrm/widevine.html +++ b/drm/test/nagradrm/widevine.html @@ -2,10 +2,10 @@ THEOplayer Web SDK Nagra Widevine - - - + + + @@ -33,7 +33,7 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); @@ -64,7 +64,7 @@ window.THEOplayer.registerContentProtectionIntegration( contentProtectionIdentifier, 'widevine', - new ContentProtectionIntegrations.NagraDrmWidevineContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.NagraDrmWidevineContentProtectionIntegrationFactory() ); player.source = { sources: [ diff --git a/drm/test/titaniumdrm/fairplay.html b/drm/test/titaniumdrm/fairplay.html index 65867af2..0a9dec43 100644 --- a/drm/test/titaniumdrm/fairplay.html +++ b/drm/test/titaniumdrm/fairplay.html @@ -3,9 +3,9 @@ Titanium DRM Fairplay Test Using AuthToken or device parameters - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'titaniumdrm', 'fairplay', - new ContentProtectionIntegrations.TitaniumFairplayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.TitaniumFairplayContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/titaniumdrm/playready.html b/drm/test/titaniumdrm/playready.html index 4766ef30..ca3c9913 100644 --- a/drm/test/titaniumdrm/playready.html +++ b/drm/test/titaniumdrm/playready.html @@ -3,9 +3,9 @@ Titanium DRM PlayReady Test using AuthToken or device parameters - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'titaniumdrm', 'playready', - new ContentProtectionIntegrations.TitaniumPlayReadyContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.TitaniumPlayReadyContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/titaniumdrm/widevine.html b/drm/test/titaniumdrm/widevine.html index 8128614e..fadac836 100644 --- a/drm/test/titaniumdrm/widevine.html +++ b/drm/test/titaniumdrm/widevine.html @@ -3,9 +3,9 @@ Titanium DRM Widevine Test Using AuthToken or device parameters - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'titaniumdrm', 'widevine', - new ContentProtectionIntegrations.TitaniumWidevineContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.TitaniumWidevineContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/verimatrixcoredrm/fairplay.html b/drm/test/verimatrixcoredrm/fairplay.html index d99b15f2..3e0afb1c 100644 --- a/drm/test/verimatrixcoredrm/fairplay.html +++ b/drm/test/verimatrixcoredrm/fairplay.html @@ -3,9 +3,9 @@ Verimatrix Core DRM FairPlay Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'verimatrixcore', 'fairplay', - new ContentProtectionIntegrations.VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.VerimatrixCoreDrmFairplayContentProtectionIntegrationFactory() ); const src = ''; diff --git a/drm/test/verimatrixcoredrm/playready.html b/drm/test/verimatrixcoredrm/playready.html index 45e172dc..6c2326c2 100644 --- a/drm/test/verimatrixcoredrm/playready.html +++ b/drm/test/verimatrixcoredrm/playready.html @@ -3,9 +3,9 @@ Verimatrix Core DRM PlayReady Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'verimatrixcore', 'playready', - new ContentProtectionIntegrations.VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.VerimatrixCoreDrmPlayReadyContentProtectionIntegrationFactory() ); const src = ''; diff --git a/drm/test/verimatrixcoredrm/widevine.html b/drm/test/verimatrixcoredrm/widevine.html index 559c0fed..f21db6d9 100644 --- a/drm/test/verimatrixcoredrm/widevine.html +++ b/drm/test/verimatrixcoredrm/widevine.html @@ -3,9 +3,9 @@ Verimatrix Core DRM Widevine Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'verimatrixcore', 'widevine', - new ContentProtectionIntegrations.VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.VerimatrixCoreDrmWidevineContentProtectionIntegrationFactory() ); const src = ''; diff --git a/drm/test/vudrm/fairplay.html b/drm/test/vudrm/fairplay.html index 6a2bc123..fe811ec2 100644 --- a/drm/test/vudrm/fairplay.html +++ b/drm/test/vudrm/fairplay.html @@ -3,9 +3,9 @@ Vudrm Fairplay Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'vudrm', 'fairplay', - new ContentProtectionIntegrations.VudrmFairplayContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.VudrmFairplayContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/vudrm/playready.html b/drm/test/vudrm/playready.html index 2ee4466d..7ae7f380 100644 --- a/drm/test/vudrm/playready.html +++ b/drm/test/vudrm/playready.html @@ -3,9 +3,9 @@ Vudrm PlayReady Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'vudrm', 'playready', - new ContentProtectionIntegrations.VudrmPlayReadyContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.VudrmPlayReadyContentProtectionIntegrationFactory() ); player.source = { diff --git a/drm/test/vudrm/widevine.html b/drm/test/vudrm/widevine.html index 78a700ff..1d55faa4 100644 --- a/drm/test/vudrm/widevine.html +++ b/drm/test/vudrm/widevine.html @@ -3,9 +3,9 @@ Vudrm Widevine Test - - - + + +
@@ -15,14 +15,14 @@ ui: { fluid: true }, - license: ContentProtectionIntegrations.THEOPLAYER_LICENSE, + license: 'insert-your-license-here', libraryLocation: '/THEOplayer/' }); THEOplayer.registerContentProtectionIntegration( 'vudrm', 'widevine', - new ContentProtectionIntegrations.VudrmWidevineContentProtectionIntegrationFactory() + new THEOplayerDrmConnector.VudrmWidevineContentProtectionIntegrationFactory() ); player.source = { From ee698e6298be5676ad7aadf5a13df667e65872c5 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Fri, 2 Aug 2024 17:29:15 +0200 Subject: [PATCH 77/85] Add changeset --- .changeset/khaki-shoes-visit.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/khaki-shoes-visit.md diff --git a/.changeset/khaki-shoes-visit.md b/.changeset/khaki-shoes-visit.md new file mode 100644 index 00000000..7b6908f5 --- /dev/null +++ b/.changeset/khaki-shoes-visit.md @@ -0,0 +1,5 @@ +--- +"@theoplayer/drm-connectors-web": major +--- + +Initial Release. From 13832a51fca7320a8e71b5b5ea7311db2cadb713 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 12 Aug 2024 11:30:59 +0200 Subject: [PATCH 78/85] Run npm i after merge --- package-lock.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4df815c9..ab8fae58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,8 @@ "cmcd", "comscore", "adscript", - "gemius" + "gemius", + "drm" ], "devDependencies": { "@changesets/cli": "^2.27.1", @@ -86,9 +87,16 @@ } } }, + "drm": { + "version": "0.0.0", + "license": "MIT", + "peerDependencies": { + "theoplayer": "^7.0.0" + } + }, "gemius": { "name": "@theoplayer/gemius-connector-web", - "version": "0.0.1", + "version": "0.1.0", "license": "MIT", "peerDependencies": { "theoplayer": "^7.0.0" @@ -2430,6 +2438,10 @@ "resolved": "conviva", "link": true }, + "node_modules/@theoplayer/drm-connectors-web": { + "resolved": "drm", + "link": true + }, "node_modules/@theoplayer/gemius-connector-web": { "resolved": "gemius", "link": true From 35e127cac06620427f0cf9acbd087553bb5a233d Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 12 Aug 2024 11:31:04 +0200 Subject: [PATCH 79/85] Add exclusion --- .idea/web-connectors.iml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/web-connectors.iml b/.idea/web-connectors.iml index c9184b4e..b9613383 100644 --- a/.idea/web-connectors.iml +++ b/.idea/web-connectors.iml @@ -12,6 +12,7 @@ + From 2fd74c03e8f29ff48e728df64335ab7f6f9d6283 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 12 Aug 2024 11:31:12 +0200 Subject: [PATCH 80/85] Update README --- drm/README.md | 326 +++++++++----------------------------------------- 1 file changed, 57 insertions(+), 269 deletions(-) diff --git a/drm/README.md b/drm/README.md index 3e4cc079..aa7c8811 100644 --- a/drm/README.md +++ b/drm/README.md @@ -1,295 +1,83 @@ -## Getting started on Web +# drm-connectors-web -### Table of contents - -1. [Overview](#overview) -2. [Creating a new integration](#creating-a-new-integration) -3. [Request and Response types](#request-and-response-types) -4. [Hook return types](#hook-return-types) -5. [Available examples](#available-examples) -6. [Testing an integration](#testing-an-integration) -7. [Conclusion](#conclusion) - -### Overview - -This document provides a step-by-step approach on how to create a custom DRM integration with the THEOplayer Web SDK. -It gives an overview of which classes are involved and how they participate in the DRM flow. - -The project's top-level [README](../README.md) elaborates on what it means to create a DRM integration, gives a brief -platform-independent overview of the flow, and clarifies the terminology being used throughout the document. Make sure -to familiarise yourself with it before starting your own implementation. - -The static class diagram below depicts classes that are part of the SDK in white, while coloured classes need to be -implemented when creating a custom integration. The `ContentProtectionIntegrationFactory` subclass is only used once -by THEOplayer to create an instance of a `ContentProtectedIntegration` subclass. The latter contains the actual hook methods -being referred to in the DRM integration [sequence diagram](../README.md#drm-integration-api). - -![Custom DRM integration class diagram](../resources/web_custom_drm_classes.svg) - -In the next section a custom integration is built by implementing both subclasses. - -### Creating a new integration - -First create a custom implementation of [ContentProtectionIntegration](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.contentprotectionintegration.md) -under `src/integration/custom`. This object defines handler methods that allow altering license and certificate requests and responses as part of the -DRM flow. -All methods are optional. They can be omitted if the integration does not require additional action, in which case the -default implementation will be used. - -```ts -import { - ContentProtectionIntegration, - CertificateRequest, - MaybeAsync, - BufferSource, - CertificateResponse, - LicenseRequest, - LicenseResponse -} from 'theoplayer'; -import { CustomDRMConfiguration } from './CustomDRMConfiguration'; - -export class CustomContentProtectionIntegration implements ContentProtectionIntegration { - constructor(private readonly contentProtectionConfiguration: CustomDRMConfiguration) { - } - - onCertificateRequest(request: CertificateRequest): MaybeAsync | BufferSource> { - throw new Error('not implemented yet'); - } - - onCertificateResponse(response: CertificateResponse): MaybeAsync { - throw new Error('not implemented yet'); - } - - onLicenseRequest(request: LicenseRequest): MaybeAsync | BufferSource> { - // const token = this.contentProtectionConfiguration.integrationParameters.token; - // request.headers = { - // ...request.headers, - // 'x-token': token - // }; - // return request; - throw new Error('not implemented yet'); - } +A collection of DRM connectors for the THEOplayer Web SDK: +- Axinom DRM +- Microsoft Azure DRM +- CastLabs DRMtoday +- Comcast DRM +- EZDRM (only for Fairplay, as Widevine and PlayReady can use the default implementation) +- Irdeto Control +- BuyDRM KeyOS +- Nagra DRM +- Vualto VuDRM +- Verimatrix MultiDRM Core DRM +- Arris Titanium DRM - onLicenseResponse(response: LicenseResponse): MaybeAsync { - throw new Error('not implemented yet'); - } - - extractFairplayContentId?(skdUrl: string): string { - throw new Error('not implemented yet'); - } -} -``` +## Installation -Optional parameters needed for certificate or license requests, such as tokens, can be added to a [DRMConfiguration](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.drmconfiguration.md/#drmconfiguration-interface) -object that is passed when creating instances of the `CustomContentProtectionIntegration` class. +Install using your favorite package manager for Node (such as `npm` or `yarn`): -```ts -import { DRMConfiguration } from 'theoplayer'; +### Install via npm -export interface CustomDRMConfiguration extends DRMConfiguration { - integrationParameters: { - token: string; - // any other parameters - }; -} +```bash +npm install @theoplayer/drm-connectors-web ``` -In the example, `CustomContentProtectionIntegration` adds a token from the configuration object as part of the headers -during a license request. - -Next, create a [ContentProtectionIntegrationFactory](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.contentprotectionintegrationfactory.md) -for building `CustomContentProtectionIntegration` instances. -THEOplayer will use this factory in its DRM flow whenever it needs a ContentProtectionIntegration instance that -matches with the content protected source. How THEOplayer knows which factory to take will be determined in the -`registerContentProtectionIntegration` step later on. +### Install via yarn -```ts -import { - ContentProtectionIntegration, - ContentProtectionIntegrationFactory, - DRMConfiguration -} from 'theoplayer'; -import { CustomContentProtectionIntegration } from './CustomContentProtectionIntegration'; - -export class CustomContentProtectionIntegrationFactory implements ContentProtectionIntegrationFactory { - build(configuration: CustomDRMConfiguration): ContentProtectionIntegration { - return new CustomContentProtectionIntegration(configuration); - } -} +```bash +yarn add @theoplayer/drm-connectors-web ``` -Before the factory can be used externally, it needs to be exported in the bundle's entry point `src/index.ts`. +## Usage +First you need to add the one of the DRM connectors to your app. +This example uses Axinom DRM but this equivalent with all connectors: -```ts -import { CustomContentProtectionIntegrationFactory } from './integration/custom/CustomContentProtectionIntegrationFactory'; - -export { - // ... - CustomContentProtectionIntegrationFactory -}; -``` - -The final step, after updating the integrations library with `npm build`, is creating a web page under `test/custom`. - -An instance of `CustomContentProtectionIntegrationFactory` needs to be -[registered](https://docs.portal.theoplayer.com/api-reference/web/theoplayer.registercontentprotectionintegration.md/#registercontentprotectionintegration-function) -with THEOplayer by specifying a unique `integrationId`, such as `'custom_wv'` in this example. - -```ts -THEOplayer.registerContentProtectionIntegration( - 'custom_wv', - 'widevine', - new THEOplayerDrmConnector.CustomContentProtectionIntegrationFactory() -); -``` -The object `ContentProtectionIntegrations` is provided by the library `dist/bundle.js` and gives access to all exports from `src/index.ts`. - -When the player now loads a source with an `integration` parameter that matches the `integrationId` -passed during registration, an instance of `CustomContentProtectionIntegration` will be created and used in the DRM flow. +* Add as a regular script ```html - - - - - Custom Widevine Test - - - - - -
+ - - -``` - -### Request and Response types - -Manipulating certificate and license requests and responses requires special care. Next to adding header -fields or changing the target url, the body of the `ContentProtectionRequest` most often needs to be transformed or wrapped -before passing it along. - -```javascript -interface ContentProtectionRequest { - url: string; - method: string; - headers: { [headerName: string]: string }; - body: Uint8Array | null; - useCredentials: boolean; -} - -interface LicenseRequest extends ContentProtectionRequest { - // Only available for Fairplay license requests. The value will be `undefined` otherwise. - fairplaySkdUrl: string | undefined; -} - -declare type CertificateRequest = ContentProtectionRequest; ``` -A `ContentProtectionRequest` object expects the body to be a `Uint8Array`. -In case of a license request it originally contains the challenge generated by the CDM. -A common way of passing extra data to the server is by wrapping the raw request body -in an object with some additional properties, which is then transformed back into the required type `Uint8Array`. -The following example is taken from the [VuDRM Widevine integration sample](./src/integration/vudrm/VudrmWidevineContentProtectionIntegration.ts): +* Add as an ES2015 module -```javascript -private wrapRequestBody(body: Uint8Array): Uint8Array { - const token = this.contentProtectionConfiguration.integrationParameters.token; - const drmInfo = fromUint8ArrayToNumberArray(body); - const kid = this.contentProtectionConfiguration.integrationParameters.keyId; - return fromObjectToUint8Array({ token, drm_info: drmInfo, kid }); -} +```html + ``` -where `fromUint8ArrayToNumberArray` and `fromObjectToUint8Array` are helper methods transforming variables to different -representations. -Similarly, the `ContentProtectionResponse` object returned from the server contains among others the response headers and the response -body. The latter is again an array of `Uint8Array`, containing the certificate or license that will be passed to the CDM. +To make use of the registered DRM connectors, you need : ```javascript -public interface ContentProtectionResponse { - request: ContentProtectionRequest; - url: string; - status: number; - statusText: string; - headers: { [headerName: string]: string }; - body: Uint8Array; -} +player.source = { + sources: [ + { + src: '', + contentProtection: { + integration: 'axinom', + integrationParameters: { + // This is specific for Axinom. + token: '' + }, + widevine: { ... }, + playready: { ... }, + fairplay: { ... } + } + } + ] +}; ``` - -Depending on the DRM integration, the response body either already is a raw certificate or license that can be passed along as-is, -or needs to be transformed or unwrapped first in a way similar to the request body. - -### Hook return types - -The return types of both `onCertificateRequest()` and `onLicenseRequest()` hooks are defined as -`MaybeAsync | BufferSource>` and `MaybeAsync | BufferSource>` -respectively. This gives the flexibility to either return the optionally modified request, without the need to specify all properties -(i.e. `Partial`), or a raw certificate or license. In the latter case, the request is skipped entirely and the certificate or -license is used directly. - -`BufferSource` is defined as the union type `BufferSource = ArrayBufferView | ArrayBuffer`. - -For the `onCertificateResponse()` and `onLicenseResponse()` hooks the return type is defined as -`MaybeAsync`, meaning they are expected to return the raw certificate or license. - -### Available examples - -- Axinom DRM -- Microsoft Azure DRM -- CastLabs DRMtoday -- Comcast DRM -- EZDRM (only for Fairplay, as Widevine and PlayReady can use the default implementation) -- Irdeto Control -- BuyDRM KeyOS -- Nagra DRM -- Vualto VuDRM -- Verimatrix MultiDRM Core DRM -- Arris Titanium DRM - -### Testing an integration - -- Enter your [THEOplayer license](https://portal.theoplayer.com) instead of `YOUR_LICENSE_HERE` in `src/index.ts`. -- Run `npm install && npm run build` in the root folder to create the integrations library `bundle.js` under `dist/`. -- Start http-server in the root folder by running `npm run server`. -- Go to `localhost:8080/test/[integration you want to test]`. - -### Conclusion - -This document showed how to create a custom DRM integration for Web using THEOplayer's Content Integration API, -and register it with THEOplayer. The Web integration API can slightly differ on other platforms, so it is best -to check the platform's specific document. From ce0e173e8e3b3be26ad53d3aa05829ca8a68f0e1 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 12 Aug 2024 11:33:30 +0200 Subject: [PATCH 81/85] Fix libraryLocation in demos --- drm/test/axinomdrm/playready.html | 2 +- drm/test/axinomdrm/widevine.html | 2 +- drm/test/azuredrm/fairplay.html | 2 +- drm/test/azuredrm/playready.html | 2 +- drm/test/azuredrm/widevine.html | 2 +- drm/test/castlabs/fairplay.html | 2 +- drm/test/castlabs/playready.html | 2 +- drm/test/castlabs/widevine.html | 2 +- drm/test/comcastdrm/fairplay.html | 2 +- drm/test/ezdrm/fairplay.html | 2 +- drm/test/irdetocontrol/fairplay.html | 2 +- drm/test/irdetocontrol/playready.html | 2 +- drm/test/irdetocontrol/widevine.html | 2 +- drm/test/keyos/fairplay.html | 2 +- drm/test/keyos/playready.html | 2 +- drm/test/keyos/widevine.html | 2 +- drm/test/nagradrm/fairplay.html | 2 +- drm/test/nagradrm/playready.html | 2 +- drm/test/nagradrm/widevine.html | 2 +- drm/test/titaniumdrm/fairplay.html | 2 +- drm/test/titaniumdrm/playready.html | 2 +- drm/test/titaniumdrm/widevine.html | 2 +- drm/test/verimatrixcoredrm/fairplay.html | 2 +- drm/test/verimatrixcoredrm/playready.html | 2 +- drm/test/verimatrixcoredrm/widevine.html | 2 +- drm/test/vudrm/fairplay.html | 2 +- drm/test/vudrm/playready.html | 2 +- drm/test/vudrm/widevine.html | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drm/test/axinomdrm/playready.html b/drm/test/axinomdrm/playready.html index aec75211..26a361eb 100644 --- a/drm/test/axinomdrm/playready.html +++ b/drm/test/axinomdrm/playready.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); const contentProtectionIdentifier = 'axinom'; diff --git a/drm/test/axinomdrm/widevine.html b/drm/test/axinomdrm/widevine.html index cef19856..8b2ad124 100644 --- a/drm/test/axinomdrm/widevine.html +++ b/drm/test/axinomdrm/widevine.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); const contentProtectionIdentifier = 'axinom'; diff --git a/drm/test/azuredrm/fairplay.html b/drm/test/azuredrm/fairplay.html index b0ea83c3..7417a87a 100644 --- a/drm/test/azuredrm/fairplay.html +++ b/drm/test/azuredrm/fairplay.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/azuredrm/playready.html b/drm/test/azuredrm/playready.html index b26dde7f..ac2db6ec 100644 --- a/drm/test/azuredrm/playready.html +++ b/drm/test/azuredrm/playready.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/azuredrm/widevine.html b/drm/test/azuredrm/widevine.html index a2e94d84..44185cdd 100644 --- a/drm/test/azuredrm/widevine.html +++ b/drm/test/azuredrm/widevine.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/castlabs/fairplay.html b/drm/test/castlabs/fairplay.html index 8c288780..2ca3c920 100644 --- a/drm/test/castlabs/fairplay.html +++ b/drm/test/castlabs/fairplay.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/castlabs/playready.html b/drm/test/castlabs/playready.html index c9807e8f..4f3101e3 100644 --- a/drm/test/castlabs/playready.html +++ b/drm/test/castlabs/playready.html @@ -24,7 +24,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); const src = ''; diff --git a/drm/test/castlabs/widevine.html b/drm/test/castlabs/widevine.html index 68fe401e..f5f8748e 100644 --- a/drm/test/castlabs/widevine.html +++ b/drm/test/castlabs/widevine.html @@ -24,7 +24,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); const src = ''; diff --git a/drm/test/comcastdrm/fairplay.html b/drm/test/comcastdrm/fairplay.html index 50671ff1..2c11d5ab 100644 --- a/drm/test/comcastdrm/fairplay.html +++ b/drm/test/comcastdrm/fairplay.html @@ -41,7 +41,7 @@

Comcast DRM FairPlay

}, mutedAutoplay: true, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/ezdrm/fairplay.html b/drm/test/ezdrm/fairplay.html index cfba4e2c..2b821131 100644 --- a/drm/test/ezdrm/fairplay.html +++ b/drm/test/ezdrm/fairplay.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/irdetocontrol/fairplay.html b/drm/test/irdetocontrol/fairplay.html index 5913f5e6..cadb696b 100644 --- a/drm/test/irdetocontrol/fairplay.html +++ b/drm/test/irdetocontrol/fairplay.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/irdetocontrol/playready.html b/drm/test/irdetocontrol/playready.html index d56e1949..baa164ef 100644 --- a/drm/test/irdetocontrol/playready.html +++ b/drm/test/irdetocontrol/playready.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); const streamSrc = '.mpd'; diff --git a/drm/test/irdetocontrol/widevine.html b/drm/test/irdetocontrol/widevine.html index 66c148c9..3beec3f6 100644 --- a/drm/test/irdetocontrol/widevine.html +++ b/drm/test/irdetocontrol/widevine.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); const streamSrc = '.mpd'; diff --git a/drm/test/keyos/fairplay.html b/drm/test/keyos/fairplay.html index 163806ea..db20836f 100644 --- a/drm/test/keyos/fairplay.html +++ b/drm/test/keyos/fairplay.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/keyos/playready.html b/drm/test/keyos/playready.html index d01e6568..0b2d8a46 100644 --- a/drm/test/keyos/playready.html +++ b/drm/test/keyos/playready.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/keyos/widevine.html b/drm/test/keyos/widevine.html index 12770d3d..44495335 100644 --- a/drm/test/keyos/widevine.html +++ b/drm/test/keyos/widevine.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/nagradrm/fairplay.html b/drm/test/nagradrm/fairplay.html index 9fb78ba8..95eb7db0 100644 --- a/drm/test/nagradrm/fairplay.html +++ b/drm/test/nagradrm/fairplay.html @@ -38,7 +38,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); let configureStream = function (src, licenseAcquisitionURL, certificateURL, tenantId, token) { diff --git a/drm/test/nagradrm/playready.html b/drm/test/nagradrm/playready.html index 85451ee7..29bc56c2 100644 --- a/drm/test/nagradrm/playready.html +++ b/drm/test/nagradrm/playready.html @@ -34,7 +34,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); let configureStream = function (src, licenseAcquisitionURL, token) { diff --git a/drm/test/nagradrm/widevine.html b/drm/test/nagradrm/widevine.html index e080d434..efc73fbb 100644 --- a/drm/test/nagradrm/widevine.html +++ b/drm/test/nagradrm/widevine.html @@ -34,7 +34,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); let configureStream = function (src, licenseAcquisitionURL, token) { diff --git a/drm/test/titaniumdrm/fairplay.html b/drm/test/titaniumdrm/fairplay.html index 0a9dec43..70eeae27 100644 --- a/drm/test/titaniumdrm/fairplay.html +++ b/drm/test/titaniumdrm/fairplay.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/titaniumdrm/playready.html b/drm/test/titaniumdrm/playready.html index ca3c9913..a978290c 100644 --- a/drm/test/titaniumdrm/playready.html +++ b/drm/test/titaniumdrm/playready.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/titaniumdrm/widevine.html b/drm/test/titaniumdrm/widevine.html index fadac836..1a9a825e 100644 --- a/drm/test/titaniumdrm/widevine.html +++ b/drm/test/titaniumdrm/widevine.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/verimatrixcoredrm/fairplay.html b/drm/test/verimatrixcoredrm/fairplay.html index 3e0afb1c..783a2be4 100644 --- a/drm/test/verimatrixcoredrm/fairplay.html +++ b/drm/test/verimatrixcoredrm/fairplay.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/verimatrixcoredrm/playready.html b/drm/test/verimatrixcoredrm/playready.html index 6c2326c2..2729d919 100644 --- a/drm/test/verimatrixcoredrm/playready.html +++ b/drm/test/verimatrixcoredrm/playready.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/verimatrixcoredrm/widevine.html b/drm/test/verimatrixcoredrm/widevine.html index f21db6d9..60f587ed 100644 --- a/drm/test/verimatrixcoredrm/widevine.html +++ b/drm/test/verimatrixcoredrm/widevine.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/vudrm/fairplay.html b/drm/test/vudrm/fairplay.html index fe811ec2..44fcb11a 100644 --- a/drm/test/vudrm/fairplay.html +++ b/drm/test/vudrm/fairplay.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/vudrm/playready.html b/drm/test/vudrm/playready.html index 7ae7f380..fe45f0e7 100644 --- a/drm/test/vudrm/playready.html +++ b/drm/test/vudrm/playready.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( diff --git a/drm/test/vudrm/widevine.html b/drm/test/vudrm/widevine.html index 1d55faa4..c7fc1ab7 100644 --- a/drm/test/vudrm/widevine.html +++ b/drm/test/vudrm/widevine.html @@ -16,7 +16,7 @@ fluid: true }, license: 'insert-your-license-here', - libraryLocation: '/THEOplayer/' + libraryLocation: '../../../node_modules/theoplayer/' }); THEOplayer.registerContentProtectionIntegration( From 76d48b26d6e8f4d78d60b34cfbaa17637496b1ec Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 12 Aug 2024 11:37:12 +0200 Subject: [PATCH 82/85] Rename package --- drm/package.json | 2 +- package-lock.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drm/package.json b/drm/package.json index 6f066b48..fe35348c 100644 --- a/drm/package.json +++ b/drm/package.json @@ -1,5 +1,5 @@ { - "name": "@theoplayer/drm-connectors-web", + "name": "@theoplayer/drm-connector-web", "version": "0.0.0", "description": "External DRM connectors for the THEOplayer Web SDK", "main": "dist/drm-connectors.umd.js", diff --git a/package-lock.json b/package-lock.json index ab8fae58..b2ad9fb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -88,6 +88,7 @@ } }, "drm": { + "name": "@theoplayer/drm-connector-web", "version": "0.0.0", "license": "MIT", "peerDependencies": { @@ -2438,7 +2439,7 @@ "resolved": "conviva", "link": true }, - "node_modules/@theoplayer/drm-connectors-web": { + "node_modules/@theoplayer/drm-connector-web": { "resolved": "drm", "link": true }, From 01d18f2aa991caced67ff1a3ea9e2a7122334a53 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Mon, 12 Aug 2024 11:38:00 +0200 Subject: [PATCH 83/85] Add package to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2b8e841d..e67953c6 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Using the available connectors allows you to augment the features delivered thro | CMCD | [![@theoplayer/cmcd-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fcmcd-connector-web?label=%40theoplayer%2Fcmcd-connector-web)](https://npmjs.com/package/@theoplayer/cmcd-connector-web) | [cmcd](https://github.com/THEOplayer/web-connectors/tree/main/cmcd) | | Comscore | [![@theoplayer/comscore-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fcomscore-connector-web?label=%40theoplayer%2Fcomscore-connector-web)](https://npmjs.com/package/@theoplayer/comscore-connector-web) | [comscore](https://github.com/THEOplayer/web-connectors/tree/main/comscore) | | Conviva | [![@theoplayer/conviva-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fconviva-connector-web?label=%40theoplayer%2Fconviva-connector-web)](https://npmjs.com/package/@theoplayer/conviva-connector-web) | [conviva](https://github.com/THEOplayer/web-connectors/tree/main/conviva) | +| DRM | [![@theoplayer/drm-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fdrm-connector-web?label=%40theoplayer%2Fdrm-connector-web)](https://npmjs.com/package/@theoplayer/drm-connector-web) | [drm](https://github.com/THEOplayer/web-connectors/tree/main/conviva) | | Gemius | [![@theoplayer/gemius-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fgemius-connector-web?label=%40theoplayer%2Fgemius-connector-web)](https://npmjs.com/package/@theoplayer/gemius-connector-web) | [gemius](https://github.com/THEOplayer/web-connectors/tree/main/gemius) | | Nielsen | [![@theoplayer/nielsen-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fnielsen-connector-web?label=%40theoplayer%2Fnielsen-connector-web)](https://npmjs.com/package/@theoplayer/nielsen-connector-web) | [nielsen](https://github.com/THEOplayer/web-connectors/tree/main/nielsen) | | Yospace | [![@theoplayer/yospace-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fyospace-connector-web?label=%40theoplayer%2Fyospace-connector-web)](https://npmjs.com/package/@theoplayer/yospace-connector-web) | [yospace](https://github.com/THEOplayer/web-connectors/tree/main/yospace) | From 02e8a24acc3b4d8adba1c8822fde5b83dfb34c76 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Wed, 21 Aug 2024 11:39:12 +0200 Subject: [PATCH 84/85] Fix inconstent naming --- .changeset/khaki-shoes-visit.md | 2 +- drm/README.md | 10 +++++----- drm/package.json | 8 ++++---- drm/rollup.config.mjs | 2 +- drm/test/axinomdrm/fairplay.html | 2 +- drm/test/axinomdrm/playready.html | 2 +- drm/test/axinomdrm/widevine.html | 2 +- drm/test/azuredrm/fairplay.html | 2 +- drm/test/azuredrm/playready.html | 2 +- drm/test/azuredrm/widevine.html | 2 +- drm/test/castlabs/fairplay.html | 2 +- drm/test/castlabs/playready.html | 2 +- drm/test/castlabs/widevine.html | 2 +- drm/test/comcastdrm/playready.html | 2 +- drm/test/comcastdrm/widevine.html | 2 +- drm/test/ezdrm/fairplay.html | 2 +- drm/test/irdetocontrol/fairplay.html | 2 +- drm/test/irdetocontrol/playready.html | 2 +- drm/test/irdetocontrol/widevine.html | 2 +- drm/test/keyos/fairplay.html | 2 +- drm/test/keyos/playready.html | 2 +- drm/test/keyos/widevine.html | 2 +- drm/test/nagradrm/fairplay.html | 2 +- drm/test/nagradrm/playready.html | 2 +- drm/test/nagradrm/widevine.html | 2 +- drm/test/titaniumdrm/fairplay.html | 2 +- drm/test/titaniumdrm/playready.html | 2 +- drm/test/titaniumdrm/widevine.html | 2 +- drm/test/verimatrixcoredrm/fairplay.html | 2 +- drm/test/verimatrixcoredrm/playready.html | 2 +- drm/test/verimatrixcoredrm/widevine.html | 2 +- drm/test/vudrm/fairplay.html | 2 +- drm/test/vudrm/playready.html | 2 +- drm/test/vudrm/widevine.html | 2 +- 34 files changed, 41 insertions(+), 41 deletions(-) diff --git a/.changeset/khaki-shoes-visit.md b/.changeset/khaki-shoes-visit.md index 7b6908f5..8e915708 100644 --- a/.changeset/khaki-shoes-visit.md +++ b/.changeset/khaki-shoes-visit.md @@ -1,5 +1,5 @@ --- -"@theoplayer/drm-connectors-web": major +"@theoplayer/drm-connector-web": major --- Initial Release. diff --git a/drm/README.md b/drm/README.md index aa7c8811..2db76dbf 100644 --- a/drm/README.md +++ b/drm/README.md @@ -1,4 +1,4 @@ -# drm-connectors-web +# drm-connector-web A collection of DRM connectors for the THEOplayer Web SDK: - Axinom DRM @@ -20,13 +20,13 @@ Install using your favorite package manager for Node (such as `npm` or `yarn`): ### Install via npm ```bash -npm install @theoplayer/drm-connectors-web +npm install @theoplayer/drm-connector-web ``` ### Install via yarn ```bash -yarn add @theoplayer/drm-connectors-web +yarn add @theoplayer/drm-connector-web ``` ## Usage @@ -36,7 +36,7 @@ This example uses Axinom DRM but this equivalent with all connectors: * Add as a regular script ```html - + - +
diff --git a/drm/test/axinomdrm/playready.html b/drm/test/axinomdrm/playready.html index 26a361eb..d26f9b6e 100644 --- a/drm/test/axinomdrm/playready.html +++ b/drm/test/axinomdrm/playready.html @@ -5,7 +5,7 @@ Axinom PlayReady Test - +
diff --git a/drm/test/axinomdrm/widevine.html b/drm/test/axinomdrm/widevine.html index 8b2ad124..51094f38 100644 --- a/drm/test/axinomdrm/widevine.html +++ b/drm/test/axinomdrm/widevine.html @@ -5,7 +5,7 @@ Axinom Widevine Test - +
diff --git a/drm/test/azuredrm/fairplay.html b/drm/test/azuredrm/fairplay.html index 7417a87a..014b7b1b 100644 --- a/drm/test/azuredrm/fairplay.html +++ b/drm/test/azuredrm/fairplay.html @@ -5,7 +5,7 @@ Azure drm FairPlay Test - +
diff --git a/drm/test/azuredrm/playready.html b/drm/test/azuredrm/playready.html index ac2db6ec..3e98faef 100644 --- a/drm/test/azuredrm/playready.html +++ b/drm/test/azuredrm/playready.html @@ -5,7 +5,7 @@ Azure drm PlayReady Test - +
diff --git a/drm/test/azuredrm/widevine.html b/drm/test/azuredrm/widevine.html index 44185cdd..d5032686 100644 --- a/drm/test/azuredrm/widevine.html +++ b/drm/test/azuredrm/widevine.html @@ -5,7 +5,7 @@ Azure drm Widevine Test - +
diff --git a/drm/test/castlabs/fairplay.html b/drm/test/castlabs/fairplay.html index 2ca3c920..7ab7fdce 100644 --- a/drm/test/castlabs/fairplay.html +++ b/drm/test/castlabs/fairplay.html @@ -5,7 +5,7 @@ CastLabs FairPlay Test - +
diff --git a/drm/test/castlabs/playready.html b/drm/test/castlabs/playready.html index 4f3101e3..90b50f26 100644 --- a/drm/test/castlabs/playready.html +++ b/drm/test/castlabs/playready.html @@ -5,7 +5,7 @@ CastLabs PlayReady Test - +

diff --git a/drm/test/castlabs/widevine.html b/drm/test/castlabs/widevine.html index f5f8748e..6b4b72da 100644 --- a/drm/test/castlabs/widevine.html +++ b/drm/test/castlabs/widevine.html @@ -5,7 +5,7 @@ CastLabs Widevine Test - +

diff --git a/drm/test/comcastdrm/playready.html b/drm/test/comcastdrm/playready.html index 2a3e1c00..cad04330 100644 --- a/drm/test/comcastdrm/playready.html +++ b/drm/test/comcastdrm/playready.html @@ -6,7 +6,7 @@ - +

diff --git a/drm/test/comcastdrm/widevine.html b/drm/test/comcastdrm/widevine.html index c8d7c19b..3970efed 100644 --- a/drm/test/comcastdrm/widevine.html +++ b/drm/test/comcastdrm/widevine.html @@ -6,7 +6,7 @@ - +
diff --git a/drm/test/ezdrm/fairplay.html b/drm/test/ezdrm/fairplay.html index 2b821131..ffcd3b8f 100644 --- a/drm/test/ezdrm/fairplay.html +++ b/drm/test/ezdrm/fairplay.html @@ -5,7 +5,7 @@ Ezdrm Fairplay Test - +
diff --git a/drm/test/irdetocontrol/fairplay.html b/drm/test/irdetocontrol/fairplay.html index cadb696b..17eb5896 100644 --- a/drm/test/irdetocontrol/fairplay.html +++ b/drm/test/irdetocontrol/fairplay.html @@ -5,7 +5,7 @@ Irdeto Control FairPlay Test - +
diff --git a/drm/test/irdetocontrol/playready.html b/drm/test/irdetocontrol/playready.html index baa164ef..9769e35f 100644 --- a/drm/test/irdetocontrol/playready.html +++ b/drm/test/irdetocontrol/playready.html @@ -5,7 +5,7 @@ Irdeto Control PlayReady Test - +
diff --git a/drm/test/irdetocontrol/widevine.html b/drm/test/irdetocontrol/widevine.html index 3beec3f6..db9c07ca 100644 --- a/drm/test/irdetocontrol/widevine.html +++ b/drm/test/irdetocontrol/widevine.html @@ -5,7 +5,7 @@ Irdeto Control Widevine Test - +
diff --git a/drm/test/keyos/fairplay.html b/drm/test/keyos/fairplay.html index db20836f..385284ed 100644 --- a/drm/test/keyos/fairplay.html +++ b/drm/test/keyos/fairplay.html @@ -5,7 +5,7 @@ KeyOS drm FairPlay Test - +
diff --git a/drm/test/keyos/playready.html b/drm/test/keyos/playready.html index 0b2d8a46..65bc361a 100644 --- a/drm/test/keyos/playready.html +++ b/drm/test/keyos/playready.html @@ -5,7 +5,7 @@ KeyOS drm PlayReady Test - +
diff --git a/drm/test/keyos/widevine.html b/drm/test/keyos/widevine.html index 44495335..dcac0fd5 100644 --- a/drm/test/keyos/widevine.html +++ b/drm/test/keyos/widevine.html @@ -5,7 +5,7 @@ KeyOS drm Widevine Test - +
diff --git a/drm/test/nagradrm/fairplay.html b/drm/test/nagradrm/fairplay.html index 95eb7db0..e35d912a 100644 --- a/drm/test/nagradrm/fairplay.html +++ b/drm/test/nagradrm/fairplay.html @@ -5,7 +5,7 @@ < - + diff --git a/drm/test/nagradrm/playready.html b/drm/test/nagradrm/playready.html index 29bc56c2..d751e00f 100644 --- a/drm/test/nagradrm/playready.html +++ b/drm/test/nagradrm/playready.html @@ -5,7 +5,7 @@ - + diff --git a/drm/test/nagradrm/widevine.html b/drm/test/nagradrm/widevine.html index efc73fbb..90a80a01 100644 --- a/drm/test/nagradrm/widevine.html +++ b/drm/test/nagradrm/widevine.html @@ -5,7 +5,7 @@ - + diff --git a/drm/test/titaniumdrm/fairplay.html b/drm/test/titaniumdrm/fairplay.html index 70eeae27..3e520cb7 100644 --- a/drm/test/titaniumdrm/fairplay.html +++ b/drm/test/titaniumdrm/fairplay.html @@ -5,7 +5,7 @@ Titanium DRM Fairplay Test Using AuthToken or device parameters - +
diff --git a/drm/test/titaniumdrm/playready.html b/drm/test/titaniumdrm/playready.html index a978290c..814e0ae2 100644 --- a/drm/test/titaniumdrm/playready.html +++ b/drm/test/titaniumdrm/playready.html @@ -5,7 +5,7 @@ Titanium DRM PlayReady Test using AuthToken or device parameters - +
diff --git a/drm/test/titaniumdrm/widevine.html b/drm/test/titaniumdrm/widevine.html index 1a9a825e..be7f7564 100644 --- a/drm/test/titaniumdrm/widevine.html +++ b/drm/test/titaniumdrm/widevine.html @@ -5,7 +5,7 @@ Titanium DRM Widevine Test Using AuthToken or device parameters - +
diff --git a/drm/test/verimatrixcoredrm/fairplay.html b/drm/test/verimatrixcoredrm/fairplay.html index 783a2be4..756697f8 100644 --- a/drm/test/verimatrixcoredrm/fairplay.html +++ b/drm/test/verimatrixcoredrm/fairplay.html @@ -5,7 +5,7 @@ Verimatrix Core DRM FairPlay Test - +
diff --git a/drm/test/verimatrixcoredrm/playready.html b/drm/test/verimatrixcoredrm/playready.html index 2729d919..cdd3e253 100644 --- a/drm/test/verimatrixcoredrm/playready.html +++ b/drm/test/verimatrixcoredrm/playready.html @@ -5,7 +5,7 @@ Verimatrix Core DRM PlayReady Test - +
diff --git a/drm/test/verimatrixcoredrm/widevine.html b/drm/test/verimatrixcoredrm/widevine.html index 60f587ed..39ee769d 100644 --- a/drm/test/verimatrixcoredrm/widevine.html +++ b/drm/test/verimatrixcoredrm/widevine.html @@ -5,7 +5,7 @@ Verimatrix Core DRM Widevine Test - +
diff --git a/drm/test/vudrm/fairplay.html b/drm/test/vudrm/fairplay.html index 44fcb11a..966d82a1 100644 --- a/drm/test/vudrm/fairplay.html +++ b/drm/test/vudrm/fairplay.html @@ -5,7 +5,7 @@ Vudrm Fairplay Test - +
diff --git a/drm/test/vudrm/playready.html b/drm/test/vudrm/playready.html index fe45f0e7..1be0a0bd 100644 --- a/drm/test/vudrm/playready.html +++ b/drm/test/vudrm/playready.html @@ -5,7 +5,7 @@ Vudrm PlayReady Test - +
diff --git a/drm/test/vudrm/widevine.html b/drm/test/vudrm/widevine.html index c7fc1ab7..6499db3c 100644 --- a/drm/test/vudrm/widevine.html +++ b/drm/test/vudrm/widevine.html @@ -5,7 +5,7 @@ Vudrm Widevine Test - +
From 217c23471c5e8d5db8ee5206df32293e288bc515 Mon Sep 17 00:00:00 2001 From: George Choustoulakis Date: Wed, 21 Aug 2024 11:39:53 +0200 Subject: [PATCH 85/85] =?UTF-8?q?Fix=20link=E2=80=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e67953c6..c3539fc8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Using the available connectors allows you to augment the features delivered thro | CMCD | [![@theoplayer/cmcd-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fcmcd-connector-web?label=%40theoplayer%2Fcmcd-connector-web)](https://npmjs.com/package/@theoplayer/cmcd-connector-web) | [cmcd](https://github.com/THEOplayer/web-connectors/tree/main/cmcd) | | Comscore | [![@theoplayer/comscore-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fcomscore-connector-web?label=%40theoplayer%2Fcomscore-connector-web)](https://npmjs.com/package/@theoplayer/comscore-connector-web) | [comscore](https://github.com/THEOplayer/web-connectors/tree/main/comscore) | | Conviva | [![@theoplayer/conviva-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fconviva-connector-web?label=%40theoplayer%2Fconviva-connector-web)](https://npmjs.com/package/@theoplayer/conviva-connector-web) | [conviva](https://github.com/THEOplayer/web-connectors/tree/main/conviva) | -| DRM | [![@theoplayer/drm-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fdrm-connector-web?label=%40theoplayer%2Fdrm-connector-web)](https://npmjs.com/package/@theoplayer/drm-connector-web) | [drm](https://github.com/THEOplayer/web-connectors/tree/main/conviva) | +| DRM | [![@theoplayer/drm-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fdrm-connector-web?label=%40theoplayer%2Fdrm-connector-web)](https://npmjs.com/package/@theoplayer/drm-connector-web) | [drm](https://github.com/THEOplayer/web-connectors/tree/main/drm) | | Gemius | [![@theoplayer/gemius-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fgemius-connector-web?label=%40theoplayer%2Fgemius-connector-web)](https://npmjs.com/package/@theoplayer/gemius-connector-web) | [gemius](https://github.com/THEOplayer/web-connectors/tree/main/gemius) | | Nielsen | [![@theoplayer/nielsen-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fnielsen-connector-web?label=%40theoplayer%2Fnielsen-connector-web)](https://npmjs.com/package/@theoplayer/nielsen-connector-web) | [nielsen](https://github.com/THEOplayer/web-connectors/tree/main/nielsen) | | Yospace | [![@theoplayer/yospace-connector-web](https://img.shields.io/npm/v/%40theoplayer%2Fyospace-connector-web?label=%40theoplayer%2Fyospace-connector-web)](https://npmjs.com/package/@theoplayer/yospace-connector-web) | [yospace](https://github.com/THEOplayer/web-connectors/tree/main/yospace) |