Compare commits
7 commits
postgreSQL
...
banned-cha
Author | SHA1 | Date | |
---|---|---|---|
c3509b9639 | |||
7cf1593c7c | |||
c686100008 | |||
5985c8d280 | |||
d61af3f9d5 | |||
387faf6d75 | |||
d4727533b1 |
|
@ -1,6 +0,0 @@
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_size = 4
|
|
||||||
indent_style = space
|
|
|
@ -128,8 +128,6 @@ max-channels-per-user: 5
|
||||||
max-accounts-per-ip: 5
|
max-accounts-per-ip: 5
|
||||||
# Minimum number of seconds between guest logins from the same IP
|
# Minimum number of seconds between guest logins from the same IP
|
||||||
guest-login-delay: 60
|
guest-login-delay: 60
|
||||||
# Maximum character length of a chat message, capped at 1000 characters
|
|
||||||
max-chat-message-length: 320
|
|
||||||
|
|
||||||
# Allows you to customize the path divider. The /r/ in http://localhost/r/yourchannel
|
# Allows you to customize the path divider. The /r/ in http://localhost/r/yourchannel
|
||||||
# Acceptable characters are a-z A-Z 0-9 _ and -
|
# Acceptable characters are a-z A-Z 0-9 _ and -
|
||||||
|
|
|
@ -110,25 +110,6 @@ describe('KickbanModule', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects if the username is invalid', done => {
|
|
||||||
mockUser.socket.emit = (frame, obj) => {
|
|
||||||
if (frame === 'errorMsg') {
|
|
||||||
assert.strictEqual(
|
|
||||||
obj.msg,
|
|
||||||
'Invalid username'
|
|
||||||
);
|
|
||||||
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
kickban.handleCmdBan(
|
|
||||||
mockUser,
|
|
||||||
'/ban test_user<>%$# because reasons',
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rejects if the user does not have ban permission', done => {
|
it('rejects if the user does not have ban permission', done => {
|
||||||
mockUser.socket.emit = (frame, obj) => {
|
mockUser.socket.emit = (frame, obj) => {
|
||||||
if (frame === 'errorMsg') {
|
if (frame === 'errorMsg') {
|
||||||
|
|
11024
package-lock.json
generated
11024
package-lock.json
generated
File diff suppressed because it is too large
Load diff
17
package.json
17
package.json
|
@ -2,17 +2,17 @@
|
||||||
"author": "Calvin Montgomery",
|
"author": "Calvin Montgomery",
|
||||||
"name": "CyTube",
|
"name": "CyTube",
|
||||||
"description": "Online media synchronizer and chat",
|
"description": "Online media synchronizer and chat",
|
||||||
"version": "3.86.0",
|
"version": "3.84.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "http://github.com/calzoneman/sync"
|
"url": "http://github.com/calzoneman/sync"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calzoneman/jsli": "^2.0.1",
|
"@calzoneman/jsli": "^2.0.1",
|
||||||
"@cytube/mediaquery": "github:CyTube/mediaquery#564d0c4615e80f72722b0f68ac81f837a4c5fc81",
|
"@cytube/mediaquery": "github:CyTube/mediaquery#c1dcf792cd6e9977c04c1e96f23315dad5e3294d",
|
||||||
"bcrypt": "^5.0.1",
|
"bcrypt": "^5.0.1",
|
||||||
"bluebird": "^3.7.2",
|
"bluebird": "^3.7.2",
|
||||||
"body-parser": "^1.20.1",
|
"body-parser": "^1.19.0",
|
||||||
"cheerio": "^1.0.0-rc.10",
|
"cheerio": "^1.0.0-rc.10",
|
||||||
"clone": "^2.1.2",
|
"clone": "^2.1.2",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
|
@ -20,22 +20,21 @@
|
||||||
"create-error": "^0.3.1",
|
"create-error": "^0.3.1",
|
||||||
"csrf": "^3.1.0",
|
"csrf": "^3.1.0",
|
||||||
"cytubefilters": "github:calzoneman/cytubefilters#c67b2dab2dc5cc5ed11018819f71273d0f8a1bf5",
|
"cytubefilters": "github:calzoneman/cytubefilters#c67b2dab2dc5cc5ed11018819f71273d0f8a1bf5",
|
||||||
"express": "^4.18.2",
|
"express": "^4.17.1",
|
||||||
"express-minify": "^1.0.0",
|
"express-minify": "^1.0.0",
|
||||||
"json-typecheck": "^0.1.3",
|
"json-typecheck": "^0.1.3",
|
||||||
"knex": "^2.4.0",
|
"knex": "^0.95.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
"nodemailer": "^6.6.1",
|
"nodemailer": "^6.6.1",
|
||||||
"pg": "^8.11.3",
|
|
||||||
"pg-native": "^3.0.1",
|
|
||||||
"prom-client": "^13.1.0",
|
"prom-client": "^13.1.0",
|
||||||
"proxy-addr": "^2.0.6",
|
"proxy-addr": "^2.0.6",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"redis": "^3.1.1",
|
"redis": "^3.1.1",
|
||||||
"sanitize-html": "^2.7.0",
|
"sanitize-html": "^2.7.0",
|
||||||
"serve-static": "^1.15.0",
|
"serve-static": "^1.14.1",
|
||||||
"socket.io": "^4.5.4",
|
"socket.io": "^4.5.0",
|
||||||
"source-map-support": "^0.5.19",
|
"source-map-support": "^0.5.19",
|
||||||
"toml": "^3.0.0",
|
"toml": "^3.0.0",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
|
|
|
@ -15,19 +15,8 @@ window.CustomEmbedPlayer = class CustomEmbedPlayer extends EmbedPlayer
|
||||||
return
|
return
|
||||||
|
|
||||||
embedSrc = data.meta.embed.src
|
embedSrc = data.meta.embed.src
|
||||||
|
link = "<a href=\"#{embedSrc}\" target=\"_blank\"><strong>#{embedSrc}</strong></a>"
|
||||||
link = document.createElement('a')
|
alert = makeAlert('Untrusted Content', CUSTOM_EMBED_WARNING.replace('%link%', link),
|
||||||
link.href = embedSrc
|
|
||||||
link.target = '_blank'
|
|
||||||
link.rel = 'noopener noreferer'
|
|
||||||
|
|
||||||
strong = document.createElement('strong')
|
|
||||||
strong.textContent = embedSrc
|
|
||||||
link.appendChild(strong)
|
|
||||||
|
|
||||||
# TODO: Ideally makeAlert() would allow optionally providing a DOM
|
|
||||||
# element instead of requiring HTML text
|
|
||||||
alert = makeAlert('Untrusted Content', CUSTOM_EMBED_WARNING.replace('%link%', link.outerHTML),
|
|
||||||
'alert-warning')
|
'alert-warning')
|
||||||
.removeClass('col-md-12')
|
.removeClass('col-md-12')
|
||||||
$('<button/>').addClass('btn btn-default')
|
$('<button/>').addClass('btn btn-default')
|
||||||
|
|
|
@ -162,7 +162,7 @@ ChatModule.prototype.handleChatMsg = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.msg = data.msg.substring(0, Config.get("max-chat-message-length"));
|
data.msg = data.msg.substring(0, 320);
|
||||||
|
|
||||||
// Restrict new accounts/IPs from chatting and posting links
|
// Restrict new accounts/IPs from chatting and posting links
|
||||||
if (this.restrictNewAccount(user, data)) {
|
if (this.restrictNewAccount(user, data)) {
|
||||||
|
@ -248,7 +248,7 @@ ChatModule.prototype.handlePm = function (user, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data.msg = data.msg.substring(0, Config.get("max-chat-message-length"));
|
data.msg = data.msg.substring(0, 320);
|
||||||
var to = null;
|
var to = null;
|
||||||
for (var i = 0; i < this.channel.users.length; i++) {
|
for (var i = 0; i < this.channel.users.length; i++) {
|
||||||
if (this.channel.users[i].getLowerName() === data.to) {
|
if (this.channel.users[i].getLowerName() === data.to) {
|
||||||
|
|
|
@ -4,7 +4,6 @@ var Flags = require("../flags");
|
||||||
var util = require("../utilities");
|
var util = require("../utilities");
|
||||||
var Account = require("../account");
|
var Account = require("../account");
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
const XSS = require("../xss");
|
|
||||||
|
|
||||||
const dbIsNameBanned = Promise.promisify(db.channels.isNameBanned);
|
const dbIsNameBanned = Promise.promisify(db.channels.isNameBanned);
|
||||||
const dbIsIPBanned = Promise.promisify(db.channels.isIPBanned);
|
const dbIsIPBanned = Promise.promisify(db.channels.isIPBanned);
|
||||||
|
@ -262,6 +261,7 @@ KickBanModule.prototype.handleCmdIPBan = function (user, msg, _meta) {
|
||||||
chan.refCounter.ref("KickBanModule::handleCmdIPBan");
|
chan.refCounter.ref("KickBanModule::handleCmdIPBan");
|
||||||
|
|
||||||
this.banAll(user, name, range, reason).catch(error => {
|
this.banAll(user, name, range, reason).catch(error => {
|
||||||
|
//console.log('!!!', error.stack);
|
||||||
const message = error.message || error;
|
const message = error.message || error;
|
||||||
user.socket.emit("errorMsg", { msg: message });
|
user.socket.emit("errorMsg", { msg: message });
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
@ -276,10 +276,6 @@ KickBanModule.prototype.checkChannelAlive = function checkChannelAlive() {
|
||||||
};
|
};
|
||||||
|
|
||||||
KickBanModule.prototype.banName = async function banName(actor, name, reason) {
|
KickBanModule.prototype.banName = async function banName(actor, name, reason) {
|
||||||
if (!util.isValidUserName(name)) {
|
|
||||||
throw new Error("Invalid username");
|
|
||||||
}
|
|
||||||
|
|
||||||
reason = reason.substring(0, 255);
|
reason = reason.substring(0, 255);
|
||||||
|
|
||||||
var chan = this.channel;
|
var chan = this.channel;
|
||||||
|
@ -327,9 +323,6 @@ KickBanModule.prototype.banName = async function banName(actor, name, reason) {
|
||||||
};
|
};
|
||||||
|
|
||||||
KickBanModule.prototype.banIP = async function banIP(actor, ip, name, reason) {
|
KickBanModule.prototype.banIP = async function banIP(actor, ip, name, reason) {
|
||||||
if (!util.isValidUserName(name)) {
|
|
||||||
throw new Error("Invalid username");
|
|
||||||
}
|
|
||||||
reason = reason.substring(0, 255);
|
reason = reason.substring(0, 255);
|
||||||
var masked = util.cloakIP(ip);
|
var masked = util.cloakIP(ip);
|
||||||
|
|
||||||
|
@ -452,9 +445,8 @@ KickBanModule.prototype.handleUnban = function (user, data) {
|
||||||
self.channel.logger.log("[mod] " + user.getName() + " unbanned " + data.name);
|
self.channel.logger.log("[mod] " + user.getName() + " unbanned " + data.name);
|
||||||
if (self.channel.modules.chat) {
|
if (self.channel.modules.chat) {
|
||||||
var banperm = self.channel.modules.permissions.permissions.ban;
|
var banperm = self.channel.modules.permissions.permissions.ban;
|
||||||
// TODO: quick fix, shouldn't trust name from unban frame.
|
|
||||||
self.channel.modules.chat.sendModMessage(
|
self.channel.modules.chat.sendModMessage(
|
||||||
user.getName() + " unbanned " + XSS.sanitizeText(data.name),
|
user.getName() + " unbanned " + data.name,
|
||||||
banperm
|
banperm
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,7 @@ import { CaptchaConfig } from './configuration/captchaconfig';
|
||||||
const LOGGER = require('@calzoneman/jsli')('config');
|
const LOGGER = require('@calzoneman/jsli')('config');
|
||||||
|
|
||||||
var defaults = {
|
var defaults = {
|
||||||
database: {
|
mysql: {
|
||||||
client: "mysql",
|
|
||||||
server: "localhost",
|
server: "localhost",
|
||||||
port: 3306,
|
port: 3306,
|
||||||
database: "cytube3",
|
database: "cytube3",
|
||||||
|
@ -72,7 +71,6 @@ var defaults = {
|
||||||
"max-channels-per-user": 5,
|
"max-channels-per-user": 5,
|
||||||
"max-accounts-per-ip": 5,
|
"max-accounts-per-ip": 5,
|
||||||
"guest-login-delay": 60,
|
"guest-login-delay": 60,
|
||||||
"max-chat-message-length": 320,
|
|
||||||
aliases: {
|
aliases: {
|
||||||
"purge-interval": 3600000,
|
"purge-interval": 3600000,
|
||||||
"max-age": 2592000000
|
"max-age": 2592000000
|
||||||
|
@ -429,11 +427,6 @@ function preprocessConfig(cfg) {
|
||||||
cfg['channel-storage'] = { type: undefined };
|
cfg['channel-storage'] = { type: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg["max-chat-message-length"] > 1000) {
|
|
||||||
LOGGER.warn("Max chat message length was greater than 1000. Setting to 1000.");
|
|
||||||
cfg["max-chat-message-length"] = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,7 @@ export function validate(data) {
|
||||||
validateURL(data.thumbnail);
|
validateURL(data.thumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateSources(data.sources);
|
validateSources(data.sources, data);
|
||||||
validateAudioTracks(data.audioTracks);
|
validateAudioTracks(data.audioTracks);
|
||||||
validateTextTracks(data.textTracks);
|
validateTextTracks(data.textTracks);
|
||||||
/*
|
/*
|
||||||
|
@ -182,7 +182,7 @@ export function validate(data) {
|
||||||
validateFonts(data.fonts);
|
validateFonts(data.fonts);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateSources(sources) {
|
function validateSources(sources, data) {
|
||||||
if (!Array.isArray(sources))
|
if (!Array.isArray(sources))
|
||||||
throw new ValidationError('sources must be a list');
|
throw new ValidationError('sources must be a list');
|
||||||
if (sources.length === 0)
|
if (sources.length === 0)
|
||||||
|
|
|
@ -30,19 +30,19 @@ class Database {
|
||||||
constructor(knexConfig = null) {
|
constructor(knexConfig = null) {
|
||||||
if (knexConfig === null) {
|
if (knexConfig === null) {
|
||||||
knexConfig = {
|
knexConfig = {
|
||||||
client: Config.get('database.client'),
|
client: 'mysql',
|
||||||
connection: {
|
connection: {
|
||||||
host: Config.get('database.server'),
|
host: Config.get('mysql.server'),
|
||||||
port: Config.get('database.port'),
|
port: Config.get('mysql.port'),
|
||||||
user: Config.get('database.user'),
|
user: Config.get('mysql.user'),
|
||||||
password: Config.get('database.password'),
|
password: Config.get('mysql.password'),
|
||||||
database: Config.get('database.database'),
|
database: Config.get('mysql.database'),
|
||||||
multipleStatements: true, // Legacy thing
|
multipleStatements: true, // Legacy thing
|
||||||
charset: 'utf8mb4'
|
charset: 'utf8mb4'
|
||||||
},
|
},
|
||||||
pool: {
|
pool: {
|
||||||
min: Config.get('database.pool-size'),
|
min: Config.get('mysql.pool-size'),
|
||||||
max: Config.get('database.pool-size')
|
max: Config.get('mysql.pool-size')
|
||||||
},
|
},
|
||||||
debug: !!process.env.KNEX_DEBUG
|
debug: !!process.env.KNEX_DEBUG
|
||||||
};
|
};
|
||||||
|
@ -73,8 +73,6 @@ module.exports.init = function (newDB) {
|
||||||
} else {
|
} else {
|
||||||
db = new Database();
|
db = new Database();
|
||||||
}
|
}
|
||||||
// FIXME Initial database connection failed: error: select 1 from dual
|
|
||||||
// relation "dual" does not exist
|
|
||||||
db.knex.raw('select 1 from dual')
|
db.knex.raw('select 1 from dual')
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
LOGGER.error('Initial database connection failed: %s', error.stack);
|
LOGGER.error('Initial database connection failed: %s', error.stack);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import CyTubeUtil from '../../utilities';
|
import CyTubeUtil from '../../utilities';
|
||||||
import Config from '../../config';
|
|
||||||
import { sanitizeText } from '../../xss';
|
import { sanitizeText } from '../../xss';
|
||||||
import { sendPug } from '../pug';
|
import { sendPug } from '../pug';
|
||||||
import * as HTTPStatus from '../httpstatus';
|
import * as HTTPStatus from '../httpstatus';
|
||||||
|
@ -28,8 +27,7 @@ export default function initialize(app, ioConfig, chanPath, getBannedChannel) {
|
||||||
|
|
||||||
sendPug(res, 'channel', {
|
sendPug(res, 'channel', {
|
||||||
channelName: req.params.channel,
|
channelName: req.params.channel,
|
||||||
sioSource: `${socketBaseURL}/socket.io/socket.io.js`,
|
sioSource: `${socketBaseURL}/socket.io/socket.io.js`
|
||||||
maxMsgLen: Config.get("max-chat-message-length")
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ html(lang="en")
|
||||||
#userlist
|
#userlist
|
||||||
#messagebuffer.linewrap
|
#messagebuffer.linewrap
|
||||||
form(action="javascript:void(0)")
|
form(action="javascript:void(0)")
|
||||||
input#chatline.form-control(type="text", maxlength=maxMsgLen, style="display: none")
|
input#chatline.form-control(type="text", maxlength="320", style="display: none")
|
||||||
#guestlogin.input-group
|
#guestlogin.input-group
|
||||||
span.input-group-addon Guest login
|
span.input-group-addon Guest login
|
||||||
input#guestname.form-control(type="text", placeholder="Name")
|
input#guestname.form-control(type="text", placeholder="Name")
|
||||||
|
|
|
@ -1,55 +1,4 @@
|
||||||
/*eslint no-unused-vars: "off"*/
|
/*eslint no-unused-vars: "off"*/
|
||||||
|
|
||||||
(function() {
|
|
||||||
/**
|
|
||||||
* Test whether the browser supports nullish-coalescing operator.
|
|
||||||
*
|
|
||||||
* Users with old browsers will probably fail to load the client correctly
|
|
||||||
* because parsing this operator in older browsers results in a SyntaxError
|
|
||||||
* that aborts compilation of the entire script (not just an exception where
|
|
||||||
* it is used). In particular, as of 2023-01-28, Utherverse ships with
|
|
||||||
* a rather old browser version (Chrome 76) and several users have reported
|
|
||||||
* it not working.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
new Function('x?.y');
|
|
||||||
} catch (e) {
|
|
||||||
if (e.name === 'SyntaxError') {
|
|
||||||
/**
|
|
||||||
* If we're at this point, we can't be sure what scripts have
|
|
||||||
* actually loaded, so construct the error alert the old
|
|
||||||
* fashioned way.
|
|
||||||
*/
|
|
||||||
var wrap = document.createElement('div');
|
|
||||||
wrap.className = 'col-md-12';
|
|
||||||
var al = document.createElement('div');
|
|
||||||
al.className = 'alert alert-danger';
|
|
||||||
var title = document.createElement('strong');
|
|
||||||
title.textContent = 'Unsupported Browser';
|
|
||||||
var msg = document.createElement('p');
|
|
||||||
msg.textContent = 'It looks like your browser does not support ' +
|
|
||||||
'the required JavaScript features to run ' +
|
|
||||||
'CyTube. This is usually caused by ' +
|
|
||||||
'using an outdated browser version. Please '+
|
|
||||||
'check if an update is available. Your ' +
|
|
||||||
'browser version is reported as:';
|
|
||||||
var version = document.createElement('tt');
|
|
||||||
version.textContent = navigator.userAgent;
|
|
||||||
|
|
||||||
wrap.appendChild(al);
|
|
||||||
al.appendChild(title);
|
|
||||||
al.appendChild(msg);
|
|
||||||
al.appendChild(document.createElement('br'));
|
|
||||||
al.appendChild(version);
|
|
||||||
document.getElementById('motdrow').appendChild(wrap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error probing for feature support:', e.stack);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
var CL_VERSION = 3.0;
|
var CL_VERSION = 3.0;
|
||||||
var GS_VERSION = 1.7; // Google Drive Userscript
|
var GS_VERSION = 1.7; // Google Drive Userscript
|
||||||
|
|
||||||
|
|
|
@ -1287,11 +1287,6 @@ function playlistMove(from, after, cb) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkYP(id) {
|
|
||||||
if (!/^(PL[a-zA-Z0-9_-]{32}|PL[A-F0-9]{16}|OLA[a-zA-Z0-9_-]{38})$/.test(id)) {
|
|
||||||
throw new Error('Invalid YouTube Playlist ID. Note that only regular user-created playlists are supported.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseMediaLink(url) {
|
function parseMediaLink(url) {
|
||||||
function parseShortCode(url){
|
function parseShortCode(url){
|
||||||
|
@ -1306,9 +1301,6 @@ function parseMediaLink(url) {
|
||||||
case 'fi':
|
case 'fi':
|
||||||
case 'cm':
|
case 'cm':
|
||||||
return { type, id };
|
return { type, id };
|
||||||
case 'yp':
|
|
||||||
checkYP(id);
|
|
||||||
return { type, id };
|
|
||||||
// Generic for the rest.
|
// Generic for the rest.
|
||||||
default:
|
default:
|
||||||
return { type, id: id.match(/([^\?&#]+)/)[1] };
|
return { type, id: id.match(/([^\?&#]+)/)[1] };
|
||||||
|
@ -1364,7 +1356,6 @@ function parseMediaLink(url) {
|
||||||
return { type: 'yt', id: data.pathname.slice(8,19) }
|
return { type: 'yt', id: data.pathname.slice(8,19) }
|
||||||
}
|
}
|
||||||
if(data.pathname == '/playlist'){
|
if(data.pathname == '/playlist'){
|
||||||
checkYP(data.searchParams.get('list'));
|
|
||||||
return { type: 'yp', id: data.searchParams.get('list') }
|
return { type: 'yp', id: data.searchParams.get('list') }
|
||||||
}
|
}
|
||||||
case 'youtu.be':
|
case 'youtu.be':
|
||||||
|
|
Loading…
Reference in a new issue