mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-21 11:49:59 +00:00
fix(YouTube Node): Chunk file content before uploading (#15405)
This commit is contained in:
@@ -8,7 +8,7 @@ import type {
|
|||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { NodeConnectionTypes, BINARY_ENCODING, NodeOperationError } from 'n8n-workflow';
|
import { NodeConnectionTypes, BINARY_ENCODING, NodeOperationError } from 'n8n-workflow';
|
||||||
import type { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
|
|
||||||
import { isoCountryCodes } from '@utils/ISOCountryCodes';
|
import { isoCountryCodes } from '@utils/ISOCountryCodes';
|
||||||
|
|
||||||
@@ -839,7 +839,7 @@ export class YouTube implements INodeType {
|
|||||||
|
|
||||||
let mimeType: string;
|
let mimeType: string;
|
||||||
let contentLength: number;
|
let contentLength: number;
|
||||||
let fileContent: Buffer | Readable;
|
let fileContent: Readable;
|
||||||
|
|
||||||
if (binaryData.id) {
|
if (binaryData.id) {
|
||||||
// Stream data in 256KB chunks, and upload the via the resumable upload api
|
// Stream data in 256KB chunks, and upload the via the resumable upload api
|
||||||
@@ -848,8 +848,9 @@ export class YouTube implements INodeType {
|
|||||||
contentLength = metadata.fileSize;
|
contentLength = metadata.fileSize;
|
||||||
mimeType = metadata.mimeType ?? binaryData.mimeType;
|
mimeType = metadata.mimeType ?? binaryData.mimeType;
|
||||||
} else {
|
} else {
|
||||||
fileContent = Buffer.from(binaryData.data, BINARY_ENCODING);
|
const buffer = Buffer.from(binaryData.data, BINARY_ENCODING);
|
||||||
contentLength = fileContent.length;
|
fileContent = Readable.from(buffer);
|
||||||
|
contentLength = buffer.length;
|
||||||
mimeType = binaryData.mimeType;
|
mimeType = binaryData.mimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import type { MockProxy } from 'jest-mock-extended';
|
||||||
|
import { mock } from 'jest-mock-extended';
|
||||||
|
import type { IExecuteFunctions } from 'n8n-workflow';
|
||||||
|
import { Readable } from 'stream';
|
||||||
|
|
||||||
|
import * as genericFunctions from '../../GenericFunctions';
|
||||||
|
import { YouTube } from '../../YouTube.node';
|
||||||
|
|
||||||
|
jest.mock('../../GenericFunctions', () => {
|
||||||
|
const originalModule = jest.requireActual('../../GenericFunctions');
|
||||||
|
return {
|
||||||
|
...originalModule,
|
||||||
|
googleApiRequest: jest.fn(async function (method: string) {
|
||||||
|
if (method === 'POST') {
|
||||||
|
return {
|
||||||
|
headers: { location: 'https://www.youtube.com/watch?v=1234' },
|
||||||
|
body: { id: '1234' },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const httpRequestMock = jest.fn(() => ({ id: '5678' }));
|
||||||
|
|
||||||
|
describe('Test YouTube, video => upload', () => {
|
||||||
|
let youTube: YouTube;
|
||||||
|
let mockExecuteFunctions: MockProxy<IExecuteFunctions>;
|
||||||
|
let fromSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fromSpy = jest.spyOn(Readable, 'from');
|
||||||
|
youTube = new YouTube();
|
||||||
|
mockExecuteFunctions = mock<IExecuteFunctions>();
|
||||||
|
const buffer = Buffer.alloc(2 * 1024 * 1024, 'a');
|
||||||
|
mockExecuteFunctions.helpers = {
|
||||||
|
constructExecutionMetaData: jest.fn(() => []),
|
||||||
|
returnJsonArray: jest.fn(() => []),
|
||||||
|
assertBinaryData: jest.fn(() => ({ data: buffer.toString('base64'), mimeType: 'video/mp4' })),
|
||||||
|
httpRequest: httpRequestMock,
|
||||||
|
} as any;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fromSpy.mockRestore();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create readable from buffer', async () => {
|
||||||
|
const items = [{ json: { data: 'test' } }];
|
||||||
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||||
|
mockExecuteFunctions.getNodeParameter.mockImplementation((key: string) => {
|
||||||
|
switch (key) {
|
||||||
|
case 'resource':
|
||||||
|
return 'video';
|
||||||
|
case 'operation':
|
||||||
|
return 'upload';
|
||||||
|
case 'title':
|
||||||
|
return 'test';
|
||||||
|
case 'categoryId':
|
||||||
|
return '11';
|
||||||
|
case 'options':
|
||||||
|
return {};
|
||||||
|
case 'binaryProperty':
|
||||||
|
return 'data';
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await youTube.execute.call(mockExecuteFunctions);
|
||||||
|
|
||||||
|
expect(genericFunctions.googleApiRequest).toHaveBeenCalledTimes(1);
|
||||||
|
expect(genericFunctions.googleApiRequest).toHaveBeenCalledWith(
|
||||||
|
'POST',
|
||||||
|
'/upload/youtube/v3/videos',
|
||||||
|
{
|
||||||
|
recordingDetails: { recordingDate: undefined },
|
||||||
|
snippet: {
|
||||||
|
categoryId: '11',
|
||||||
|
defaultLanguage: undefined,
|
||||||
|
description: undefined,
|
||||||
|
tags: undefined,
|
||||||
|
title: 'test',
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
embeddable: undefined,
|
||||||
|
license: undefined,
|
||||||
|
privacyStatus: undefined,
|
||||||
|
publicStatsViewable: undefined,
|
||||||
|
publishAt: undefined,
|
||||||
|
selfDeclaredMadeForKids: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
notifySubscribers: false,
|
||||||
|
part: 'snippet,status,recordingDetails',
|
||||||
|
uploadType: 'resumable',
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
headers: { 'X-Upload-Content-Length': 2097152, 'X-Upload-Content-Type': 'video/mp4' },
|
||||||
|
json: true,
|
||||||
|
resolveWithFullResponse: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(httpRequestMock).toHaveBeenCalledWith({
|
||||||
|
body: expect.any(Object),
|
||||||
|
headers: { 'Content-Length': 2097152, 'Content-Range': 'bytes 0-2097151/2097152' },
|
||||||
|
method: 'PUT',
|
||||||
|
url: 'https://www.youtube.com/watch?v=1234',
|
||||||
|
});
|
||||||
|
expect(fromSpy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user