nodebb-plugin-audio-embed 2.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ import serverConfig from 'eslint-config-nodebb';
4
+ import publicConfig from 'eslint-config-nodebb/public';
5
+
6
+ export default [
7
+ ...publicConfig,
8
+ ...serverConfig,
9
+ ];
10
+
@@ -1,25 +1,67 @@
1
1
  'use strict';
2
2
 
3
+ const fs = require('fs').promises;
4
+ const path = require('path');
5
+
6
+ const nconf = nodebb.require('nconf');
7
+ const db = nodebb.require('./src/database');
8
+
3
9
  const Controllers = module.exports;
4
10
 
5
- Controllers.renderAdminPage = function (req, res, next) {
11
+ Controllers.renderAdminPage = function (req, res) {
6
12
  res.render('admin/plugins/audio-embed', {
7
13
  title: 'Audio Embed',
8
14
  });
9
15
  };
10
16
 
11
- Controllers.upload = function(req, res, next) {
12
- var main = module.parent.exports;
13
-
14
- main.processUpload(req.files.files[0], function(err, payload) {
15
- if (!err) {
16
- res.json([{
17
- url: payload.id
18
- }]);
19
- } else {
20
- res.json({
21
- error: err.message === 'invalid-file-type' ? 'Invalid File Type Uploaded. Please check the file format or extension to ensure it is an audio file.' : 'An unknown error occured'
22
- });
23
- }
24
- });
17
+ Controllers.upload = async function (req, res) {
18
+ try {
19
+ const payload = await processUpload(req.files[0]);
20
+ res.json([{
21
+ url: payload.id,
22
+ }]);
23
+ } catch (err) {
24
+ res.status(400);
25
+ res.json({
26
+ error: err.message === 'invalid-file-type' ?
27
+ 'Invalid File Type Uploaded. Please check the file format or extension to ensure it is an audio file.' :
28
+ err.message,
29
+ });
30
+ }
25
31
  };
32
+
33
+ async function processUpload(payload) {
34
+ if (!payload || !payload.path || !payload.name || !payload.size) {
35
+ throw new Error('invalid-file');
36
+ }
37
+ if (!payload.type.startsWith('audio/')) {
38
+ throw new Error('invalid-file-type');
39
+ }
40
+
41
+ const id = path.basename(payload.path);
42
+ const uploadPath = path.join(nconf.get('upload_path'), 'audio-embed', id);
43
+
44
+ await move(payload.path, uploadPath);
45
+ await db.setObject('audio-embed:id:' + id, {
46
+ name: payload.name,
47
+ size: payload.size,
48
+ });
49
+ await db.sortedSetAdd('audio-embed:date', +new Date(), id);
50
+
51
+ return {
52
+ id: id,
53
+ };
54
+ }
55
+
56
+ async function move(path, uploadPath) {
57
+ try {
58
+ await fs.rename(path, uploadPath);
59
+ } catch (err) {
60
+ if (err.code !== 'EXDEV') {
61
+ throw err;
62
+ }
63
+
64
+ await fs.copyFile(path, uploadPath);
65
+ await fs.unlink(path);
66
+ }
67
+ }
package/library.js CHANGED
@@ -1,121 +1,90 @@
1
- "use strict";
2
- /* globals require, module */
1
+ 'use strict';
3
2
 
4
- var path = require('path'),
5
- fs = require('fs'),
6
- mkdirp = require('mkdirp'),
7
- mv = require('mv'),
8
- async = require('async'),
9
- nconf = require.main.require('nconf');
3
+ const path = require('path');
4
+ const { mkdirp } = require('mkdirp');
10
5
 
11
- var db = require.main.require('./src/database');
6
+ const nconf = nodebb.require('nconf');
12
7
 
13
- var controllers = require('./lib/controllers');
8
+ const db = nodebb.require('./src/database');
9
+ const routeHelpers = nodebb.require('./src/routes/helpers');
14
10
 
15
- var plugin = {
16
- embedRegex: /\[audio\/([\w\-_.]+)\]/g
17
- },
18
- app;
11
+ const controllers = require('./lib/controllers');
19
12
 
20
- plugin.init = function(params, callback) {
21
- var router = params.router,
22
- hostMiddleware = params.middleware,
23
- multiparty = require.main.require('connect-multiparty')();
13
+ const plugin = {
14
+ embedRegex: /\[audio\/([\w\-_.]+)\]/g,
15
+ };
16
+ let app;
24
17
 
25
- app = params.app;
18
+ plugin.init = async function (params) {
19
+ const { router, middleware } = params;
26
20
 
27
- router.get('/admin/plugins/audio-embed', hostMiddleware.admin.buildHeader, controllers.renderAdminPage);
28
- router.get('/api/admin/plugins/audio-embed', controllers.renderAdminPage);
29
- router.post('/plugins/nodebb-plugin-audio-embed/upload', multiparty, hostMiddleware.validateFiles, hostMiddleware.applyCSRF, controllers.upload);
21
+ app = params.app;
30
22
 
31
- mkdirp(path.join(nconf.get('upload_path'), 'audio-embed'), callback);
32
- };
23
+ routeHelpers.setupAdminPageRoute(router, '/admin/plugins/audio-embed', controllers.renderAdminPage);
33
24
 
34
- plugin.addAdminNavigation = function(header, callback) {
35
- header.plugins.push({
36
- route: '/plugins/audio-embed',
37
- icon: 'fa-volume-up',
38
- name: 'Audio Embed'
39
- });
25
+ const upload = nodebb.require('./src/middleware/multer');
40
26
 
41
- callback(null, header);
42
- };
27
+ router.post('/plugins/nodebb-plugin-audio-embed/upload', upload.any(), middleware.validateFiles, middleware.applyCSRF, routeHelpers.tryRoute(controllers.upload));
43
28
 
44
- plugin.registerFormatting = function(payload, callback) {
45
- payload.options.push({ name: 'audio-embed', className: 'fa fa-file-audio-o' });
46
- callback(null, payload);
29
+ await mkdirp(path.join(nconf.get('upload_path'), 'audio-embed'));
47
30
  };
48
31
 
49
- plugin.processUpload = function(payload, callback) {
50
- if (payload.type.startsWith('audio/')) {
51
- var id = path.basename(payload.path),
52
- uploadPath = path.join(nconf.get('upload_path'), 'audio-embed', id);
53
-
54
- async.waterfall([
55
- async.apply(mv, payload.path, uploadPath),
56
- async.apply(db.setObject, 'audio-embed:id:' + id, {
57
- name: payload.name,
58
- size: payload.size
59
- }),
60
- async.apply(db.sortedSetAdd, 'audio-embed:date', +new Date(), id)
61
- ], function(err) {
62
- if (err) {
63
- return callback(err);
64
- }
65
-
66
- callback(null, {
67
- id: id
68
- });
69
- });
70
- } else {
71
- callback(new Error('invalid-file-type'));
72
- }
32
+ plugin.addAdminNavigation = function (header) {
33
+ header.plugins.push({
34
+ route: '/plugins/audio-embed',
35
+ icon: 'fa-volume-up',
36
+ name: 'Audio Embed',
37
+ });
38
+ return header;
73
39
  };
74
40
 
75
- plugin.parsePost = function(data, callback) {
76
- if (!data || !data.postData || !data.postData.content) {
77
- return callback(null, data);
78
- }
41
+ plugin.registerFormatting = function (payload) {
42
+ payload.options.push({
43
+ name: 'audio-embed',
44
+ className: 'fa fa-file-audio-o',
45
+ title: 'Embed Audio',
46
+ });
47
+ return payload;
48
+ };
79
49
 
80
- plugin.parseRaw(data.postData.content, function(err, content) {
81
- if (err) {
82
- return callback(err);
83
- }
50
+ plugin.parsePost = async function (data) {
51
+ if (!data || !data.postData || !data.postData.content) {
52
+ return data;
53
+ }
84
54
 
85
- data.postData.content = content;
86
- callback(null, data);
87
- });
55
+ data.postData.content = await plugin.parseRaw(data.postData.content);
56
+ return data;
88
57
  };
89
58
 
90
- plugin.parseRaw = function(content, callback) {
91
- var matches = content.match(plugin.embedRegex);
92
-
93
- if (!matches) {
94
- return callback(null, content);
95
- }
96
-
97
- // Filter out duplicates
98
- matches = matches.filter(function(match, idx) {
99
- return idx === matches.indexOf(match);
100
- }).map(function(match) {
101
- return match.slice(7, -1);
102
- });
103
-
104
- async.filter(matches, plugin.exists, function(err, ids) {
105
- async.reduce(ids, content, function(content, id, next) {
106
- app.render('partials/audio-embed', {
107
- id: id,
108
- path: path.join(nconf.get('relative_path'), '/uploads/audio-embed', id)
109
- }, function(err, html) {
110
- content = content.replace('[audio/' + id + ']', html);
111
- next(err, content);
112
- });
113
- }, callback);
114
- });
59
+ plugin.parseRaw = async function (content) {
60
+ const matches = [...new Set(content.match(plugin.embedRegex) || [])]
61
+ .map(match => match.slice(7, -1));
62
+
63
+ if (!matches.length) {
64
+ return content;
65
+ }
66
+
67
+ const existence = await db.isSortedSetMembers('audio-embed:date', matches);
68
+ const ids = matches.filter((id, index) => existence[index]);
69
+
70
+ let parsedContent = content;
71
+ const renderedEmbeds = await Promise.all(ids.map(async id => ({
72
+ id,
73
+ html: await app.renderAsync('partials/audio-embed', {
74
+ id,
75
+ path: path.join(nconf.get('relative_path'), '/uploads/audio-embed', id),
76
+ }),
77
+ })));
78
+
79
+ for (const { id, html } of renderedEmbeds) {
80
+ parsedContent = parsedContent.replace(`[audio/${id}]`, html);
81
+ }
82
+
83
+ return parsedContent;
115
84
  };
116
85
 
117
- plugin.exists = function(id, callback) {
118
- db.isSortedSetMember('audio-embed:date', id, callback);
86
+ plugin.exists = async function (id) {
87
+ return await db.isSortedSetMember('audio-embed:date', id);
119
88
  };
120
89
 
121
90
  module.exports = plugin;
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "nodebb-plugin-audio-embed",
3
- "version": "2.0.1",
3
+ "version": "3.0.0",
4
4
  "description": "",
5
5
  "main": "library.js",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/julianlam/nodebb-plugin-audio-embed"
9
9
  },
10
+ "scripts": {
11
+ "lint": "eslint ."
12
+ },
10
13
  "keywords": [
11
14
  "nodebb",
12
15
  "plugin"
@@ -21,11 +24,13 @@
21
24
  },
22
25
  "readmeFilename": "README.md",
23
26
  "nbbpm": {
24
- "compatibility": "^3.2.0"
27
+ "compatibility": "^4.14.0"
25
28
  },
26
29
  "dependencies": {
27
- "async": "^3.2.2",
28
- "mkdirp": "^0.5.1",
29
- "mv": "^2.1.1"
30
+ "mkdirp": "^3.0.1"
31
+ },
32
+ "devDependencies": {
33
+ "eslint": "10.6.0",
34
+ "eslint-config-nodebb": "^2.0.3"
30
35
  }
31
36
  }
@@ -1,23 +1,22 @@
1
1
  'use strict';
2
- /* globals $, app, socket, define */
3
2
 
4
- define('admin/plugins/audio-embed', ['settings', 'alerts'], function(Settings, alerts) {
3
+ define('admin/plugins/audio-embed', ['settings', 'alerts'], function (Settings, alerts) {
5
4
 
6
- var ACP = {};
5
+ const ACP = {};
7
6
 
8
- ACP.init = function() {
7
+ ACP.init = function () {
9
8
  Settings.load('audio-embed', $('.audio-embed-settings'));
10
9
 
11
- $('#save').on('click', function() {
12
- Settings.save('audio-embed', $('.audio-embed-settings'), function() {
10
+ $('#save').on('click', function () {
11
+ Settings.save('audio-embed', $('.audio-embed-settings'), function () {
13
12
  alerts.alert({
14
13
  type: 'success',
15
14
  alert_id: 'audio-embed-saved',
16
15
  title: 'Settings Saved',
17
16
  message: 'Please reload your NodeBB to apply these settings',
18
- clickfn: function() {
17
+ clickfn: function () {
19
18
  socket.emit('admin.reload');
20
- }
19
+ },
21
20
  });
22
21
  });
23
22
  });
@@ -1,21 +1,20 @@
1
- "use strict";
2
- /* globals $, require */
1
+ 'use strict';
3
2
 
4
- $(document).ready(function() {
3
+ $(document).ready(function () {
5
4
  function upload(callback) {
6
5
  require(['uploader'], function (uploader) {
7
6
  uploader.show({
8
7
  title: 'Upload Audio',
9
8
  description: 'Upload an audio file for embedding into your post',
10
- route: config.relative_path + '/plugins/nodebb-plugin-audio-embed/upload'
9
+ route: config.relative_path + '/plugins/nodebb-plugin-audio-embed/upload',
11
10
  }, callback);
12
11
  });
13
12
  }
14
13
 
15
- $(window).on('action:composer.loaded', function (ev, data) {
16
- require(['composer/formatting', 'composer/controls'], function(formatting, controls) {
14
+ $(window).on('action:composer.loaded', function () {
15
+ require(['composer/formatting', 'composer/controls'], function (formatting, controls) {
17
16
  if (formatting && controls) {
18
- formatting.addButtonDispatch('audio-embed', function(textarea, selectionStart, selectionEnd){
17
+ formatting.addButtonDispatch('audio-embed', function (textarea) {
19
18
  upload(function (id) {
20
19
  controls.insertIntoTextarea(textarea, '[audio/' + id + ']');
21
20
  controls.updateTextareaSelection(textarea, id.length + 8, id.length + 8);
@@ -29,33 +28,33 @@ $(document).ready(function() {
29
28
  }
30
29
  });
31
30
 
32
- $(window).on('action:redactor.load', function() {
31
+ $(window).on('action:redactor.load', function () {
33
32
  $.Redactor.prototype['audio-embed'] = function () {
34
33
  return {
35
34
  init: function () {
36
- var self = this;
35
+ const self = this;
37
36
 
38
37
  // require translator as such because it was undefined without it
39
38
  require(['translator'], function (translator) {
40
39
  translator.translate('Embed Audio', function (translated) {
41
- var button = self.button.add('audio-embed', translated);
40
+ const button = self.button.add('audio-embed', translated);
42
41
  self.button.setIcon(button, '<i class="fa fa-file-audio-o"></i>');
43
42
  self.button.addCallback(button, self['audio-embed'].onClick);
44
43
  });
45
44
  });
46
45
  },
47
46
  onClick: function () {
48
- var self = this;
47
+ const self = this;
49
48
  upload(function (id) {
50
49
  require(['benchpress'], (Benchpress) => {
51
50
  Benchpress.parse('partials/audio-embed', {
52
- path: config.relative_path + '/uploads/audio-embed/' + id
51
+ path: config.relative_path + '/uploads/audio-embed/' + id,
53
52
  }, function (html) {
54
53
  self.insert.html(html);
55
54
  });
56
55
  });
57
56
  });
58
- }
57
+ },
59
58
  };
60
59
  };
61
60
  });