diff --git a/modules/persistence/Settings.js b/modules/persistence/Settings.js
index 867cc377..f2ef05eb 100644
--- a/modules/persistence/Settings.js
+++ b/modules/persistence/Settings.js
@@ -5,7 +5,7 @@ const fs = require("fs").promises;
class Settings {
constructor(
paths, env, outputFormat, audioOutputFormat, downloadPath,
- proxy, rateLimit, autoFillClipboard, noPlaylist, globalShortcut, spoofUserAgent,
+ proxy, rateLimit, autoFillClipboard, noPlaylist, globalShortcut, userAgent,
validateCertificate, enableEncoding, taskList, nameFormat, nameFormatMode,
sizeMode, splitMode, maxConcurrent, updateBinary, downloadType, updateApplication, cookiePath,
statSend, downloadMetadata, downloadThumbnail, keepUnmerged, calculateTotalSize, theme
@@ -20,7 +20,7 @@ class Settings {
this.autoFillClipboard = autoFillClipboard == null ? true : autoFillClipboard;
this.noPlaylist = noPlaylist == null ? false : noPlaylist;
this.globalShortcut = globalShortcut == null ? true : globalShortcut;
- this.spoofUserAgent = spoofUserAgent == null ? true : spoofUserAgent;
+ this.userAgent = userAgent == null ? "spoof" : userAgent;
this.validateCertificate = validateCertificate == null ? false : validateCertificate;
this.enableEncoding = enableEncoding == null ? false : enableEncoding;
this.taskList = taskList == null ? true : taskList;
@@ -57,7 +57,7 @@ class Settings {
data.autoFillClipboard,
data.noPlaylist,
data.globalShortcut,
- data.spoofUserAgent,
+ data.userAgent,
data.validateCertificate,
data.enableEncoding,
data.taskList,
@@ -94,7 +94,7 @@ class Settings {
this.autoFillClipboard = settings.autoFillClipboard;
this.noPlaylist = settings.noPlaylist;
this.globalShortcut = settings.globalShortcut;
- this.spoofUserAgent = settings.spoofUserAgent;
+ this.userAgent = settings.userAgent;
this.validateCertificate = settings.validateCertificate;
this.enableEncoding = settings.enableEncoding;
this.taskList = settings.taskList;
@@ -131,7 +131,7 @@ class Settings {
autoFillClipboard: this.autoFillClipboard,
noPlaylist: this.noPlaylist,
globalShortcut: this.globalShortcut,
- spoofUserAgent: this.spoofUserAgent,
+ userAgent: this.userAgent,
validateCertificate: this.validateCertificate,
enableEncoding: this.enableEncoding,
taskList: this.taskList,
@@ -156,7 +156,6 @@ class Settings {
}
save() {
- console.log(this.serialize());
fs.writeFile(this.paths.settings, JSON.stringify(this.serialize()), "utf8").then(() => {
console.log("Saved settings file.")
});
diff --git a/modules/types/Query.js b/modules/types/Query.js
index 2d56b17a..47aa1778 100644
--- a/modules/types/Query.js
+++ b/modules/types/Query.js
@@ -22,9 +22,12 @@ class Query {
args.push("--no-cache-dir");
args.push("--ignore-config");
- if(this.environment.settings.spoofUserAgent) {
+ if(this.environment.settings.userAgent === "spoof") {
args.push("--user-agent"); //Add random user agent to slow down user agent profiling
args.push(new UserAgent({ deviceCategory: 'desktop' }).toString());
+ } else if(this.environment.settings.userAgent === "empty") {
+ args.push("--user-agent");
+ args.push("''"); //Add an empty user agent string to workaround VR video issues
}
if(this.environment.settings.proxy != null && this.environment.settings.proxy.length > 0) {
diff --git a/renderer/renderer.html b/renderer/renderer.html
index 258b969a..08ef8ddb 100644
--- a/renderer/renderer.html
+++ b/renderer/renderer.html
@@ -388,8 +388,12 @@
Advanced
-
-
+
+
diff --git a/renderer/renderer.js b/renderer/renderer.js
index 35937dc1..4ec8300a 100644
--- a/renderer/renderer.js
+++ b/renderer/renderer.js
@@ -978,7 +978,7 @@ async function getSettings() {
const settings = await window.main.invoke("settingsAction", {action: "get"});
$('#updateBinary').prop('checked', settings.updateBinary);
$('#updateApplication').prop('checked', settings.updateApplication);
- $('#spoofUserAgent').prop('checked', settings.spoofUserAgent);
+ $('#userAgent').val(settings.userAgent);
$('#validateCertificate').prop('checked', settings.validateCertificate);
$('#enableEncoding').prop('checked', settings.enableEncoding);
$('#taskList').prop('checked', settings.taskList);
@@ -1014,7 +1014,7 @@ function sendSettings() {
outputFormat: $('#outputFormat').val(),
audioOutputFormat: $('#audioOutputFormat').val(),
proxy: $('#proxySetting').val(),
- spoofUserAgent: $('#spoofUserAgent').prop('checked'),
+ userAgent: $('#userAgent').val(),
validateCertificate: $('#validateCertificate').prop('checked'),
enableEncoding: $('#enableEncoding').prop('checked'),
taskList: $('#taskList').prop('checked'),
diff --git a/tests/Query.test.js b/tests/Query.test.js
index 524f72bd..21113b0b 100644
--- a/tests/Query.test.js
+++ b/tests/Query.test.js
@@ -25,16 +25,26 @@ describe('ytdl Query', () => {
it('adds a random user agent when this setting is enabled', () => {
UserAgent.prototype.toString = jest.fn().mockReturnValue("agent");
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(true, null, errorHandlerMock, "python");
+ const instance = instanceBuilder("spoof", null, errorHandlerMock, "python");
return instance.start("https://url.link", [], null).then(() => {
expect(UserAgent.prototype.toString).toBeCalledTimes(1);
expect(execa.mock.calls[0][1]).toContain("--user-agent");
expect(execa.mock.calls[0][1]).toContain("agent");
});
});
+ it('adds an empty user agent when this setting is enabled', () => {
+ UserAgent.prototype.toString = jest.fn().mockReturnValue("agent");
+ const errorHandlerMock = jest.fn();
+ const instance = instanceBuilder("empty", null, errorHandlerMock, "python");
+ return instance.start("https://url.link", [], null).then(() => {
+ expect(UserAgent.prototype.toString).toBeCalledTimes(0);
+ expect(execa.mock.calls[0][1]).toContain("--user-agent");
+ expect(execa.mock.calls[0][1]).toContain("''");
+ });
+ });
it('adds the proxy when one is set', () => {
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(false, "a/path/to/cookies.txt", errorHandlerMock, "python", "https://iama.proxy");
+ const instance = instanceBuilder("default", "a/path/to/cookies.txt", errorHandlerMock, "python", "https://iama.proxy");
return instance.start("https://url.link", [], null).then(() => {
expect(execa.mock.calls[0][1]).toContain("--proxy");
expect(execa.mock.calls[0][1]).toContain("https://iama.proxy");
@@ -42,14 +52,14 @@ describe('ytdl Query', () => {
})
it('does not add a proxy when none are set', () => {
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(false, "a/path/to/cookies.txt", errorHandlerMock, "python", "");
+ const instance = instanceBuilder("default", "a/path/to/cookies.txt", errorHandlerMock, "python", "");
return instance.start("https://url.link", [], null).then(() => {
expect(execa.mock.calls[0][1]).not.toContain("--proxy");
});
})
it('adds the cookies argument when specified in settings', () => {
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(false, "a/path/to/cookies.txt", errorHandlerMock, "python");
+ const instance = instanceBuilder("default", "a/path/to/cookies.txt", errorHandlerMock, "python");
return instance.start("https://url.link", [], null).then(() => {
expect(execa.mock.calls[0][1]).toContain("--cookies");
expect(execa.mock.calls[0][1]).toContain("a/path/to/cookies.txt");
@@ -57,7 +67,7 @@ describe('ytdl Query', () => {
});
it('uses the detected python command', () => {
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(false, null, errorHandlerMock, "python3");
+ const instance = instanceBuilder("default", null, errorHandlerMock, "python3");
return instance.start("https://url.link", [], null).then(() => {
expect(execa.mock.calls[0][0]).toEqual("python3");
expect(execa.mock.calls[0][1][0]).toEqual("a/path/to/ytdl");
@@ -65,14 +75,14 @@ describe('ytdl Query', () => {
});
it('adds the url as final argument', () => {
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(false, null, errorHandlerMock, "python");
+ const instance = instanceBuilder("default", null, errorHandlerMock, "python");
return instance.start("https://url.link", [], null).then(() => {
expect(execa.mock.calls[0][1][execa.mock.calls[0][1].length - 1]).toContain("https://url.link");
});
})
it('adds the no-cache-dir as argument', () => {
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(false, null, errorHandlerMock, "python");
+ const instance = instanceBuilder("default", null, errorHandlerMock, "python");
return instance.start("https://url.link", [], null).then(() => {
expect(execa.mock.calls[0][1]).toContain("--no-cache-dir");
});
@@ -85,7 +95,7 @@ describe('Query with live callback', () => {
execa.mockReturnValue(mock)
const errorHandlerMock = jest.fn();
const callbackMock = jest.fn();
- const instance = instanceBuilder(false, null, errorHandlerMock, "python");
+ const instance = instanceBuilder("default", null, errorHandlerMock, "python");
const result = instance.start("https://url.link", [], callbackMock);
setTimeout(() => {
instance.stop();
@@ -99,7 +109,7 @@ describe('Query with live callback', () => {
console.error = jest.fn();
const errorHandlerMock = jest.fn();
const callbackMock = jest.fn();
- const instance = instanceBuilder(false, null, errorHandlerMock, "python");
+ const instance = instanceBuilder("default", null, errorHandlerMock, "python");
const result = instance.start("https://url.link", [], callbackMock);
setTimeout(() => {
stderr.emit("data", "test-error");
@@ -114,7 +124,7 @@ describe('Query with live callback', () => {
const [stdout, stderr, mock] = execaMockBuilder(false);
execa.mockReturnValue(mock)
const callbackMock = jest.fn();
- const instance = instanceBuilder(false, null, jest.fn(), "python");
+ const instance = instanceBuilder("default", null, jest.fn(), "python");
const result = instance.start("https://url.link", [], callbackMock);
setTimeout(() => {
stdout.emit("close");
@@ -126,7 +136,7 @@ describe('Query with live callback', () => {
const [stdout, stderr, mock] = execaMockBuilder(false);
execa.mockReturnValue(mock);
const callbackMock = jest.fn();
- const instance = instanceBuilder(false, null, jest.fn(), "python");
+ const instance = instanceBuilder("default", null, jest.fn(), "python");
const result = instance.start("https://url.link", [], callbackMock);
setTimeout(() => {
stdout.emit("data", "test-data");
@@ -143,21 +153,21 @@ describe('Query without callback', () => {
it('Returns the data from the execa call', async () => {
execa.mockResolvedValue({stdout: "fake-data"});
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(true, null, errorHandlerMock, "python");
+ const instance = instanceBuilder("default", null, errorHandlerMock, "python");
const result = instance.start("https://url.link", [], null)
await expect(result).resolves.toEqual("fake-data");
});
it('Returns a stringified empty object on error', async () => {
execa.mockResolvedValue(null);
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(true, null, errorHandlerMock, "python");
+ const instance = instanceBuilder("default", null, errorHandlerMock, "python");
const result = instance.start("https://url.link", [], null)
await expect(result).resolves.toEqual("{}");
});
it('Checks the error on error', () => {
execa.mockResolvedValue(null);
const errorHandlerMock = jest.fn();
- const instance = instanceBuilder(true, null, errorHandlerMock, "python");
+ const instance = instanceBuilder("default", null, errorHandlerMock, "python");
return instance.start("https://url.link", [], null).then(() => {
expect(errorHandlerMock).toBeCalled();
});
@@ -171,6 +181,6 @@ function execaMockBuilder(killed) {
return [stdout, stderr, mock];
}
-function instanceBuilder(spoofUserAgent, cookiePath, errorHandlerMock, pythonCommand, proxy) {
- return new Query({pythonCommand: pythonCommand, errorHandler: {checkError: errorHandlerMock, raiseUnhandledError: errorHandlerMock}, paths: {ytdl: "a/path/to/ytdl"}, settings: {cookiePath: cookiePath, spoofUserAgent: spoofUserAgent, proxy: proxy}}, "test__id");
+function instanceBuilder(userAgent, cookiePath, errorHandlerMock, pythonCommand, proxy) {
+ return new Query({pythonCommand: pythonCommand, errorHandler: {checkError: errorHandlerMock, raiseUnhandledError: errorHandlerMock}, paths: {ytdl: "a/path/to/ytdl"}, settings: {cookiePath: cookiePath, userAgent, proxy: proxy}}, "test__id");
}
diff --git a/tests/Settings.test.js b/tests/Settings.test.js
index 07514a92..4fa5a8b3 100644
--- a/tests/Settings.test.js
+++ b/tests/Settings.test.js
@@ -2,8 +2,8 @@ const fs = require('fs').promises;
const os = require("os");
const Settings = require('../modules/persistence/Settings');
const env = {version: "2.0.0-test1", app: {getPath: jest.fn().mockReturnValue("test/path")}};
-const defaultSettingsInstance = new Settings({settings: "tests/test-settings.json"}, env, "none", "none", "test/path", "", "", true, false, true, true, false, false, true, "%(title).200s-(%(height)sp%(fps).0d).%(ext)s", "%(title).200s-(%(height)sp%(fps).0d).%(ext)s", "click", "49", 8, true, "video", true, "C:\\Users\\user\\cookies.txt", false, true, false, false, true, "dark");
-const defaultSettings = "{\"outputFormat\":\"none\",\"audioOutputFormat\":\"none\",\"downloadPath\":\"test/path\",\"proxy\":\"\",\"rateLimit\":\"\",\"autoFillClipboard\":true,\"noPlaylist\":false,\"globalShortcut\":true,\"spoofUserAgent\":true,\"validateCertificate\":false,\"enableEncoding\":false,\"taskList\":true,\"nameFormat\":\"%(title).200s-(%(height)sp%(fps).0d).%(ext)s\",\"nameFormatMode\":\"%(title).200s-(%(height)sp%(fps).0d).%(ext)s\",\"sizeMode\":\"click\",\"splitMode\":\"49\",\"maxConcurrent\":8,\"defaultConcurrent\":8,\"updateBinary\":true,\"downloadType\":\"video\",\"updateApplication\":true,\"statSend\":false,\"downloadMetadata\":true,\"downloadThumbnail\":false,\"keepUnmerged\":false,\"calculateTotalSize\":true,\"theme\":\"dark\",\"version\":\"2.0.0-test1\"}"
+const defaultSettingsInstance = new Settings({settings: "tests/test-settings.json"}, env, "none", "none", "test/path", "", "", true, false, true, "spoof", false, false, true, "%(title).200s-(%(height)sp%(fps).0d).%(ext)s", "%(title).200s-(%(height)sp%(fps).0d).%(ext)s", "click", "49", 8, true, "video", true, "C:\\Users\\user\\cookies.txt", false, true, false, false, true, "dark");
+const defaultSettings = "{\"outputFormat\":\"none\",\"audioOutputFormat\":\"none\",\"downloadPath\":\"test/path\",\"proxy\":\"\",\"rateLimit\":\"\",\"autoFillClipboard\":true,\"noPlaylist\":false,\"globalShortcut\":true,\"userAgent\":\"spoof\",\"validateCertificate\":false,\"enableEncoding\":false,\"taskList\":true,\"nameFormat\":\"%(title).200s-(%(height)sp%(fps).0d).%(ext)s\",\"nameFormatMode\":\"%(title).200s-(%(height)sp%(fps).0d).%(ext)s\",\"sizeMode\":\"click\",\"splitMode\":\"49\",\"maxConcurrent\":8,\"defaultConcurrent\":8,\"updateBinary\":true,\"downloadType\":\"video\",\"updateApplication\":true,\"statSend\":false,\"downloadMetadata\":true,\"downloadThumbnail\":false,\"keepUnmerged\":false,\"calculateTotalSize\":true,\"theme\":\"dark\",\"version\":\"2.0.0-test1\"}"
describe('Load settings from file', () => {
beforeEach(() => {
diff --git a/tests/test-settings.json b/tests/test-settings.json
index 09c39c33..983e39cb 100644
--- a/tests/test-settings.json
+++ b/tests/test-settings.json
@@ -1 +1 @@
-{"outputFormat":"none","audioOutputFormat":"none","downloadPath": "test/path","proxy": "","rateLimit": "","autoFillClipboard":true,"noPlaylist": false,"globalShortcut":true,"spoofUserAgent":true,"validateCertificate": false,"enableEncoding": false,"taskList":true,"nameFormat":"%(title).200s-(%(height)sp%(fps).0d).%(ext)s","nameFormatMode":"%(title).200s-(%(height)sp%(fps).0d).%(ext)s","sizeMode":"click","splitMode":"49","maxConcurrent":8,"defaultConcurrent":8,"updateBinary":true,"downloadType":"video","updateApplication":true,"cookiePath":"C:\\Users\\user\\cookies.txt","statSend":false,"downloadMetadata":true,"downloadThumbnail":false,"keepUnmerged":false,"calculateTotalSize":true,"theme": "dark","version":"2.0.0-test1"}
+{"outputFormat":"none","audioOutputFormat":"none","downloadPath": "test/path","proxy": "","rateLimit": "","autoFillClipboard":true,"noPlaylist": false,"globalShortcut":true,"userAgent":"spoof","validateCertificate": false,"enableEncoding": false,"taskList":true,"nameFormat":"%(title).200s-(%(height)sp%(fps).0d).%(ext)s","nameFormatMode":"%(title).200s-(%(height)sp%(fps).0d).%(ext)s","sizeMode":"click","splitMode":"49","maxConcurrent":8,"defaultConcurrent":8,"updateBinary":true,"downloadType":"video","updateApplication":true,"cookiePath":"C:\\Users\\user\\cookies.txt","statSend":false,"downloadMetadata":true,"downloadThumbnail":false,"keepUnmerged":false,"calculateTotalSize":true,"theme": "dark","version":"2.0.0-test1"}