Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

@remotion/webcodecs: Send usage event with @remotion/licensing #4639

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions packages/docs/docs/media-parser/parse-media.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,10 @@ If the signal is aborted, the parser will stop reading the media and stop the de

### Callbacks

Each field also has a callback that allows you to retrieve the value as soon as it is obtained without waiting for the function to resolve.
You must pass `true` as the value for the field in order for the callback to be called.
Each field also has a callback that allows you to retrieve the value as soon as it is obtained without waiting for the function to resolve.

You do not have to add the field to the [`fields`](#fields) object if you use the callback.
However, just like with [`fields`](#fields), adding a callback for a [slow field](/docs/media-parser/fast-and-slow) may require reading more of the file.

```tsx twoslash title="Using a callback"
// @module: es2022
Expand All @@ -254,10 +256,6 @@ import {parseMedia} from '@remotion/media-parser';

const result = await parseMedia({
src: 'https://example.com/my-video.mp4',
fields: {
durationInSeconds: true,
dimensions: true,
},
onDurationInSeconds: (durationInSeconds) => {
console.log(durationInSeconds);
},
Expand Down
8 changes: 8 additions & 0 deletions packages/docs/docs/webcodecs/convert-media.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ _number_

The number of degrees to rotate the video. See [Rotate a video](/docs/webcodecs/rotate-a-video) for more information.

### `apiKey?`

If you are a customer of a [Remotion Company License](https://remotion.pro/license), you can provide an API key from your dashboard to track your conversions.

:::note
[Telemetry is enabled](/docs/webcodecs/telemetry) even if you don't provide an API key.
:::

### `logLevel?`

_string_ <TsType type="LogLevel" source="@remotion/media-parser"/>
Expand Down
61 changes: 61 additions & 0 deletions packages/docs/docs/webcodecs/telemetry.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
image: /generated/articles-docs-webcodecs-telemetry.png
id: telemetry
title: Telemetry in @remotion/webcodecs
slug: /webcodecs/telemetry
crumb: '@remotion/webcodecs'
---

Upon finishing a conversion with [`convertMedia()`](/docs/webcodecs/convert-media), a HTTP request is sent to an endpoint on [`remotion.pro`](https://remotion.pro), registering the domain and whether the conversion was successful.

Telemetry will never cause any conversions to fail.

import {LicenseDisclaimer} from './LicenseDisclaimer';

<details>
<summary>💼 Important License Disclaimer</summary>
<LicenseDisclaimer />
</details>

## Data collection

No user data is collected, however the IP address may be used to reject invalid telemetry.

## Use of data

Telemetry data helps Remotion understand which sites use the [`@remotion/webcodecs`](/docs/webcodecs) package.

Historically, it's been difficult to understand which sites use Remotion and various sizable companies have been using it without getting the appropriate license.

Hence we have decided to add telemetry to this new package.

Remotion will not share any telemetry data with others.

## Track conversions with an API key

You may add an API key that you obtained from [`remotion.pro`](https://remotion.pro) to the [`convertMedia()`](/docs/webcodecs/convert-media) function.

```tsx twoslash title="Adding an API key"
// @module: es2022
// @target: es2017
import {convertMedia} from '@remotion/webcodecs';

await convertMedia({
src: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
container: 'webm',
apiKey: 'rm_pub_abcdefghijklo',
});
```

You will then be able to see the amount of conversions you did on your dashboard.
For now, you still need to adjust the license manually to cover your WebCodecs conversions.

## Disabling telemetry

A version of [`@remotion/webcodecs`](/docs/webcodecs) without telemetry can be obtained with an Remotion Enterprise License.
Contact [email protected] to request an Enterprise License.

## See also

- [`@remotion/licensing`](/docs/licensing)
- [`convertMedia()`](/docs/webcodecs/convert-media)
1 change: 1 addition & 0 deletions packages/docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ module.exports = {
'webcodecs/convert-a-video',
'webcodecs/rotate-a-video',
'webcodecs/fix-mediarecorder-video',
'webcodecs/telemetry',
],
},
{
Expand Down
7 changes: 7 additions & 0 deletions packages/docs/src/data/articles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3382,6 +3382,13 @@ export const articles = [
compId: 'articles-docs-webcodecs-fix-a-mediarecorder-video',
crumb: '@remotion/webcodecs',
},
{
id: 'telemetry',
title: 'Telemetry in @remotion/webcodecs',
relativePath: 'docs/webcodecs/telemetry.mdx',
compId: 'articles-docs-webcodecs-telemetry',
crumb: '@remotion/webcodecs',
},
{
id: 'convert-a-video',
title: 'Convert a video',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions packages/licensing/src/register-usage-point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const registerUsageEvent = async ({
succeeded,
event,
}: {
apiKey: string;
host: string;
apiKey: string | null;
host: string | null;
succeeded: boolean;
event: UsageEventType;
}): Promise<RegisterUsageEventResponse> => {
Expand Down
22 changes: 17 additions & 5 deletions packages/licensing/src/test/register.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {registerUsageEvent} from '../register-usage-point';

test('Should be able to track production usage', async () => {
const result = await registerUsageEvent({
apiKey: 'rm_pub_1dd7193534bbe72571b55bd43926654ddaaca3dd6f07772b',
apiKey: 'rm_pub_cbbf1d1e7f07cb0b86daa0247693d6c9af4740463768f2f6',
host: 'http://localhost:50955',
succeeded: true,
event: 'webcodec-conversion',
Expand All @@ -20,7 +20,7 @@ test('Should be able to track production usage', async () => {

test('Should be able to track development usage', async () => {
const result = await registerUsageEvent({
apiKey: 'rm_pub_1dd7193534bbe72571b55bd43926654ddaaca3dd6f07772b',
apiKey: 'rm_pub_cbbf1d1e7f07cb0b86daa0247693d6c9af4740463768f2f6',
host: 'https://remotion.dev',
succeeded: true,
event: 'webcodec-conversion',
Expand All @@ -30,8 +30,20 @@ test('Should be able to track development usage', async () => {
classification: 'billable',
});
});
test('Should be able to track without host', async () => {
const result = await registerUsageEvent({
apiKey: 'rm_pub_cbbf1d1e7f07cb0b86daa0247693d6c9af4740463768f2f6',
host: null,
succeeded: true,
event: 'webcodec-conversion',
});
expect(result).toEqual({
billable: true,
classification: 'billable',
});
});

test('Should reject invalid API key', async () => {
test('Should reject invalid API key', () => {
const result = registerUsageEvent({
apiKey: 'rm_pub_1dd719b',
host: 'http://localhost:50955',
Expand Down Expand Up @@ -63,7 +75,7 @@ test('should require secret key for usage', () => {

test('should be able to get usage', async () => {
const result = await getUsage({
apiKey: 'rm_sec_7cef7338672c2b474729ac081134a6ded7dc360baf0068fe',
apiKey: 'rm_sec_b776a51f683c850101ece5c580c7db7281397d1864e076a9',
since: null,
});

Expand All @@ -75,7 +87,7 @@ test('should be able to get usage', async () => {
expect(result.cloudRenders.failed).toBeGreaterThanOrEqual(0);
});

test('should not be able to get usage older than 90 says', async () => {
test('should not be able to get usage older than 90 says', () => {
const result = getUsage({
apiKey: 'rm_sec_7cef7338672c2b474729ac081134a6ded7dc360baf0068fe',
since: new Date().getTime() - 1000 * 60 * 60 * 24 * 700,
Expand Down
3 changes: 2 additions & 1 deletion packages/webcodecs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"author": "Jonny Burger <[email protected]>",
"license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)",
"dependencies": {
"@remotion/media-parser": "workspace:*"
"@remotion/media-parser": "workspace:*",
"@remotion/licensing": "workspace:*"
},
"peerDependencies": {},
"devDependencies": {
Expand Down
14 changes: 14 additions & 0 deletions packages/webcodecs/src/convert-media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ import {generateOutputFilename} from './generate-output-filename';
import type {ConvertMediaAudioCodec} from './get-available-audio-codecs';
import type {ConvertMediaContainer} from './get-available-containers';
import type {ConvertMediaVideoCodec} from './get-available-video-codecs';
import {Log} from './log';
import {makeAudioTrackHandler} from './on-audio-track';
import {type ConvertMediaOnAudioTrackHandler} from './on-audio-track-handler';
import {makeVideoTrackHandler} from './on-video-track';
import {type ConvertMediaOnVideoTrackHandler} from './on-video-track-handler';
import {selectContainerCreator} from './select-container-creator';
import {sendUsageEvent} from './send-telemetry-event';
import {throttledStateUpdate} from './throttled-state-update';

export type ConvertMediaProgress = {
Expand Down Expand Up @@ -74,6 +76,7 @@ export const convertMedia = async function <
writer,
progressIntervalInMs,
rotate,
apiKey,
...more
}: {
src: ParseMediaOptions<F>['src'];
Expand All @@ -90,6 +93,7 @@ export const convertMedia = async function <
writer?: WriterInterface;
progressIntervalInMs?: number;
rotate?: number;
apiKey?: string | null;
} & ParseMediaDynamicOptions<F>): Promise<ConvertMediaResult> {
if (userPassedAbortSignal?.aborted) {
return Promise.reject(new Error('Aborted'));
Expand Down Expand Up @@ -243,7 +247,17 @@ export const convertMedia = async function <
finalState: throttledState.get(),
});
})
.then(() => {
sendUsageEvent({succeeded: true, apiKey: apiKey ?? null}).catch((err) => {
Log.error('Failed to send usage event', err);
});
})
.catch((err) => {
sendUsageEvent({succeeded: false, apiKey: apiKey ?? null}).catch(
(err2) => {
Log.error('Failed to send usage event hmm', err2);
},
);
reject(err);
})
.finally(() => {
Expand Down
26 changes: 26 additions & 0 deletions packages/webcodecs/src/send-telemetry-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {registerUsageEvent} from '@remotion/licensing';

export const sendUsageEvent = async ({
apiKey,
succeeded,
}: {
apiKey: string | null;
succeeded: boolean;
}) => {
const host =
typeof window === 'undefined'
? null
: typeof window.location === 'undefined'
? null
: (window.location.origin ?? null);
if (host === null) {
return;
}

await registerUsageEvent({
apiKey,
event: 'webcodec-conversion',
host,
succeeded,
});
};
3 changes: 3 additions & 0 deletions packages/webcodecs/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
"references": [
{
"path": "../media-parser"
},
{
"path": "../licensing"
}
]
}
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading