nodebb-plugin-tenor-gif 1.2.9 → 2.1.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.
- package/.eslintrc +1 -137
- package/README.md +8 -3
- package/library.js +65 -59
- package/package.json +8 -6
- package/static/lib/.eslintrc +3 -0
- package/static/lib/admin.js +1 -6
- package/static/lib/main.js +9 -8
- package/static/templates/admin/plugins/tenor-gif.tpl +17 -1
- package/websockets.js +5 -3
package/.eslintrc
CHANGED
|
@@ -1,139 +1,3 @@
|
|
|
1
1
|
{
|
|
2
|
-
"extends": "
|
|
3
|
-
"parserOptions": {
|
|
4
|
-
"sourceType": "script"
|
|
5
|
-
},
|
|
6
|
-
|
|
7
|
-
"rules": {
|
|
8
|
-
// Customized
|
|
9
|
-
"handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ],
|
|
10
|
-
"comma-dangle": ["error", {
|
|
11
|
-
"arrays": "always-multiline",
|
|
12
|
-
"objects": "always-multiline",
|
|
13
|
-
"imports": "always-multiline",
|
|
14
|
-
"exports": "always-multiline",
|
|
15
|
-
"functions": "never"
|
|
16
|
-
}],
|
|
17
|
-
"no-return-await": "off",
|
|
18
|
-
"no-constant-condition": "off",
|
|
19
|
-
"no-empty": ["error", { "allowEmptyCatch": true }],
|
|
20
|
-
"no-underscore-dangle": "off",
|
|
21
|
-
"no-console": "off",
|
|
22
|
-
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
|
|
23
|
-
"strict": ["error", "global"],
|
|
24
|
-
"consistent-return": "off",
|
|
25
|
-
"func-names": "off",
|
|
26
|
-
"no-tabs": "off",
|
|
27
|
-
"indent": ["error", "tab"],
|
|
28
|
-
"no-eq-null": "off",
|
|
29
|
-
"camelcase": "off",
|
|
30
|
-
"no-new": "off",
|
|
31
|
-
"no-shadow": "off",
|
|
32
|
-
"no-use-before-define": ["error", "nofunc"],
|
|
33
|
-
"no-prototype-builtins": "off",
|
|
34
|
-
"new-cap": "off",
|
|
35
|
-
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
|
|
36
|
-
"object-curly-newline": "off",
|
|
37
|
-
"no-restricted-globals": "off",
|
|
38
|
-
"function-paren-newline": "off",
|
|
39
|
-
"import/no-unresolved": "error",
|
|
40
|
-
"quotes": ["error", "single", {
|
|
41
|
-
"avoidEscape": true,
|
|
42
|
-
"allowTemplateLiterals": true
|
|
43
|
-
}],
|
|
44
|
-
"no-else-return": [ "error", { "allowElseIf": true } ],
|
|
45
|
-
"operator-linebreak": [ "error", "after" ],
|
|
46
|
-
|
|
47
|
-
// ES6
|
|
48
|
-
"prefer-rest-params": "off",
|
|
49
|
-
"prefer-spread": "off",
|
|
50
|
-
"prefer-arrow-callback": "off",
|
|
51
|
-
"prefer-template": "off",
|
|
52
|
-
"no-var": "off",
|
|
53
|
-
"object-shorthand": "off",
|
|
54
|
-
"vars-on-top": "off",
|
|
55
|
-
"prefer-destructuring": "off",
|
|
56
|
-
|
|
57
|
-
// TODO
|
|
58
|
-
"import/no-extraneous-dependencies": "off",
|
|
59
|
-
"import/no-dynamic-require": "off",
|
|
60
|
-
"import/newline-after-import": "off",
|
|
61
|
-
"no-bitwise": "off",
|
|
62
|
-
"global-require": "off",
|
|
63
|
-
"max-len": "off",
|
|
64
|
-
"no-param-reassign": "off",
|
|
65
|
-
"no-restricted-syntax": "off",
|
|
66
|
-
"no-script-url": "off",
|
|
67
|
-
"default-case": "off",
|
|
68
|
-
"linebreak-style": "off",
|
|
69
|
-
|
|
70
|
-
// "no-multi-assign": "off",
|
|
71
|
-
// "one-var": "off",
|
|
72
|
-
// "no-undef": "off",
|
|
73
|
-
// "max-nested-callbacks": "off",
|
|
74
|
-
// "no-mixed-requires": "off",
|
|
75
|
-
// "brace-style": "off",
|
|
76
|
-
// "max-statements-per-line": "off",
|
|
77
|
-
// "no-unused-vars": "off",
|
|
78
|
-
// "no-mixed-spaces-and-tabs": "off",
|
|
79
|
-
// "no-useless-concat": "off",
|
|
80
|
-
// "require-jsdoc": "off",
|
|
81
|
-
// "eqeqeq": "off",
|
|
82
|
-
// "no-negated-condition": "off",
|
|
83
|
-
// "one-var-declaration-per-line": "off",
|
|
84
|
-
// "no-lonely-if": "off",
|
|
85
|
-
// "radix": "off",
|
|
86
|
-
// "no-else-return": "off",
|
|
87
|
-
// "no-useless-escape": "off",
|
|
88
|
-
// "block-scoped-var": "off",
|
|
89
|
-
// "operator-assignment": "off",
|
|
90
|
-
// "yoda": "off",
|
|
91
|
-
// "no-loop-func": "off",
|
|
92
|
-
// "no-void": "off",
|
|
93
|
-
// "valid-jsdoc": "off",
|
|
94
|
-
// "no-cond-assign": "off",
|
|
95
|
-
// "no-redeclare": "off",
|
|
96
|
-
// "no-unreachable": "off",
|
|
97
|
-
// "no-nested-ternary": "off",
|
|
98
|
-
// "operator-linebreak": "off",
|
|
99
|
-
// "guard-for-in": "off",
|
|
100
|
-
// "no-unneeded-ternary": "off",
|
|
101
|
-
// "no-sequences": "off",
|
|
102
|
-
// "no-extend-native": "off",
|
|
103
|
-
// "no-shadow-restricted-names": "off",
|
|
104
|
-
// "no-extra-boolean-cast": "off",
|
|
105
|
-
// "no-path-concat": "off",
|
|
106
|
-
// "no-unused-expressions": "off",
|
|
107
|
-
// "no-return-assign": "off",
|
|
108
|
-
// "no-restricted-modules": "off",
|
|
109
|
-
// "object-curly-spacing": "off",
|
|
110
|
-
// "indent": "off",
|
|
111
|
-
// "padded-blocks": "off",
|
|
112
|
-
// "eol-last": "off",
|
|
113
|
-
// "lines-around-directive": "off",
|
|
114
|
-
// "strict": "off",
|
|
115
|
-
// "comma-dangle": "off",
|
|
116
|
-
// "no-multi-spaces": "off",
|
|
117
|
-
// "quotes": "off",
|
|
118
|
-
// "keyword-spacing": "off",
|
|
119
|
-
// "no-mixed-operators": "off",
|
|
120
|
-
// "comma-spacing": "off",
|
|
121
|
-
// "no-trailing-spaces": "off",
|
|
122
|
-
// "key-spacing": "off",
|
|
123
|
-
// "no-multiple-empty-lines": "off",
|
|
124
|
-
// "spaced-comment": "off",
|
|
125
|
-
// "space-in-parens": "off",
|
|
126
|
-
// "block-spacing": "off",
|
|
127
|
-
// "quote-props": "off",
|
|
128
|
-
// "space-unary-ops": "off",
|
|
129
|
-
// "no-empty": "off",
|
|
130
|
-
// "dot-notation": "off",
|
|
131
|
-
// "func-call-spacing": "off",
|
|
132
|
-
// "array-bracket-spacing": "off",
|
|
133
|
-
// "object-property-newline": "off",
|
|
134
|
-
// "no-continue": "off",
|
|
135
|
-
// "no-extra-semi": "off",
|
|
136
|
-
// "no-spaced-func": "off",
|
|
137
|
-
// "no-useless-return": "off"
|
|
138
|
-
}
|
|
2
|
+
"extends": "nodebb"
|
|
139
3
|
}
|
package/README.md
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
This plugin adds a "GIF" button to the default composer and allows you to search and insert GIFs. It is powered by the [Tenor GIF service](https://tenor.com). Kudos to Tenor for providing a simple and easy-to-use API! ❤️
|
|
5
|
+
This plugin adds a "GIF" button to the default composer and allows you to search and insert GIFs. It is powered by the [Tenor GIF service](https://tenor.com). Kudos to Tenor/Alphabet for providing a simple and easy-to-use API! ❤️
|
|
6
6
|
|
|
7
|
-
Install the plugin via the admin dashboard, or `npm i nodebb-plugin-tenor-gif`. You'll need to register for a Tenor GIF API key
|
|
7
|
+
Install the plugin via the admin dashboard, or `npm i nodebb-plugin-tenor-gif`. You'll need to register for a Tenor GIF API key from the [Google Cloud Console](https://console.cloud.google.com/apis/credentials).
|
|
8
8
|
|
|
9
|
-
Then insert said API, save the config, and reload/restart NodeBB.
|
|
9
|
+
Then insert said API, save the config, and reload/restart NodeBB.
|
|
10
|
+
|
|
11
|
+
# Migrating from v1 to v2
|
|
12
|
+
|
|
13
|
+
We are now using v2 of the Tenor GIF API.
|
|
14
|
+
Register for a new v2 API key from the [Google Cloud Console](https://console.cloud.google.com/apis/credentials) and replace the existing key.
|
package/library.js
CHANGED
|
@@ -1,39 +1,32 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
var websockets = require('./websockets');
|
|
5
|
-
var meta = require.main.require('./src/meta');
|
|
6
|
-
var winston = require.main.require('winston');
|
|
3
|
+
const request = require('request-promise-native');
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
const controllers = require('./lib/controllers');
|
|
6
|
+
const websockets = require('./websockets');
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const nconf = require.main.require('nconf');
|
|
9
|
+
const meta = require.main.require('./src/meta');
|
|
10
|
+
const slugify = require.main.require('./src/slugify');
|
|
11
|
+
const cacheCreate = require.main.require('./src/cacheCreate');
|
|
12
|
+
|
|
13
|
+
const plugin = module.exports;
|
|
14
|
+
|
|
15
|
+
plugin._cache = cacheCreate({
|
|
16
|
+
name: 'gifs',
|
|
17
|
+
max: 20,
|
|
18
|
+
length: function (n) { return n.length; },
|
|
19
|
+
maxAge: 1000 * 60 * 60, // 1 hour
|
|
20
|
+
});
|
|
15
21
|
|
|
16
|
-
plugin.init =
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
plugin.init = async (params) => {
|
|
23
|
+
const { router } = params;
|
|
24
|
+
const hostMiddleware = params.middleware;
|
|
19
25
|
|
|
20
26
|
router.get('/admin/plugins/tenor-gif', hostMiddleware.admin.buildHeader, controllers.renderAdminPage);
|
|
21
27
|
router.get('/api/admin/plugins/tenor-gif', controllers.renderAdminPage);
|
|
22
28
|
|
|
23
29
|
websockets.init();
|
|
24
|
-
plugin.refreshSettings(callback);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
plugin.refreshSettings = function (callback) {
|
|
28
|
-
meta.settings.get('tenor-gif', function (err, settings) {
|
|
29
|
-
Object.assign(plugin._settings, settings);
|
|
30
|
-
|
|
31
|
-
if (!settings.key || !settings.key.length) {
|
|
32
|
-
winston.warn('[plugin/tenor-gif] Invalid or missing API Key, plugin disabled');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
callback(err);
|
|
36
|
-
});
|
|
37
30
|
};
|
|
38
31
|
|
|
39
32
|
plugin.addAdminNavigation = function (header, callback) {
|
|
@@ -46,45 +39,58 @@ plugin.addAdminNavigation = function (header, callback) {
|
|
|
46
39
|
callback(null, header);
|
|
47
40
|
};
|
|
48
41
|
|
|
49
|
-
plugin.registerFormatting =
|
|
50
|
-
|
|
42
|
+
plugin.registerFormatting = async (payload) => {
|
|
43
|
+
const { key } = await meta.settings.get('tenor-gif');
|
|
44
|
+
if (key) {
|
|
51
45
|
payload.options.push({ name: 'gif', className: 'fa fa-tenor-gif', title: 'Insert GIF' });
|
|
52
46
|
}
|
|
53
47
|
|
|
54
|
-
|
|
48
|
+
return payload;
|
|
55
49
|
};
|
|
56
50
|
|
|
57
|
-
plugin.query =
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
plugin.query = async (query) => {
|
|
52
|
+
let { contentFilter, key, limit } = await meta.settings.get('tenor-gif');
|
|
53
|
+
if (!limit || limit < 1 || limit > 50) {
|
|
54
|
+
limit = 10;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
query = String(query).trim();
|
|
58
|
+
const commonArgs = `&limit=${limit}&contentfilter=${contentFilter || 'medium'}&key=${key}&client_key=nodebb-${slugify(nconf.get('url'))}`;
|
|
59
|
+
let url = `https://tenor.googleapis.com/v2/featured?type=featured${commonArgs}`;
|
|
60
|
+
if (query) {
|
|
61
|
+
url = `https://tenor.googleapis.com/v2/search?q=${query}${commonArgs}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let gifs = plugin._cache.get(query);
|
|
65
|
+
if (gifs) {
|
|
66
|
+
return gifs;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const body = await request({
|
|
70
|
+
url,
|
|
60
71
|
method: 'get',
|
|
61
72
|
json: true,
|
|
62
|
-
}, function (err, res, body) {
|
|
63
|
-
if (!plugin._settings.key || (body && body.hasOwnProperty('error'))) {
|
|
64
|
-
err = new Error('[[error:invalid-login-credentials]]');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Malformed return handling
|
|
68
|
-
if (!body || !body.results) {
|
|
69
|
-
return callback(new Error('[[error:invalid-data]]'));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (err) {
|
|
73
|
-
return callback(err);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Collapse results down to array of images
|
|
77
|
-
var gifs = body.results.reduce(function (memo, cur) {
|
|
78
|
-
memo.push({
|
|
79
|
-
url: cur.media[0].gif.url,
|
|
80
|
-
thumb: cur.media[0].tinygif.url,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return memo;
|
|
84
|
-
}, []);
|
|
85
|
-
|
|
86
|
-
callback(null, gifs);
|
|
87
73
|
});
|
|
88
|
-
};
|
|
89
74
|
|
|
90
|
-
|
|
75
|
+
if (!key || (body && body.hasOwnProperty('error'))) {
|
|
76
|
+
throw new Error('[[error:invalid-login-credentials]]');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Malformed return handling
|
|
80
|
+
if (!body.results) {
|
|
81
|
+
throw new Error('[[error:invalid-data]]');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Collapse results down to array of images
|
|
85
|
+
gifs = body.results.reduce((memo, cur) => {
|
|
86
|
+
memo.push({
|
|
87
|
+
url: cur.media_formats.gif.url,
|
|
88
|
+
thumb: cur.media_formats.tinygif.url,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return memo;
|
|
92
|
+
}, []);
|
|
93
|
+
|
|
94
|
+
plugin._cache.set(query, gifs);
|
|
95
|
+
return gifs;
|
|
96
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodebb-plugin-tenor-gif",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "library.js",
|
|
6
6
|
"repository": {
|
|
@@ -21,20 +21,22 @@
|
|
|
21
21
|
},
|
|
22
22
|
"readmeFilename": "README.md",
|
|
23
23
|
"nbbpm": {
|
|
24
|
-
"compatibility": "^1.6.0"
|
|
24
|
+
"compatibility": "^1.6.0 || ^2.0.0"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@commitlint/cli": "^9.1.2",
|
|
28
|
-
"eslint": "
|
|
28
|
+
"eslint": "8.x",
|
|
29
29
|
"lint-staged": "^10.0.9",
|
|
30
|
-
"request": "^2.88.0"
|
|
30
|
+
"request": "^2.88.0",
|
|
31
|
+
"request-promise-native": "^1.0.9"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@commitlint/cli": "^9.1.2",
|
|
34
35
|
"@commitlint/config-angular": "^7.1.2",
|
|
35
36
|
"eslint": "^7.7.0",
|
|
36
|
-
"eslint-config-airbnb-base": "^
|
|
37
|
-
"eslint-
|
|
37
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
38
|
+
"eslint-config-nodebb": "0.1.1",
|
|
39
|
+
"eslint-plugin-import": "2.x",
|
|
38
40
|
"husky": "^2.4.0",
|
|
39
41
|
"lint-staged": "^10.0.9"
|
|
40
42
|
}
|
package/static/lib/admin.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
/* globals $, app, socket */
|
|
4
|
-
|
|
5
3
|
define('admin/plugins/tenor-gif', ['settings'], function (Settings) {
|
|
6
4
|
var ACP = {};
|
|
7
5
|
|
|
@@ -14,10 +12,7 @@ define('admin/plugins/tenor-gif', ['settings'], function (Settings) {
|
|
|
14
12
|
type: 'success',
|
|
15
13
|
alert_id: 'tenor-gif-saved',
|
|
16
14
|
title: 'Settings Saved',
|
|
17
|
-
|
|
18
|
-
clickfn: function () {
|
|
19
|
-
socket.emit('admin.reload');
|
|
20
|
-
},
|
|
15
|
+
timeout: 5000,
|
|
21
16
|
});
|
|
22
17
|
});
|
|
23
18
|
});
|
package/static/lib/main.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
/* globals $, document, window, socket, bootbox */
|
|
4
|
-
|
|
5
3
|
$(document).ready(function () {
|
|
6
4
|
var Tenor = {};
|
|
7
5
|
|
|
@@ -85,10 +83,6 @@ $(document).ready(function () {
|
|
|
85
83
|
});
|
|
86
84
|
|
|
87
85
|
queryEl.on('keyup', function () {
|
|
88
|
-
if (!queryEl.val().length) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
86
|
if (queryTimeout) {
|
|
93
87
|
clearTimeout(queryTimeout);
|
|
94
88
|
}
|
|
@@ -112,6 +106,9 @@ $(document).ready(function () {
|
|
|
112
106
|
callback(this.getAttribute('data-url'), queryEl.val());
|
|
113
107
|
modal.modal('hide');
|
|
114
108
|
});
|
|
109
|
+
|
|
110
|
+
// Start with empty query
|
|
111
|
+
queryEl.trigger('keyup');
|
|
115
112
|
});
|
|
116
113
|
});
|
|
117
114
|
};
|
|
@@ -123,10 +120,14 @@ $(document).ready(function () {
|
|
|
123
120
|
], function (formatting, controls) {
|
|
124
121
|
if (selectionStart === selectionEnd) {
|
|
125
122
|
controls.insertIntoTextarea(textarea, '');
|
|
126
|
-
controls.updateTextareaSelection(
|
|
123
|
+
controls.updateTextareaSelection(
|
|
124
|
+
textarea, selectionStart + query.length + 4, selectionEnd + query.length + url.length + 4
|
|
125
|
+
);
|
|
127
126
|
} else {
|
|
128
127
|
var wrapDelta = controls.wrapSelectionInTextareaWith(textarea, '');
|
|
129
|
-
controls.updateTextareaSelection(
|
|
128
|
+
controls.updateTextareaSelection(
|
|
129
|
+
textarea, selectionEnd + 4 - wrapDelta[1], selectionEnd + url.length + 4 - wrapDelta[1]
|
|
130
|
+
);
|
|
130
131
|
}
|
|
131
132
|
});
|
|
132
133
|
};
|
|
@@ -3,12 +3,28 @@
|
|
|
3
3
|
<div class="col-sm-2 col-xs-12 settings-header">General</div>
|
|
4
4
|
<div class="col-sm-10 col-xs-12">
|
|
5
5
|
<p class="lead">
|
|
6
|
-
Sign up for your Tenor GIF API Key
|
|
6
|
+
Sign up for your Tenor GIF API Key from the <a href="https://console.cloud.google.com/apis/credentials">Google Cloud Console</a>, then enter it below and reload your NodeBB.
|
|
7
|
+
</p>
|
|
8
|
+
<p>
|
|
9
|
+
<strong>Be careful</strong>: If you use the <i class="fa fa-copy"></i> button to copy the API key, it'll add spaces to the beginning and end. You'll need to remove those.
|
|
7
10
|
</p>
|
|
8
11
|
<div class="form-group">
|
|
9
12
|
<label for="key">API Key</label>
|
|
10
13
|
<input type="text" id="key" name="key" title="API Key" class="form-control" placeholder="API Key">
|
|
11
14
|
</div>
|
|
15
|
+
<div class="form-group">
|
|
16
|
+
<label for="contentFilter">Content Filter</label>
|
|
17
|
+
<select class="form-control" id="contentFilter" name="contentFilter">
|
|
18
|
+
<option value="off">Off</option>
|
|
19
|
+
<option value="low">Low</option>
|
|
20
|
+
<option value="medium" selected>Medium (default)</option>
|
|
21
|
+
<option value="high">High</option>
|
|
22
|
+
</select>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="form-group">
|
|
25
|
+
<label for="limit">Limit results</label>
|
|
26
|
+
<input class="form-control" type="number" min="1" max="50" id="limit" placeholder="10" name="limit" />
|
|
27
|
+
</div>
|
|
12
28
|
</div>
|
|
13
29
|
</div>
|
|
14
30
|
</form>
|
package/websockets.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const SocketPlugins = require.main.require('./src/socket.io/plugins');
|
|
4
4
|
SocketPlugins['tenor-gif'] = {};
|
|
5
5
|
|
|
6
6
|
module.exports.init = function () {
|
|
7
|
-
|
|
7
|
+
const main = module.parent.exports;
|
|
8
8
|
|
|
9
9
|
SocketPlugins['tenor-gif'].query = function (socket, data, callback) {
|
|
10
|
-
main.query(data.query
|
|
10
|
+
main.query(data.query).then((gifs) => {
|
|
11
|
+
callback(null, gifs);
|
|
12
|
+
}).catch(callback);
|
|
11
13
|
};
|
|
12
14
|
};
|
|
13
15
|
|