Skip to content
This repository has been archived by the owner on Apr 1, 2023. It is now read-only.

Commit

Permalink
feat: add methods uploadResourceAsBlob and downloadResourceAsBlob (
Browse files Browse the repository at this point in the history
  • Loading branch information
robingenz authored Jan 11, 2023
1 parent 6624ced commit e19991e
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 82 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ further processing after downloading.

</docgen-api>

## Utils

See [docs/utils/README.md](/docs/utils/README.md).

## Changelog

See [CHANGELOG.md](https://github.com/capawesome-team/capacitor-cloudinary/blob/main/CHANGELOG.md).
Expand Down
117 changes: 117 additions & 0 deletions docs/utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Utils

## API

<docgen-index>

* [`uploadResourceAsBlob(...)`](#uploadresourceasblob)
* [`downloadResourceAsBlob(...)`](#downloadresourceasblob)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)
* [Enums](#enums)

</docgen-index>

<docgen-api>
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->

### uploadResourceAsBlob(...)

```typescript
uploadResourceAsBlob(options: UploadResourceAsBlobOptions) => Promise<UploadResourceResult>
```

Upload a file to Cloudinary as a blob.

| Param | Type |
| ------------- | ----------------------------------------------------------------------------------- |
| **`options`** | <code><a href="#uploadresourceasbloboptions">UploadResourceAsBlobOptions</a></code> |

**Returns:** <code>Promise&lt;<a href="#uploadresourceresult">UploadResourceResult</a>&gt;</code>

**Since:** 0.1.1

--------------------


### downloadResourceAsBlob(...)

```typescript
downloadResourceAsBlob(options: DownloadResourceAsBlobOptions) => Promise<DownloadResourceAsBlobResult>
```

Download a file from Cloudinary as a blob.

| Param | Type |
| ------------- | --------------------------------------------------------------------------- |
| **`options`** | <code><a href="#downloadresourceoptions">DownloadResourceOptions</a></code> |

**Returns:** <code>Promise&lt;<a href="#downloadresourceasblobresult">DownloadResourceAsBlobResult</a>&gt;</code>

**Since:** 0.1.1

--------------------


### Interfaces


#### UploadResourceResult

| Prop | Type | Description | Since |
| ---------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------- | ----- |
| **`assetId`** | <code>string</code> | The unique asset identifier of the uploaded resource. Only available on Android and Web. | 0.0.1 |
| **`bytes`** | <code>number</code> | The number of bytes of the uploaded resource. Only available on Android and Web. | 0.0.1 |
| **`createdAt`** | <code>string</code> | The timestamp at which the resource was uploaded. | 0.0.1 |
| **`format`** | <code>string</code> | The format of the uploaded resource. | 0.0.1 |
| **`originalFilename`** | <code>string</code> | The original filename of the uploaded resource. Only available on Android and iOS. | 0.0.1 |
| **`resourceType`** | <code><a href="#resourcetype">ResourceType</a></code> | The resource type of the uploaded resource. | 0.0.1 |
| **`publicId`** | <code>string</code> | The unique public identifier of the uploaded resource. | 0.0.1 |
| **`url`** | <code>string</code> | The url of the uploaded resource. | 0.0.1 |


#### UploadResourceAsBlobOptions

| Prop | Type | Description | Since |
| ------------------ | ----------------------------------------------------- | ----------------------------------------------------------------------------------- | ----- |
| **`cloudName`** | <code>string</code> | The cloud name of your app which you can find in the Cloudinary Management Console. | 0.1.1 |
| **`resourceType`** | <code><a href="#resourcetype">ResourceType</a></code> | The resource type to upload. | 0.1.1 |
| **`blob`** | <code>Blob</code> | The file to upload. | 0.1.1 |
| **`uploadPreset`** | <code>string</code> | The selected upload preset. | 0.1.1 |
| **`publicId`** | <code>string</code> | Assign a unique public identifier to the resource. | 0.1.1 |


#### DownloadResourceAsBlobResult

| Prop | Type | Description | Since |
| ---------- | ----------------- | ---------------------------------- | ----- |
| **`blob`** | <code>Blob</code> | The downloaded resource as a blob. | 0.1.1 |


#### DownloadResourceOptions

| Prop | Type | Description | Since |
| --------- | ------------------- | ------------------------------------ | ----- |
| **`url`** | <code>string</code> | The url of the resource to download. | 0.0.3 |


### Type Aliases


#### DownloadResourceAsBlobOptions

<code><a href="#downloadresourceoptions">DownloadResourceOptions</a></code>


### Enums


#### ResourceType

| Members | Value | Since |
| ----------- | -------------------- | ----- |
| **`Image`** | <code>'image'</code> | 0.0.1 |
| **`Video`** | <code>'video'</code> | 0.0.1 |
| **`Raw`** | <code>'raw'</code> | 0.0.1 |

</docgen-api>
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
"eslint": "eslint . --ext ts",
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
"swiftlint": "node-swiftlint",
"docgen": "docgen --api CloudinaryPlugin --output-readme README.md --output-json dist/docs.json",
"docgen": "npm run docgen:plugin && npm run docgen:utils",
"docgen:plugin": "docgen --api CloudinaryPlugin --output-readme README.md --output-json dist/docs.json",
"docgen:utils": "docgen --api ICloudinaryUtils --output-readme docs/utils/README.md --output-json dist/utils-docs.json",
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js",
"clean": "rimraf ./dist",
"watch": "tsc --watch",
Expand Down
82 changes: 82 additions & 0 deletions src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,85 @@ export enum ResourceType {
*/
Raw = 'raw',
}

/**
* @since 0.1.1
*/
export interface ICloudinaryUtils {
/**
* Upload a file to Cloudinary as a blob.
*
* @since 0.1.1
*/
uploadResourceAsBlob(
options: UploadResourceAsBlobOptions,
): Promise<UploadResourceResult>;
/**
* Download a file from Cloudinary as a blob.
*
* @since 0.1.1
*/
downloadResourceAsBlob(
options: DownloadResourceAsBlobOptions,
): Promise<DownloadResourceAsBlobResult>;
}

/**
* @since 0.1.1
*/
export interface UploadResourceAsBlobOptions {
/**
* The cloud name of your app which you can find in the Cloudinary Management Console.
*
* @since 0.1.1
*/
cloudName: string;
/**
* The resource type to upload.
*
* @since 0.1.1
*/
resourceType: ResourceType;
/**
* The file to upload.
*
* @since 0.1.1
*/
blob: Blob;
/**
* The selected upload preset.
*
* @since 0.1.1
* @see https://cloudinary.com/documentation/upload_presets
*/
uploadPreset: string;
/**
* Assign a unique public identifier to the resource.
*
* @since 0.1.1
* @see https://cloudinary.com/documentation/upload_images#public_id
*/
publicId?: string;
}

/**
* @since 0.1.1
*/
export type UploadResourceAsBlobResult = UploadResourceResult;

/**
* @since 0.1.1
*/
export type DownloadResourceAsBlobOptions = DownloadResourceOptions;

/**
* @since 0.1.1
*/
export interface DownloadResourceAsBlobResult {
/**
* The downloaded resource as a blob.
*
* @since 0.1.1
*/
blob: Blob;
}
104 changes: 104 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type {
ResourceType,
ICloudinaryUtils,
UploadResourceAsBlobOptions,
DownloadResourceAsBlobOptions,
DownloadResourceAsBlobResult,
UploadResourceAsBlobResult,
} from './definitions';

export class CloudinaryUtils implements ICloudinaryUtils {
public async uploadResourceAsBlob(
options: UploadResourceAsBlobOptions,
): Promise<UploadResourceAsBlobResult> {
const uniqueUploadId = this.generateUniqueId();
const chunkSize = 1024 * 1024 * 10; // 10 Megabytes
const totalSize = options.blob.size;
const chunks: { start: number; end: number; blob: Blob }[] = [];

let start = 0;
let end = Math.min(chunkSize, totalSize);
while (start < totalSize) {
const blob = options.blob.slice(start, end);
chunks.push({ start, end, blob });
start = end;
end = Math.min(start + chunkSize, totalSize);
}
let response: any;
for (const chunk of chunks) {
const { start, end, blob } = chunk;
response = await this.uploadResourceChunk(
options,
uniqueUploadId,
start,
end - 1,
totalSize,
blob,
);
}
return {
assetId: response.asset_id,
bytes: response.bytes,
createdAt: response.created_at,
format: response.format,
originalFilename: response.original_filename,
resourceType: response.resource_type,
publicId: response.public_id,
url: response.secure_url,
};
}

public async downloadResourceAsBlob(
options: DownloadResourceAsBlobOptions,
): Promise<DownloadResourceAsBlobResult> {
const blob = await fetch(options.url).then(res => res.blob());
return {
blob,
};
}

private async uploadResourceChunk(
options: {
cloudName: string;
resourceType: ResourceType;
blob: Blob;
uploadPreset: string;
publicId?: string;
},
uniqueUploadId: string,
start: number,
end: number,
size: number,
chunk: Blob,
): Promise<any> {
const formData = new FormData();
formData.append('file', chunk);
formData.append('upload_preset', options.uploadPreset);
formData.append('cloud_name', options.cloudName);
if (options.publicId) {
formData.append('public_id', options.publicId);
}
return fetch(
`https://api.cloudinary.com/v1_1/${options.cloudName}/${options.resourceType}/upload`,
{
method: 'PUT',
body: formData,
headers: {
'X-Unique-Upload-Id': uniqueUploadId,
'Content-Range': `bytes ${start}-${end}/${size}`,
},
},
).then(async response => {
if (!response.ok) {
throw new Error(
`Request failed with status ${response.status}: ${response.statusText}`,
);
}
return response.json();
});
}

private generateUniqueId(): string {
return Date.now().toString(36) + Math.random().toString(36).substring(2);
}
}
Loading

0 comments on commit e19991e

Please sign in to comment.