mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-29 10:06:13 +01:00
Sound system improvements
- Fix sound ACP uploads - Display soundpack names with sound files - Soundpacks can have sounds with identical names - Link sounds during build step - Generate map of sound name to file name during build step - Change how soundpacks work. It's now done via a field in plugin.json
This commit is contained in:
@@ -58,7 +58,7 @@
|
|||||||
"nodebb-plugin-emoji-one": "1.1.5",
|
"nodebb-plugin-emoji-one": "1.1.5",
|
||||||
"nodebb-plugin-markdown": "7.1.0",
|
"nodebb-plugin-markdown": "7.1.0",
|
||||||
"nodebb-plugin-mentions": "1.1.3",
|
"nodebb-plugin-mentions": "1.1.3",
|
||||||
"nodebb-plugin-soundpack-default": "0.1.6",
|
"nodebb-plugin-soundpack-default": "1.0.0",
|
||||||
"nodebb-plugin-spam-be-gone": "0.4.10",
|
"nodebb-plugin-spam-be-gone": "0.4.10",
|
||||||
"nodebb-rewards-essentials": "0.0.9",
|
"nodebb-rewards-essentials": "0.0.9",
|
||||||
"nodebb-theme-lavender": "3.0.15",
|
"nodebb-theme-lavender": "3.0.15",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/* global app, define, socket */
|
/* global app, define, socket */
|
||||||
|
|
||||||
define('admin/general/sounds', ['sounds', 'settings'], function (Sounds, Settings) {
|
define('admin/general/sounds', ['sounds', 'settings', 'admin/settings'], function (Sounds, Settings, AdminSettings) {
|
||||||
var SoundsAdmin = {};
|
var SoundsAdmin = {};
|
||||||
|
|
||||||
SoundsAdmin.init = function () {
|
SoundsAdmin.init = function () {
|
||||||
@@ -9,8 +9,8 @@ define('admin/general/sounds', ['sounds', 'settings'], function (Sounds, Setting
|
|||||||
$('.sounds').find('button[data-action="play"]').on('click', function (e) {
|
$('.sounds').find('button[data-action="play"]').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var fileName = $(this).parent().parent().find('select').val();
|
var soundName = $(this).parent().parent().find('select').val();
|
||||||
Sounds.playFile(fileName);
|
Sounds.playSound(soundName);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load Form Values
|
// Load Form Values
|
||||||
@@ -26,6 +26,8 @@ define('admin/general/sounds', ['sounds', 'settings'], function (Sounds, Setting
|
|||||||
app.alertSuccess('[[admin/general/sounds:saved]]');
|
app.alertSuccess('[[admin/general/sounds:saved]]');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AdminSettings.prepare();
|
||||||
};
|
};
|
||||||
|
|
||||||
return SoundsAdmin;
|
return SoundsAdmin;
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds'
|
|||||||
$('.account').find('button[data-action="play"]').on('click', function (e) {
|
$('.account').find('button[data-action="play"]').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var fileName = $(this).parent().parent().find('select').val();
|
var soundName = $(this).parent().parent().find('select').val();
|
||||||
sounds.playFile(fileName);
|
sounds.playSound(soundName);
|
||||||
});
|
});
|
||||||
|
|
||||||
toggleCustomRoute();
|
toggleCustomRoute();
|
||||||
@@ -89,7 +89,7 @@ define('forum/account/settings', ['forum/account/header', 'components', 'sounds'
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sounds.reloadMapping();
|
sounds.loadMap();
|
||||||
|
|
||||||
if (requireReload && parseInt(app.user.uid, 10) === parseInt(ajaxify.data.theirid, 10)) {
|
if (requireReload && parseInt(app.user.uid, 10) === parseInt(ajaxify.data.theirid, 10)) {
|
||||||
app.alert({
|
app.alert({
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ define('chat', [
|
|||||||
|
|
||||||
if (!isSelf && (!modal.is(':visible') || !app.isFocused)) {
|
if (!isSelf && (!modal.is(':visible') || !app.isFocused)) {
|
||||||
app.alternatingTitle('[[modules:chat.user_has_messaged_you, ' + username + ']]');
|
app.alternatingTitle('[[modules:chat.user_has_messaged_you, ' + username + ']]');
|
||||||
sounds.play('chat-incoming');
|
sounds.play('chat-incoming', 'chat.incoming:' + data.message.mid);
|
||||||
|
|
||||||
taskbar.push('chat', modal.attr('UUID'), {
|
taskbar.push('chat', modal.attr('UUID'), {
|
||||||
title: username,
|
title: username,
|
||||||
@@ -89,7 +89,7 @@ define('chat', [
|
|||||||
module.toggleNew(modal.attr('UUID'), !isSelf, true);
|
module.toggleNew(modal.attr('UUID'), !isSelf, true);
|
||||||
if (!isSelf) {
|
if (!isSelf) {
|
||||||
app.alternatingTitle('[[modules:chat.user_has_messaged_you, ' + username + ']]');
|
app.alternatingTitle('[[modules:chat.user_has_messaged_you, ' + username + ']]');
|
||||||
sounds.play('chat-incoming');
|
sounds.play('chat-incoming', 'chat.incoming:' + data.message.mid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/* globals define, socket, app, ajaxify, templates, Tinycon*/
|
/* globals define, socket, app, ajaxify, templates, Tinycon*/
|
||||||
|
|
||||||
define('notifications', ['sounds', 'translator', 'components'], function (sound, translator, components) {
|
define('notifications', ['sounds', 'translator', 'components'], function (sounds, translator, components) {
|
||||||
var Notifications = {};
|
var Notifications = {};
|
||||||
|
|
||||||
var unreadNotifs = {};
|
var unreadNotifs = {};
|
||||||
@@ -105,7 +105,7 @@ define('notifications', ['sounds', 'translator', 'components'], function (sound,
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!unreadNotifs[notifData.nid]) {
|
if (!unreadNotifs[notifData.nid]) {
|
||||||
sound.play('notification');
|
sounds.play('notification', notifData.nid);
|
||||||
unreadNotifs[notifData.nid] = true;
|
unreadNotifs[notifData.nid] = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,90 +1,89 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/* global app, define, socket, config */
|
/* global app, define, socket, config */
|
||||||
|
|
||||||
define('sounds', ['buzz'], function (buzz) {
|
define('sounds', function () {
|
||||||
var Sounds = {};
|
var Sounds = {};
|
||||||
|
|
||||||
var loadedSounds = {};
|
var fileMap;
|
||||||
var eventSoundMapping;
|
var soundMap;
|
||||||
var files;
|
var cache = {};
|
||||||
|
|
||||||
socket.on('event:sounds.reloadMapping', function () {
|
Sounds.loadMap = function loadMap(callback) {
|
||||||
Sounds.reloadMapping();
|
socket.emit('modules.sounds.getUserSoundMap', function (err, map) {
|
||||||
});
|
|
||||||
|
|
||||||
Sounds.reloadMapping = function () {
|
|
||||||
socket.emit('modules.sounds.getMapping', function (err, mapping) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
eventSoundMapping = mapping;
|
soundMap = map;
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadData(callback) {
|
function loadData(callback) {
|
||||||
socket.emit('modules.sounds.getData', function (err, data) {
|
var outstanding = 2;
|
||||||
if (err) {
|
function after() {
|
||||||
return app.alertError('[sounds] Could not load sound mapping!');
|
outstanding -= 1;
|
||||||
}
|
if (outstanding === 0 && callback) {
|
||||||
eventSoundMapping = data.mapping;
|
callback();
|
||||||
files = data.files;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSoundLoaded(fileName) {
|
|
||||||
return loadedSounds[fileName];
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadFile(fileName, callback) {
|
|
||||||
function createSound() {
|
|
||||||
if (files && files[fileName]) {
|
|
||||||
loadedSounds[fileName] = new buzz.sound(files[fileName]);
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSoundLoaded(fileName)) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!files || !files[fileName]) {
|
|
||||||
return loadData(createSound);
|
|
||||||
}
|
|
||||||
createSound();
|
|
||||||
}
|
|
||||||
|
|
||||||
Sounds.play = function (name) {
|
|
||||||
function play() {
|
|
||||||
Sounds.playFile(eventSoundMapping[name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!eventSoundMapping) {
|
|
||||||
return loadData(play);
|
|
||||||
}
|
|
||||||
|
|
||||||
play();
|
|
||||||
};
|
|
||||||
|
|
||||||
Sounds.playFile = function (fileName) {
|
|
||||||
if (!fileName) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function play() {
|
|
||||||
if (loadedSounds[fileName]) {
|
|
||||||
loadedSounds[fileName].play();
|
|
||||||
} else {
|
|
||||||
app.alertError('[sounds] Not found: ' + fileName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (fileMap) {
|
||||||
if (isSoundLoaded(fileName)) {
|
outstanding -= 1;
|
||||||
play();
|
|
||||||
} else {
|
} else {
|
||||||
loadFile(fileName, play);
|
$.getJSON(config.relative_path + '/assets/sounds/fileMap.json', function (map) {
|
||||||
|
fileMap = map;
|
||||||
|
after();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sounds.loadMap(after);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sounds.playSound = function playSound(soundName) {
|
||||||
|
if (!soundMap || !fileMap) {
|
||||||
|
return loadData(after);
|
||||||
|
}
|
||||||
|
|
||||||
|
function after() {
|
||||||
|
if (!fileMap[soundName]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var audio = cache[soundName] = cache[soundName] || new Audio(config.relative_path + '/assets/sounds/' + fileMap[soundName]);
|
||||||
|
audio.pause();
|
||||||
|
audio.currentTime = 0;
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
after();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Sounds.play = function play(type, id) {
|
||||||
|
function after() {
|
||||||
|
if (!soundMap[type]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
if (localStorage.getItem('sounds.handled:' + id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localStorage.setItem('sounds.handled:' + id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sounds.playSound(soundMap[type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!soundMap || !fileMap) {
|
||||||
|
return loadData(after);
|
||||||
|
}
|
||||||
|
|
||||||
|
after();
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on('event:sounds.reloadMapping', function () {
|
||||||
|
Sounds.loadMap();
|
||||||
|
});
|
||||||
|
|
||||||
return Sounds;
|
return Sounds;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -37,11 +37,8 @@ settingsController.get = function (req, res, callback) {
|
|||||||
homePageRoutes: function (next) {
|
homePageRoutes: function (next) {
|
||||||
getHomePageRoutes(next);
|
getHomePageRoutes(next);
|
||||||
},
|
},
|
||||||
sounds: function (next) {
|
|
||||||
meta.sounds.getFiles(next);
|
|
||||||
},
|
|
||||||
soundsMapping: function (next) {
|
soundsMapping: function (next) {
|
||||||
meta.sounds.getMapping(userData.uid, next);
|
meta.sounds.getUserSoundMap(userData.uid, next);
|
||||||
}
|
}
|
||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
@@ -50,19 +47,47 @@ settingsController.get = function (req, res, callback) {
|
|||||||
userData.languages = results.languages;
|
userData.languages = results.languages;
|
||||||
userData.homePageRoutes = results.homePageRoutes;
|
userData.homePageRoutes = results.homePageRoutes;
|
||||||
|
|
||||||
var soundSettings = {
|
var types = [
|
||||||
'notificationSound': 'notification',
|
'notification',
|
||||||
'incomingChatSound': 'chat-incoming',
|
'chat-incoming',
|
||||||
'outgoingChatSound': 'chat-outgoing'
|
'chat-outgoing',
|
||||||
|
];
|
||||||
|
var aliases = {
|
||||||
|
'notification': 'notificationSound',
|
||||||
|
'chat-incoming': 'incomingChatSound',
|
||||||
|
'chat-outgoing': 'outgoingChatSound',
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(soundSettings).forEach(function (setting) {
|
types.forEach(function (type) {
|
||||||
userData[setting] = Object.keys(results.sounds).map(function (name) {
|
var soundpacks = plugins.soundpacks.map(function (pack) {
|
||||||
return {name: name, selected: name === results.soundsMapping[soundSettings[setting]]};
|
var sounds = Object.keys(pack.sounds).map(function (soundName) {
|
||||||
|
var value = pack.name + ' | ' + soundName;
|
||||||
|
return {
|
||||||
|
name: soundName,
|
||||||
|
value: value,
|
||||||
|
selected: value === results.soundsMapping[type],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: pack.name,
|
||||||
|
sounds: sounds,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
userData[type.replace('-', '_') + '_sound'] = soundpacks;
|
||||||
|
// fallback
|
||||||
|
userData[aliases[type]] = soundpacks.concat.apply([], soundpacks.map(function (pack) {
|
||||||
|
return pack.sounds.map(function (sound) {
|
||||||
|
return {
|
||||||
|
name: sound.value,
|
||||||
|
selected: sound.selected,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
plugins.fireHook('filter:user.customSettings', {settings: results.settings, customSettings: [], uid: req.uid}, next);
|
plugins.fireHook('filter:user.customSettings', { settings: results.settings, customSettings: [], uid: req.uid }, next);
|
||||||
},
|
},
|
||||||
function (data, next) {
|
function (data, next) {
|
||||||
userData.customSettings = data.customSettings;
|
userData.customSettings = data.customSettings;
|
||||||
@@ -75,10 +100,10 @@ settingsController.get = function (req, res, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
userData.dailyDigestFreqOptions = [
|
userData.dailyDigestFreqOptions = [
|
||||||
{value: 'off', name: '[[user:digest_off]]', selected: 'off' === userData.settings.dailyDigestFreq},
|
{ value: 'off', name: '[[user:digest_off]]', selected: 'off' === userData.settings.dailyDigestFreq },
|
||||||
{value: 'day', name: '[[user:digest_daily]]', selected: 'day' === userData.settings.dailyDigestFreq},
|
{ value: 'day', name: '[[user:digest_daily]]', selected: 'day' === userData.settings.dailyDigestFreq },
|
||||||
{value: 'week', name: '[[user:digest_weekly]]', selected: 'week' === userData.settings.dailyDigestFreq},
|
{ value: 'week', name: '[[user:digest_weekly]]', selected: 'week' === userData.settings.dailyDigestFreq },
|
||||||
{value: 'month', name: '[[user:digest_monthly]]', selected: 'month' === userData.settings.dailyDigestFreq}
|
{ value: 'month', name: '[[user:digest_monthly]]', selected: 'month' === userData.settings.dailyDigestFreq }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,46 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var meta = require('../../meta');
|
var plugins = require('../../plugins');
|
||||||
|
var db = require('../../database');
|
||||||
|
|
||||||
var soundsController = {};
|
var soundsController = {};
|
||||||
|
|
||||||
soundsController.get = function (req, res, next) {
|
soundsController.get = function (req, res, next) {
|
||||||
meta.sounds.getFiles(function (err, sounds) {
|
db.getObject('settings:sounds', function (err, settings) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
sounds = Object.keys(sounds).map(function (name) {
|
settings = settings || {};
|
||||||
return {
|
|
||||||
name: name
|
var types = [
|
||||||
};
|
'notification',
|
||||||
|
'chat-incoming',
|
||||||
|
'chat-outgoing',
|
||||||
|
];
|
||||||
|
var output = {};
|
||||||
|
|
||||||
|
types.forEach(function (type) {
|
||||||
|
var soundpacks = plugins.soundpacks.map(function (pack) {
|
||||||
|
var sounds = Object.keys(pack.sounds).map(function (soundName) {
|
||||||
|
var value = pack.name + ' | ' + soundName;
|
||||||
|
return {
|
||||||
|
name: soundName,
|
||||||
|
value: value,
|
||||||
|
selected: value === settings[type],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: pack.name,
|
||||||
|
sounds: sounds,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
output[type.replace('-', '_') + '_sound'] = soundpacks;
|
||||||
});
|
});
|
||||||
|
|
||||||
res.render('admin/general/sounds', {
|
res.render('admin/general/sounds', output);
|
||||||
sounds: sounds
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ var path = require('path');
|
|||||||
var async = require('async');
|
var async = require('async');
|
||||||
var nconf = require('nconf');
|
var nconf = require('nconf');
|
||||||
var winston = require('winston');
|
var winston = require('winston');
|
||||||
|
|
||||||
|
var meta = require('../../meta');
|
||||||
var file = require('../../file');
|
var file = require('../../file');
|
||||||
var image = require('../../image');
|
var image = require('../../image');
|
||||||
var plugins = require('../../plugins');
|
var plugins = require('../../plugins');
|
||||||
@@ -105,12 +107,7 @@ uploadsController.uploadSound = function (req, res, next) {
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
var soundsPath = path.join(__dirname, '../../../build/public/sounds'),
|
meta.sounds.build(function (err) {
|
||||||
filePath = path.join(nconf.get('upload_path'), 'sounds', uploadedFile.name);
|
|
||||||
|
|
||||||
file.link(filePath, path.join(soundsPath, path.basename(filePath)));
|
|
||||||
|
|
||||||
fs.unlink(uploadedFile.path, function (err) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ var winston = require('winston');
|
|||||||
|
|
||||||
var buildStart;
|
var buildStart;
|
||||||
|
|
||||||
var valid = ['js', 'clientCSS', 'acpCSS', 'tpl', 'lang'];
|
var valid = ['js', 'clientCSS', 'acpCSS', 'tpl', 'lang', 'sound'];
|
||||||
|
|
||||||
exports.buildAll = function (callback) {
|
exports.buildAll = function (callback) {
|
||||||
exports.build(valid.join(','), callback);
|
exports.build(valid.join(','), callback);
|
||||||
@@ -46,7 +46,7 @@ exports.buildTargets = function (targets, callback) {
|
|||||||
var cacheBuster = require('./cacheBuster');
|
var cacheBuster = require('./cacheBuster');
|
||||||
var meta = require('../meta');
|
var meta = require('../meta');
|
||||||
var numCpus = require('os').cpus().length;
|
var numCpus = require('os').cpus().length;
|
||||||
var strategy = (targets.length > 1 && numCpus > 1);
|
var parallel = targets.length > 1 && numCpus > 1;
|
||||||
|
|
||||||
buildStart = buildStart || Date.now();
|
buildStart = buildStart || Date.now();
|
||||||
|
|
||||||
@@ -59,13 +59,13 @@ exports.buildTargets = function (targets, callback) {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (strategy) {
|
if (parallel) {
|
||||||
winston.verbose('[build] Utilising multiple cores/processes');
|
winston.verbose('[build] Utilising multiple cores/processes');
|
||||||
} else {
|
} else {
|
||||||
winston.verbose('[build] Utilising single-core');
|
winston.verbose('[build] Utilising single-core');
|
||||||
}
|
}
|
||||||
|
|
||||||
async[strategy ? 'parallel' : 'series']([
|
async[parallel ? 'parallel' : 'series']([
|
||||||
function (next) {
|
function (next) {
|
||||||
if (targets.indexOf('js') !== -1) {
|
if (targets.indexOf('js') !== -1) {
|
||||||
winston.info('[build] Building javascript');
|
winston.info('[build] Building javascript');
|
||||||
@@ -111,6 +111,12 @@ exports.buildTargets = function (targets, callback) {
|
|||||||
meta.languages.build(step.bind(this, startTime, target, next));
|
meta.languages.build(step.bind(this, startTime, target, next));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'sound':
|
||||||
|
winston.info('[build] Linking sound files');
|
||||||
|
startTime = Date.now();
|
||||||
|
meta.sounds.build(step.bind(this, startTime, target, next));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
winston.warn('[build] Unknown build target: \'' + target + '\'');
|
winston.warn('[build] Unknown build target: \'' + target + '\'');
|
||||||
setImmediate(next);
|
setImmediate(next);
|
||||||
|
|||||||
@@ -2,71 +2,101 @@
|
|||||||
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var nconf = require('nconf');
|
|
||||||
var winston = require('winston');
|
|
||||||
var rimraf = require('rimraf');
|
var rimraf = require('rimraf');
|
||||||
var mkdirp = require('mkdirp');
|
var mkdirp = require('mkdirp');
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
|
|
||||||
var file = require('../file');
|
var file = require('../file');
|
||||||
var plugins = require('../plugins');
|
var plugins = require('../plugins');
|
||||||
|
var user = require('../user');
|
||||||
var db = require('../database');
|
var db = require('../database');
|
||||||
|
|
||||||
module.exports = function (Meta) {
|
var soundsPath = path.join(__dirname, '../../build/public/sounds');
|
||||||
|
var uploadsPath = path.join(__dirname, '../../public/uploads/sounds');
|
||||||
|
|
||||||
|
module.exports = function (Meta) {
|
||||||
Meta.sounds = {};
|
Meta.sounds = {};
|
||||||
|
|
||||||
Meta.sounds.init = function (callback) {
|
Meta.sounds.addUploads = function addUploads(callback) {
|
||||||
if (nconf.get('isPrimary') === 'true') {
|
fs.readdir(uploadsPath, function (err, files) {
|
||||||
setupSounds(callback);
|
if (err) {
|
||||||
} else {
|
if (err.code !== 'ENOENT') {
|
||||||
if (typeof callback === 'function') {
|
return callback(err);
|
||||||
callback();
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Meta.sounds.getFiles = function (callback) {
|
files = [];
|
||||||
async.waterfall([
|
}
|
||||||
function (next) {
|
|
||||||
fs.readdir(path.join(__dirname, '../../build/public/sounds'), next);
|
var uploadSounds = files.reduce(function (prev, fileName) {
|
||||||
},
|
var name = fileName.split('.');
|
||||||
function (sounds, next) {
|
if (!name.length || !name[0].length) {
|
||||||
fs.readdir(path.join(nconf.get('upload_path'), 'sounds'), function (err, uploaded) {
|
return prev;
|
||||||
if (err) {
|
}
|
||||||
if (err.code === 'ENOENT') {
|
name = name[0];
|
||||||
return next(null, sounds);
|
name = name[0].toUpperCase() + name.slice(1);
|
||||||
}
|
|
||||||
return next(err);
|
prev[name] = fileName;
|
||||||
}
|
return prev;
|
||||||
next(null, sounds.concat(uploaded));
|
}, {});
|
||||||
|
|
||||||
|
plugins.soundpacks = plugins.soundpacks.filter(function (pack) {
|
||||||
|
return pack.name !== 'Uploads';
|
||||||
|
});
|
||||||
|
if (Object.keys(uploadSounds).length) {
|
||||||
|
plugins.soundpacks.push({
|
||||||
|
name: 'Uploads',
|
||||||
|
id: 'uploads',
|
||||||
|
dir: uploadsPath,
|
||||||
|
sounds: uploadSounds,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
], function (err, files) {
|
|
||||||
if (err) {
|
|
||||||
winston.error('Could not get local sound files:' + err.message);
|
|
||||||
console.log(err.stack);
|
|
||||||
return callback(null, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
var localList = {};
|
callback();
|
||||||
|
|
||||||
// Filter out hidden files
|
|
||||||
files = files.filter(function (filename) {
|
|
||||||
return !filename.startsWith('.');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Return proper paths
|
|
||||||
files.forEach(function (filename) {
|
|
||||||
localList[filename] = nconf.get('relative_path') + '/assets/sounds/' + filename;
|
|
||||||
});
|
|
||||||
|
|
||||||
callback(null, localList);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Meta.sounds.getMapping = function (uid, callback) {
|
Meta.sounds.build = function build(callback) {
|
||||||
var user = require('../user');
|
Meta.sounds.addUploads(function (err) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
var map = plugins.soundpacks.map(function (pack) {
|
||||||
|
return Object.keys(pack.sounds).reduce(function (prev, soundName) {
|
||||||
|
var soundPath = pack.sounds[soundName];
|
||||||
|
prev[pack.name + ' | ' + soundName] = pack.id + '/' + soundPath;
|
||||||
|
return prev;
|
||||||
|
}, {});
|
||||||
|
});
|
||||||
|
map.unshift({});
|
||||||
|
map = Object.assign.apply(null, map);
|
||||||
|
|
||||||
|
async.series([
|
||||||
|
function (next) {
|
||||||
|
rimraf(soundsPath, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
mkdirp(soundsPath, next);
|
||||||
|
},
|
||||||
|
function (cb) {
|
||||||
|
async.parallel([
|
||||||
|
function (next) {
|
||||||
|
fs.writeFile(path.join(soundsPath, 'fileMap.json'), JSON.stringify(map), next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
async.each(plugins.soundpacks, function (pack, next) {
|
||||||
|
file.linkDirs(pack.dir, path.join(soundsPath, pack.id), next);
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
], cb);
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var keys = ['chat-incoming', 'chat-outgoing', 'notification'];
|
||||||
|
|
||||||
|
Meta.sounds.getUserSoundMap = function getUserSoundMap(uid, callback) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
defaultMapping: function (next) {
|
defaultMapping: function (next) {
|
||||||
db.getObject('settings:sounds', next);
|
db.getObject('settings:sounds', next);
|
||||||
@@ -78,82 +108,25 @@ module.exports = function (Meta) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
var userSettings = results.userSettings;
|
var userSettings = results.userSettings;
|
||||||
|
userSettings = {
|
||||||
|
notification: userSettings.notificationSound,
|
||||||
|
'chat-incoming': userSettings.incomingChatSound,
|
||||||
|
'chat-outgoing': userSettings.outgoingChatSound,
|
||||||
|
};
|
||||||
var defaultMapping = results.defaultMapping || {};
|
var defaultMapping = results.defaultMapping || {};
|
||||||
var soundMapping = {};
|
var soundMapping = {};
|
||||||
soundMapping.notification = (userSettings.notificationSound || userSettings.notificationSound === '') ?
|
|
||||||
userSettings.notificationSound : defaultMapping.notification || '';
|
|
||||||
|
|
||||||
soundMapping['chat-incoming'] = (userSettings.incomingChatSound || userSettings.incomingChatSound === '') ?
|
keys.forEach(function (key) {
|
||||||
userSettings.incomingChatSound : defaultMapping['chat-incoming'] || '';
|
if (userSettings[key] || userSettings[key] === '') {
|
||||||
|
soundMapping[key] = userSettings[key] || null;
|
||||||
soundMapping['chat-outgoing'] = (userSettings.outgoingChatSound || userSettings.outgoingChatSound === '') ?
|
} else {
|
||||||
userSettings.outgoingChatSound : defaultMapping['chat-outgoing'] || '';
|
soundMapping[key] = defaultMapping[key] || null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
callback(null, soundMapping);
|
callback(null, soundMapping);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function setupSounds(callback) {
|
|
||||||
var soundsPath = path.join(__dirname, '../../build/public/sounds');
|
|
||||||
|
|
||||||
async.waterfall([
|
|
||||||
function (next) {
|
|
||||||
fs.readdir(path.join(nconf.get('upload_path'), 'sounds'), function (err, files) {
|
|
||||||
if (err) {
|
|
||||||
if (err.code === 'ENOENT') {
|
|
||||||
return next(null, []);
|
|
||||||
}
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
next(null, files);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
function (uploaded, next) {
|
|
||||||
uploaded = uploaded.filter(function (filename) {
|
|
||||||
return !filename.startsWith('.');
|
|
||||||
}).map(function (filename) {
|
|
||||||
return path.join(nconf.get('upload_path'), 'sounds', filename);
|
|
||||||
});
|
|
||||||
|
|
||||||
plugins.fireHook('filter:sounds.get', uploaded, function (err, filePaths) {
|
|
||||||
if (err) {
|
|
||||||
winston.error('Could not initialise sound files:' + err.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the sounds directory
|
|
||||||
async.series([
|
|
||||||
function (next) {
|
|
||||||
rimraf(soundsPath, next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
mkdirp(soundsPath, next);
|
|
||||||
}
|
|
||||||
], function (err) {
|
|
||||||
if (err) {
|
|
||||||
winston.error('Could not initialise sound files:' + err.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link paths
|
|
||||||
async.each(filePaths, function (filePath, next) {
|
|
||||||
file.link(filePath, path.join(soundsPath, path.basename(filePath)), next);
|
|
||||||
}, function (err) {
|
|
||||||
if (!err) {
|
|
||||||
winston.verbose('[sounds] Sounds OK');
|
|
||||||
} else {
|
|
||||||
winston.error('[sounds] Could not initialise sounds: ' + err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof next === 'function') {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
], callback);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
@@ -32,6 +32,7 @@ var middleware;
|
|||||||
Plugins.libraryPaths = [];
|
Plugins.libraryPaths = [];
|
||||||
Plugins.versionWarning = [];
|
Plugins.versionWarning = [];
|
||||||
Plugins.languageCodes = [];
|
Plugins.languageCodes = [];
|
||||||
|
Plugins.soundpacks = [];
|
||||||
|
|
||||||
Plugins.initialized = false;
|
Plugins.initialized = false;
|
||||||
|
|
||||||
|
|||||||
@@ -37,10 +37,11 @@ module.exports = function (Plugins) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Plugins.prepareForBuild = function (callback) {
|
Plugins.prepareForBuild = function (callback) {
|
||||||
Plugins.cssFiles.length = 0;
|
Plugins.cssFiles = [];
|
||||||
Plugins.lessFiles.length = 0;
|
Plugins.lessFiles = [];
|
||||||
Plugins.clientScripts.length = 0;
|
Plugins.clientScripts = [];
|
||||||
Plugins.acpScripts.length = 0;
|
Plugins.acpScripts = [];
|
||||||
|
Plugins.soundpacks = [];
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
async.apply(Plugins.getPluginPaths),
|
async.apply(Plugins.getPluginPaths),
|
||||||
@@ -57,6 +58,7 @@ module.exports = function (Plugins) {
|
|||||||
async.apply(mapClientSideScripts, pluginData),
|
async.apply(mapClientSideScripts, pluginData),
|
||||||
async.apply(mapClientModules, pluginData),
|
async.apply(mapClientModules, pluginData),
|
||||||
async.apply(mapStaticDirectories, pluginData, pluginData.path),
|
async.apply(mapStaticDirectories, pluginData, pluginData.path),
|
||||||
|
async.apply(mapSoundpack, pluginData),
|
||||||
], next);
|
], next);
|
||||||
}, next);
|
}, next);
|
||||||
}
|
}
|
||||||
@@ -93,6 +95,9 @@ module.exports = function (Plugins) {
|
|||||||
function (next) {
|
function (next) {
|
||||||
mapClientModules(pluginData, next);
|
mapClientModules(pluginData, next);
|
||||||
},
|
},
|
||||||
|
function (next) {
|
||||||
|
mapSoundpack(pluginData, next);
|
||||||
|
},
|
||||||
], function (err) {
|
], function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
winston.verbose('[plugins] Could not load plugin : ' + pluginData.id);
|
winston.verbose('[plugins] Could not load plugin : ' + pluginData.id);
|
||||||
@@ -251,6 +256,35 @@ module.exports = function (Plugins) {
|
|||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapSoundpack(pluginData, callback) {
|
||||||
|
var soundpack = pluginData.soundpack;
|
||||||
|
if (!soundpack || !soundpack.dir || !soundpack.sounds) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
soundpack.name = soundpack.name || pluginData.name;
|
||||||
|
soundpack.id = pluginData.id;
|
||||||
|
soundpack.dir = path.join(pluginData.path, soundpack.dir);
|
||||||
|
async.each(Object.keys(soundpack.sounds), function (key, next) {
|
||||||
|
file.exists(path.join(soundpack.dir, soundpack.sounds[key]), function (exists) {
|
||||||
|
if (!exists) {
|
||||||
|
delete soundpack.sounds[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(soundpack.sounds).length) {
|
||||||
|
Plugins.soundpacks.push(soundpack);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function resolveModulePath(fullPath, relPath) {
|
function resolveModulePath(fullPath, relPath) {
|
||||||
/**
|
/**
|
||||||
* With npm@3, dependencies can become flattened, and appear at the root level.
|
* With npm@3, dependencies can become flattened, and appear at the root level.
|
||||||
|
|||||||
@@ -341,20 +341,8 @@ SocketModules.chats.getMessages = function (socket, data, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Sounds */
|
/* Sounds */
|
||||||
SocketModules.sounds.getSounds = function (socket, data, callback) {
|
SocketModules.sounds.getUserSoundMap = function getUserSoundMap(socket, data, callback) {
|
||||||
// Read sounds from local directory
|
meta.sounds.getUserSoundMap(socket.uid, callback);
|
||||||
meta.sounds.getFiles(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
SocketModules.sounds.getMapping = function (socket, data, callback) {
|
|
||||||
meta.sounds.getMapping(socket.uid, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
SocketModules.sounds.getData = function (socket, data, callback) {
|
|
||||||
async.parallel({
|
|
||||||
mapping: async.apply(meta.sounds.getMapping, socket.uid),
|
|
||||||
files: async.apply(meta.sounds.getFiles)
|
|
||||||
}, callback);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = SocketModules;
|
module.exports = SocketModules;
|
||||||
|
|||||||
@@ -9,9 +9,15 @@
|
|||||||
<div class="form-group col-xs-9">
|
<div class="form-group col-xs-9">
|
||||||
<select class="form-control" id="notification" name="notification">
|
<select class="form-control" id="notification" name="notification">
|
||||||
<option value="">[[user:no-sound]]</option>
|
<option value="">[[user:no-sound]]</option>
|
||||||
<!-- BEGIN sounds -->
|
<!-- BEGIN notification_sound -->
|
||||||
<option value="{sounds.name}">{sounds.name}</option>
|
<optgroup label="{notification_sound.name}">
|
||||||
<!-- END sounds -->
|
<!-- BEGIN notification_sound.sounds -->
|
||||||
|
<option value="{notification_sound.sounds.value}" <!-- IF notification_sound.sounds.selected -->selected<!-- ENDIF notification_sound.sounds.selected -->>
|
||||||
|
{notification_sound.sounds.name}
|
||||||
|
</option>
|
||||||
|
<!-- END notification_sound.sounds -->
|
||||||
|
</optgroup>
|
||||||
|
<!-- END notification_sound -->
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group col-xs-3">
|
<div class="btn-group col-xs-3">
|
||||||
@@ -29,9 +35,15 @@
|
|||||||
<div class="form-group col-xs-9">
|
<div class="form-group col-xs-9">
|
||||||
<select class="form-control" id="chat-incoming" name="chat-incoming">
|
<select class="form-control" id="chat-incoming" name="chat-incoming">
|
||||||
<option value="">[[user:no-sound]]</option>
|
<option value="">[[user:no-sound]]</option>
|
||||||
<!-- BEGIN sounds -->
|
<!-- BEGIN chat_incoming_sound -->
|
||||||
<option value="{sounds.name}">{sounds.name}</option>
|
<optgroup label="{chat_incoming_sound.name}">
|
||||||
<!-- END sounds -->
|
<!-- BEGIN chat_incoming_sound.sounds -->
|
||||||
|
<option value="{chat_incoming_sound.sounds.value}" <!-- IF chat_incoming_sound.sounds.selected -->selected<!-- ENDIF chat_incoming_sound.sounds.selected -->>
|
||||||
|
{chat_incoming_sound.sounds.name}
|
||||||
|
</option>
|
||||||
|
<!-- END chat_incoming_sound.sounds -->
|
||||||
|
</optgroup>
|
||||||
|
<!-- END chat_incoming_sound -->
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group col-xs-3">
|
<div class="btn-group col-xs-3">
|
||||||
@@ -44,9 +56,15 @@
|
|||||||
<div class="form-group col-xs-9">
|
<div class="form-group col-xs-9">
|
||||||
<select class="form-control" id="chat-outgoing" name="chat-outgoing">
|
<select class="form-control" id="chat-outgoing" name="chat-outgoing">
|
||||||
<option value="">[[user:no-sound]]</option>
|
<option value="">[[user:no-sound]]</option>
|
||||||
<!-- BEGIN sounds -->
|
<!-- BEGIN chat_outgoing_sound -->
|
||||||
<option value="{sounds.name}">{sounds.name}</option>
|
<optgroup label="{chat_outgoing_sound.name}">
|
||||||
<!-- END sounds -->
|
<!-- BEGIN chat_outgoing_sound.sounds -->
|
||||||
|
<option value="{chat_outgoing_sound.sounds.value}" <!-- IF chat_outgoing_sound.sounds.selected -->selected<!-- ENDIF chat_outgoing_sound.sounds.selected -->>
|
||||||
|
{chat_outgoing_sound.sounds.name}
|
||||||
|
</option>
|
||||||
|
<!-- END chat_outgoing_sound.sounds -->
|
||||||
|
</optgroup>
|
||||||
|
<!-- END chat_outgoing_sound -->
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group col-xs-3">
|
<div class="btn-group col-xs-3">
|
||||||
@@ -56,7 +74,15 @@
|
|||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<input data-action="upload" data-title="Upload Sound" data-route="{config.relative_path}/api/admin/upload/sound" type="button" class="btn btn-primary" value="[[admin/general/sounds:upload-new-sound]]"></input>
|
<input
|
||||||
|
data-action="upload"
|
||||||
|
data-title="Upload Sound"
|
||||||
|
data-route="{config.relative_path}/api/admin/upload/sound"
|
||||||
|
data-accept="audio/*"
|
||||||
|
type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
value="[[admin/general/sounds:upload-new-sound]]"
|
||||||
|
></input>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -103,9 +103,9 @@ function initializeNodeBB(callback) {
|
|||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
async.series([
|
async.series([
|
||||||
async.apply(meta.sounds.init),
|
meta.sounds.addUploads,
|
||||||
async.apply(languages.init),
|
languages.init,
|
||||||
async.apply(meta.blacklist.load)
|
meta.blacklist.load,
|
||||||
], next);
|
], next);
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
|
|||||||
Reference in New Issue
Block a user