commit
0f5193c700
|
@ -138,8 +138,6 @@ mail:
|
|||
# 5. Click "Server key"
|
||||
# 6. Under "APIs & auth" click "YouTube Data API" and then click "Enable API"
|
||||
youtube-v3-key: ''
|
||||
# Minutes between saving channel state to disk
|
||||
channel-save-interval: 5
|
||||
# Limit for the number of channels a user can register
|
||||
max-channels-per-user: 5
|
||||
# Limit for the number of accounts an IP address can register
|
||||
|
@ -147,6 +145,24 @@ max-accounts-per-ip: 5
|
|||
# Minimum number of seconds between guest logins from the same IP
|
||||
guest-login-delay: 60
|
||||
|
||||
# Allows you to customize the path divider. The /r/ in http://localhost/r/yourchannel
|
||||
# Acceptable characters are a-z A-Z 0-9 _ and -
|
||||
channel-path: 'r'
|
||||
# Allows you to blacklist certain channels. Users will be automatically kicked
|
||||
# upon trying to join one.
|
||||
channel-blacklist: []
|
||||
# Minutes between saving channel state to disk
|
||||
channel-save-interval: 5
|
||||
# Determines channel data storage mechanism.
|
||||
# Defaults to 'file', in which channel data is JSON stringified and saved to a file
|
||||
# in the `chandump/` folder. This is the legacy behavior of CyTube.
|
||||
# The other possible option is 'database', in which case each key-value pair of
|
||||
# channel data is stored as a row in the `channel_data` database table.
|
||||
# To migrate legacy chandump files to the database, shut down CyTube (to prevent
|
||||
# concurrent updates), then run `node lib/channel-storage/migrate.js`.
|
||||
channel-storage:
|
||||
type: 'file'
|
||||
|
||||
# Configure statistics tracking
|
||||
stats:
|
||||
# Interval (in milliseconds) between data points - default 1h
|
||||
|
@ -208,10 +224,6 @@ playlist:
|
|||
# The server must be invoked with node --expose-gc index.js for this to have any effect.
|
||||
aggressive-gc: false
|
||||
|
||||
# Allows you to blacklist certain channels. Users will be automatically kicked
|
||||
# upon trying to join one.
|
||||
channel-blacklist: []
|
||||
|
||||
# If you have ffmpeg installed, you can query metadata from raw files, allowing
|
||||
# server-synched raw file playback. This requires the following:
|
||||
# * ffmpeg must be installed on the server
|
||||
|
@ -231,16 +243,6 @@ setuid:
|
|||
# how long to wait in ms before changing uid/gid
|
||||
timeout: 15
|
||||
|
||||
# Determines channel data storage mechanism.
|
||||
# Defaults to 'file', in which channel data is JSON stringified and saved to a file
|
||||
# in the `chandump/` folder. This is the legacy behavior of CyTube.
|
||||
# The other possible option is 'database', in which case each key-value pair of
|
||||
# channel data is stored as a row in the `channel_data` database table.
|
||||
# To migrate legacy chandump files to the database, shut down CyTube (to prevent
|
||||
# concurrent updates), then run `node lib/channel-storage/migrate.js`.
|
||||
channel-storage:
|
||||
type: 'file'
|
||||
|
||||
# Allows for external services to access the system commandline
|
||||
# Useful for setups where stdin isn't available such as when using PM2
|
||||
service-socket:
|
||||
|
|
|
@ -21,4 +21,4 @@ example, for cytu.be I use:
|
|||
npm run generate-userscript CyTube http://cytu.be/r/* https://cytu.be/r/*
|
||||
```
|
||||
|
||||
This will generate `www/js/cytube-google-drive.user.js`.
|
||||
This will generate `www/js/cytube-google-drive.user.js`. If you've changed the channel path, be sure to take that into account.
|
||||
|
|
|
@ -61,6 +61,7 @@ function initPasswordResetCleanup(Server) {
|
|||
}
|
||||
|
||||
function initChannelDumper(Server) {
|
||||
const chanPath = Config.get('channel-path');
|
||||
var CHANNEL_SAVE_INTERVAL = parseInt(Config.get("channel-save-interval"))
|
||||
* 60000;
|
||||
setInterval(function () {
|
||||
|
@ -70,9 +71,9 @@ function initChannelDumper(Server) {
|
|||
return Promise.delay(wait).then(() => {
|
||||
if (!chan.dead && chan.users && chan.users.length > 0) {
|
||||
return chan.saveState().tap(() => {
|
||||
LOGGER.info(`Saved /r/${chan.name}`);
|
||||
LOGGER.info(`Saved /${chanPath}/${chan.name}`);
|
||||
}).catch(err => {
|
||||
LOGGER.error(`Failed to save /r/${chan.name}: ${err.stack}`);
|
||||
LOGGER.error(`Failed to save /${chanPath}/${chan.name}: ${err.stack}`);
|
||||
});
|
||||
}
|
||||
}).catch(error => {
|
||||
|
|
|
@ -114,6 +114,8 @@ function fixOldChandump(data) {
|
|||
}
|
||||
|
||||
function migrate(src, dest, opts) {
|
||||
const chanPath = Config.get('channel-path');
|
||||
|
||||
return src.listChannels().then(names => {
|
||||
return Promise.reduce(names, (_, name) => {
|
||||
// A long time ago there was a bug where CyTube would save a different
|
||||
|
@ -143,11 +145,11 @@ function migrate(src, dest, opts) {
|
|||
});
|
||||
return dest.save(name, data);
|
||||
}).then(() => {
|
||||
console.log(`Migrated /r/${name}`);
|
||||
console.log(`Migrated /${chanPath}/${name}`);
|
||||
}).catch(ChannelNotFoundError, err => {
|
||||
console.log(`Skipping /r/${name} (not present in the database)`);
|
||||
console.log(`Skipping /${chanPath}/${name} (not present in the database)`);
|
||||
}).catch(err => {
|
||||
console.error(`Failed to migrate /r/${name}: ${err.stack}`);
|
||||
console.error(`Failed to migrate /${chanPath}/${name}: ${err.stack}`);
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
|
|
|
@ -70,7 +70,12 @@ var defaults = {
|
|||
"from-name": "CyTube Services"
|
||||
},
|
||||
"youtube-v3-key": "",
|
||||
"channel-blacklist": [],
|
||||
"channel-path": "r",
|
||||
"channel-save-interval": 5,
|
||||
"channel-storage": {
|
||||
type: "file"
|
||||
},
|
||||
"max-channels-per-user": 5,
|
||||
"max-accounts-per-ip": 5,
|
||||
"guest-login-delay": 60,
|
||||
|
@ -102,7 +107,6 @@ var defaults = {
|
|||
"max-items": 4000,
|
||||
"update-interval": 5
|
||||
},
|
||||
"channel-blacklist": [],
|
||||
ffmpeg: {
|
||||
enabled: false,
|
||||
"ffprobe-exec": "ffprobe"
|
||||
|
@ -114,9 +118,6 @@ var defaults = {
|
|||
"user": "nobody",
|
||||
"timeout": 15
|
||||
},
|
||||
"channel-storage": {
|
||||
type: "file"
|
||||
},
|
||||
"service-socket": {
|
||||
enabled: false,
|
||||
socket: "service.sock"
|
||||
|
@ -390,6 +391,12 @@ function preprocessConfig(cfg) {
|
|||
});
|
||||
cfg["channel-blacklist"] = tbl;
|
||||
|
||||
/* Check channel path */
|
||||
if(!/^[-\w]+$/.test(cfg["channel-blacklist"])){
|
||||
LOGGER.error("Channel paths may only use the same characters as usernames and channel names.");
|
||||
process.exit(78); // sysexits.h for bad config
|
||||
}
|
||||
|
||||
if (cfg["link-domain-blacklist"].length > 0) {
|
||||
cfg["link-domain-blacklist-regex"] = new RegExp(
|
||||
cfg["link-domain-blacklist"].join("|").replace(/\./g, "\\."), "gi");
|
||||
|
|
|
@ -62,6 +62,7 @@ var Server = function () {
|
|||
self.announcement = null;
|
||||
self.infogetter = null;
|
||||
self.servers = {};
|
||||
self.chanPath = Config.get('channel-path');
|
||||
|
||||
// backend init
|
||||
var initModule;
|
||||
|
@ -264,7 +265,7 @@ Server.prototype.unloadChannel = function (chan, options) {
|
|||
|
||||
if (!options.skipSave) {
|
||||
chan.saveState().catch(error => {
|
||||
LOGGER.error(`Failed to save /r/${chan.name} for unload: ${error.stack}`);
|
||||
LOGGER.error(`Failed to save /${this.chanPath}/${chan.name} for unload: ${error.stack}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -354,9 +355,9 @@ Server.prototype.shutdown = function () {
|
|||
Promise.map(this.channels, channel => {
|
||||
try {
|
||||
return channel.saveState().tap(() => {
|
||||
LOGGER.info(`Saved /r/${channel.name}`);
|
||||
LOGGER.info(`Saved /${this.chanPath}/${channel.name}`);
|
||||
}).catch(err => {
|
||||
LOGGER.error(`Failed to save /r/${channel.name}: ${err.stack}`);
|
||||
LOGGER.error(`Failed to save /${this.chanPath}/${channel.name}: ${err.stack}`);
|
||||
});
|
||||
} catch (error) {
|
||||
LOGGER.error(`Failed to save channel: ${error.stack}`);
|
||||
|
@ -391,7 +392,7 @@ Server.prototype.handlePartitionMapChange = function () {
|
|||
});
|
||||
this.unloadChannel(channel, { skipSave: true });
|
||||
}).catch(error => {
|
||||
LOGGER.error(`Failed to unload /r/${channel.name} for ` +
|
||||
LOGGER.error(`Failed to unload /${this.chanPath}/${channel.name} for ` +
|
||||
`partition map flip: ${error.stack}`);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ function merge(locals, res) {
|
|||
loginDomain: Config.get("https.enabled") ? Config.get("https.full-address")
|
||||
: Config.get("http.full-address"),
|
||||
csrfToken: typeof res.req.csrfToken === 'function' ? res.req.csrfToken() : '',
|
||||
baseUrl: getBaseUrl(res)
|
||||
baseUrl: getBaseUrl(res),
|
||||
channelPath: Config.get("channel-path"),
|
||||
};
|
||||
if (typeof locals !== "object") {
|
||||
return _locals;
|
||||
|
|
|
@ -4,8 +4,8 @@ import { sendPug } from '../pug';
|
|||
import * as HTTPStatus from '../httpstatus';
|
||||
import { HTTPError } from '../../errors';
|
||||
|
||||
export default function initialize(app, ioConfig) {
|
||||
app.get('/r/:channel', (req, res) => {
|
||||
export default function initialize(app, ioConfig, chanPath) {
|
||||
app.get(`/${chanPath}/:channel`, (req, res) => {
|
||||
if (!req.params.channel || !CyTubeUtil.isValidChannelName(req.params.channel)) {
|
||||
throw new HTTPError(`"${sanitizeText(req.params.channel)}" is not a valid ` +
|
||||
'channel name.', { status: HTTPStatus.NOT_FOUND });
|
||||
|
|
|
@ -132,6 +132,8 @@ module.exports = {
|
|||
* Initializes webserver callbacks
|
||||
*/
|
||||
init: function (app, webConfig, ioConfig, clusterClient, channelIndex, session) {
|
||||
const chanPath = Config.get('channel-path');
|
||||
|
||||
app.use((req, res, next) => {
|
||||
counters.add("http:request", 1);
|
||||
next();
|
||||
|
@ -147,7 +149,7 @@ module.exports = {
|
|||
}
|
||||
app.use(cookieParser(webConfig.getCookieSecret()));
|
||||
app.use(csrf.init(webConfig.getCookieDomain()));
|
||||
app.use('/r/:channel', require('./middleware/ipsessioncookie').ipSessionCookieMiddleware);
|
||||
app.use(`/${chanPath}/:channel`, require('./middleware/ipsessioncookie').ipSessionCookieMiddleware);
|
||||
initializeLog(app);
|
||||
require('./middleware/authorize')(app, session);
|
||||
|
||||
|
@ -176,7 +178,7 @@ module.exports = {
|
|||
LOGGER.info('Enabled express-minify for CSS and JS');
|
||||
}
|
||||
|
||||
require('./routes/channel')(app, ioConfig);
|
||||
require('./routes/channel')(app, ioConfig, chanPath);
|
||||
require('./routes/index')(app, channelIndex, webConfig.getMaxIndexEntries());
|
||||
app.get('/sioconfig(.json)?', handleLegacySocketConfig);
|
||||
require('./routes/socketconfig')(app, clusterClient);
|
||||
|
|
|
@ -44,7 +44,7 @@ html(lang="en")
|
|||
input(type="hidden", name="name", value=c.name)
|
||||
button.btn.btn-xs.btn-danger(type="submit") Delete
|
||||
span.glyphicon.glyphicon-trash
|
||||
a(href="/r/"+c.name, style="margin-left: 5px")= c.name
|
||||
a(href=`/${channelPath}/${c.name}`, style="margin-left: 5px")= c.name
|
||||
.col-lg-6.col-md-6
|
||||
h3 Register a new channel
|
||||
if newChannelError
|
||||
|
@ -57,7 +57,7 @@ html(lang="en")
|
|||
.form-group
|
||||
label.control-label(for="channelname") Channel URL
|
||||
.input-group
|
||||
span.input-group-addon #{baseUrl}/r/
|
||||
span.input-group-addon #{baseUrl}/#{channelPath}/
|
||||
input#channelname.form-control(type="text", name="name", maxlength="30", onkeyup="checkChannel()")
|
||||
p#validate_channel.text-danger.pull-right
|
||||
button#register.btn.btn-primary.btn-block(type="submit") Register
|
||||
|
|
|
@ -11,7 +11,7 @@ html(lang="en")
|
|||
include nav
|
||||
+navheader()
|
||||
#nav-collapsible.collapse.navbar-collapse
|
||||
- var cname = "/r/" + channelName
|
||||
- var cname = `/${channelPath}/${channelName}`
|
||||
ul.nav.navbar-nav
|
||||
+navdefaultlinks(cname)
|
||||
li: a(href="javascript:void(0)", onclick="javascript:showUserOptions()") Options
|
||||
|
|
|
@ -86,7 +86,7 @@ mixin adminoptions
|
|||
#cs-adminoptions.tab-pane
|
||||
h4 Admin-Only Settings
|
||||
form.form-horizontal(action="javascript:void(0)")
|
||||
- var defname = "CyTube - /r/" + channelName
|
||||
- var defname = `CyTube - /${channelPath}/${channelName}`
|
||||
+textbox-auto("cs-pagetitle", "Page title", defname)
|
||||
+textbox-auto("cs-password", "Password", "leave blank to disable")
|
||||
+textbox-auto("cs-externalcss", "External CSS", "Stylesheet URL")
|
||||
|
|
|
@ -11,8 +11,16 @@ mixin head()
|
|||
link(href="/css/cytube.css", rel="stylesheet")
|
||||
link(id="usertheme", href=DEFAULT_THEME, rel="stylesheet")
|
||||
|
||||
script(type="text/javascript").
|
||||
var DEFAULT_THEME = '#{DEFAULT_THEME}';
|
||||
if channelName
|
||||
script(type="text/javascript").
|
||||
var DEFAULT_THEME = '#{DEFAULT_THEME}';
|
||||
var CHANNELPATH = '#{channelPath}';
|
||||
var CHANNELNAME = '#{channelName}';
|
||||
else
|
||||
script(type="text/javascript").
|
||||
var DEFAULT_THEME = '#{DEFAULT_THEME}';
|
||||
var CHANNELPATH = '#{channelPath}';
|
||||
|
||||
script(src="/js/theme.js")
|
||||
//[if lt IE 9]
|
||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
||||
|
|
|
@ -25,7 +25,7 @@ html(lang="en")
|
|||
tbody
|
||||
each chan in channels
|
||||
tr
|
||||
td: a(href="/r/"+chan.name) #{chan.pagetitle} (#{chan.name})
|
||||
td: a(href=`/${channelPath}/${chan.name}`) #{chan.pagetitle} (#{chan.name})
|
||||
td= chan.usercount
|
||||
td= chan.mediatitle
|
||||
.col-lg-3.col-md-3
|
||||
|
@ -37,6 +37,6 @@ html(lang="en")
|
|||
script(type="text/javascript").
|
||||
$("#channelname").keydown(function (ev) {
|
||||
if (ev.keyCode === 13) {
|
||||
location.href = "/r/" + $("#channelname").val();
|
||||
location.href = "/#{channelPath}/" + $("#channelname").val();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -453,8 +453,8 @@ console.log(channels[0]);
|
|||
channels.forEach(function (c) {
|
||||
var tr = $("<tr/>").appendTo(tbl);
|
||||
var name = $("<td/>").appendTo(tr);
|
||||
$("<a/>").attr("href", "/r/" + c.name)
|
||||
.text(c.pagetitle + " (/r/" + c.name + ")")
|
||||
$("<a/>").attr("href", `/${CHANNELPATH}/${c.name}`)
|
||||
.text(c.pagetitle + ` (/${CHANNELPATH}/${c.name})`)
|
||||
.appendTo(name);
|
||||
var usercount = $("<td/>").text(c.usercount).appendTo(tr);
|
||||
count += c.usercount;
|
||||
|
@ -475,7 +475,7 @@ console.log(channels[0]);
|
|||
.attr("title", "Unload")
|
||||
.appendTo(controlInner)
|
||||
.click(function () {
|
||||
if (confirm("Are you sure you want to unload /r/" + c.name + "?")) {
|
||||
if (confirm(`Are you sure you want to unload /${CHANNELPATH}/${c.name}?`)) {
|
||||
socket.emit("acp-force-unload", {
|
||||
name: c.name
|
||||
});
|
||||
|
|
|
@ -425,23 +425,6 @@ Callbacks = {
|
|||
|
||||
if (!CLIENT.guest) {
|
||||
socket.emit("initUserPLCallbacks");
|
||||
if ($("#loginform").length === 0) {
|
||||
return;
|
||||
}
|
||||
var logoutform = $("<p/>").attr("id", "logoutform")
|
||||
.addClass("navbar-text pull-right")
|
||||
.insertAfter($("#loginform"));
|
||||
|
||||
$("<span/>").attr("id", "welcome").text("Welcome, " + CLIENT.name)
|
||||
.appendTo(logoutform);
|
||||
$("<span/>").html(" · ").appendTo(logoutform);
|
||||
var domain = $("#loginform").attr("action").replace("/login", "");
|
||||
$("<a/>").attr("id", "logout")
|
||||
.attr("href", domain + "/logout?redirect=/r/" + CHANNEL.name)
|
||||
.text("Logout")
|
||||
.appendTo(logoutform);
|
||||
|
||||
$("#loginform").remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ var CHANNEL = {
|
|||
css: "",
|
||||
js: "",
|
||||
motd: "",
|
||||
name: false,
|
||||
name: CHANNELNAME,
|
||||
usercount: 0,
|
||||
emotes: []
|
||||
};
|
||||
|
|
11
www/js/ui.js
11
www/js/ui.js
|
@ -615,17 +615,6 @@ $("#shuffleplaylist").click(function() {
|
|||
}
|
||||
});
|
||||
|
||||
/* load channel */
|
||||
|
||||
var loc = document.location+"";
|
||||
var m = loc.match(/\/r\/([a-zA-Z0-9-_]+)/);
|
||||
if(m) {
|
||||
CHANNEL.name = m[1];
|
||||
if (CHANNEL.name.indexOf("#") !== -1) {
|
||||
CHANNEL.name = CHANNEL.name.substring(0, CHANNEL.name.indexOf("#"));
|
||||
}
|
||||
}
|
||||
|
||||
/* channel ranks stuff */
|
||||
function chanrankSubmit(rank) {
|
||||
var name = $("#cs-chanranks-name").val();
|
||||
|
|
Loading…
Reference in a new issue