Skip to content

Commit 6ed1bc1

Browse files
committed
[ LUA ] adding Lua support for user scripts.
1 parent 4a92f24 commit 6ed1bc1

10 files changed

Lines changed: 596 additions & 82 deletions

File tree

assets/lua12.png

1.98 KB
Loading
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
local wbMusic = {
2+
NAME = "Music From Worm Blossom"
3+
}
4+
5+
--[[
6+
Auxiliary functions
7+
]]
8+
9+
function string:contains(sub)
10+
return self:find(sub, 1, true) ~= nil
11+
end
12+
13+
function string:startswith(start)
14+
return self:sub(1, #start) == start
15+
end
16+
17+
function string:endswith(ending)
18+
return ending == "" or self:sub(-#ending) == ending
19+
end
20+
21+
local function extractWormBlossomURL(text)
22+
local m = string.match(text, '[a-z]*://[^ \n >,;]*')
23+
24+
if string.startswith(m, "https://worm-blossom/#y") then
25+
return m
26+
else
27+
return false
28+
end
29+
end
30+
31+
32+
--[[
33+
Button actions add a button to a message if it "buttonAction"
34+
returns true
35+
36+
The action function is called if the user press the button.
37+
]]
38+
39+
function wbMusic.buttonAction(msg)
40+
if msg.content.type ~= "post" then
41+
return false
42+
end
43+
44+
local text = msg.value.content.text
45+
local url = extractWormBlossomURL(text)
46+
47+
if url then
48+
return true, "Open in Worm Blossom Player"
49+
else
50+
return false
51+
end
52+
end
53+
54+
function wbMusic.action(msg)
55+
local text = msg.value.content.text
56+
local url = extractWormBlossomURL(text)
57+
local content = fetch(url)
58+
if content then
59+
local iframe = querySelect("iframe")
60+
local src = getAttribute(iframe, "src")
61+
local song = getParam(src, "song")
62+
openWindow("music_player.html", {
63+
data = song
64+
})
65+
end
66+
end
67+
68+
--[[
69+
Menu adds a menu item to the "MORE" button.
70+
]]
71+
72+
function wbMusic.menuAction()
73+
return "All Worm Blossom Music"
74+
end
75+
76+
function wbMusic.menu()
77+
local opts = {
78+
query ={{
79+
["$filter"] = {
80+
value = {
81+
content = {
82+
channel = "worm-blossom",
83+
type = "post"
84+
}
85+
}
86+
},
87+
["$sort"] = {{"value","timestamp"}}
88+
}},
89+
limit = 100,
90+
reverse = true
91+
}
92+
local music = queryAndDrain(opts)
93+
94+
end
95+
96+
97+
return wbMusic

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const Menu = electron.Menu;
1717
const extend = require("xtend");
1818
const ssbKeys = require("ssb-keys");
1919
const announcements = require("./lib/announcements.js");
20+
const customScripts = require("./lib/depject/scripts/lua/custom-scripts.js");
2021

2122
require("@electron/remote/main").initialize();
2223

@@ -244,6 +245,9 @@ electron.app.on("ready", () => {
244245
if (announcements.available()) {
245246
windows.announcement = openAnnouncementsWindow();
246247
}
248+
249+
// custom scripts
250+
customScripts.copySamples();
247251
});
248252

249253
function openServerDevTools() {

lib/depject/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,5 +214,10 @@ module.exports = {
214214
tag: require("./tag/html/tag.js"),
215215
},
216216
},
217+
scripts: {
218+
lua: {
219+
environment: require("./scripts/lua/environment.js"),
220+
}
221+
}
217222
},
218223
};
Lines changed: 107 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,152 @@
1-
const { h, when } = require('mutant')
2-
const nest = require('depnest')
3-
const getRoot = require('../../../message/sync/root')
4-
const electron = require("electron")
1+
const { h, when } = require("mutant");
2+
const nest = require("depnest");
3+
const getRoot = require("../../../message/sync/root");
4+
const customScripts = require("../../scripts/lua/custom-scripts.js")
5+
const electron = require("electron");
56

67
exports.needs = nest({
7-
'intl.sync.i18n': 'first',
8-
'app.navigate': 'first',
9-
'message.obs.doesLike': 'first',
10-
'sbot.async.publish': 'first',
11-
'sheet.editTags': 'first'
12-
})
8+
"intl.sync.i18n": "first",
9+
"app.navigate": "first",
10+
"message.obs.doesLike": "first",
11+
"sbot.async.publish": "first",
12+
"sheet.editTags": "first",
13+
"scripts.lua.environment.init": "first",
14+
"scripts.lua.environment.call": "first",
15+
});
1316

14-
exports.gives = nest('message.html.actions')
17+
exports.gives = nest("message.html.actions");
1518

1619
exports.create = (api) => {
17-
const i18n = api.intl.sync.i18n
20+
const i18n = api.intl.sync.i18n;
1821

19-
return nest('message.html.actions', function like (msg) {
20-
const liked = api.message.obs.doesLike(msg.key)
22+
return nest("message.html.actions", function like(msg) {
23+
const liked = api.message.obs.doesLike(msg.key);
24+
25+
const customActions = []
26+
27+
const activeScripts = customScripts.getActiveScriptsList()
28+
29+
for (const script of activeScripts) {
30+
const L = api.scripts.lua.environment.init(script.name)
31+
const [r, label] = api.scripts.lua.environment.call(L, "buttonAction",[msg],2)
32+
if (r) {
33+
const button = h("a.lua -right", {
34+
href: "#",
35+
title: label,
36+
"ev-click": (ev) => {
37+
const [r, label] = api.scripts.lua.environment.call(L, "action",[msg],2)
38+
ev.preventDefault();
39+
},
40+
}, label)
41+
customActions.push(button)
42+
}
43+
}
2144

2245
return [
23-
when(liked,
24-
h('a.like -liked', {
25-
href: '#',
26-
title: i18n('Click to unlike'),
27-
'ev-click': () => publishLike(msg, false)
28-
}, i18n('Liked')),
29-
h('a.like', {
30-
href: '#',
31-
'ev-click': () => publishLike(msg, true)
32-
}, i18n('Like'))
46+
when(
47+
liked,
48+
h("a.like -liked", {
49+
href: "#",
50+
title: i18n("Click to unlike"),
51+
"ev-click": () => publishLike(msg, false),
52+
}, i18n("Liked")),
53+
h("a.like", {
54+
href: "#",
55+
"ev-click": () => publishLike(msg, true),
56+
}, i18n("Like")),
3357
),
34-
h('a.reply', {
58+
h("a.reply", {
3559
href: msg.key,
36-
anchor: 'reply',
37-
'ev-click': { handleEvent, api, msg }
38-
}, i18n('Reply')),
39-
h('a.tag -right', {
40-
href: '#',
41-
title: i18n('Add / Edit Tags'),
42-
'ev-click': () => api.sheet.editTags({ msgId: msg.key }, console.log)
43-
}, i18n('Tags')),
44-
when(messageHasAudio(msg),h('a.audio -right', {
45-
href: '#',
46-
title: i18n('Open in Audio Player'),
47-
'ev-click': (ev) => {
48-
openInPlayer(msg)
49-
ev.preventDefault()
50-
}
51-
}, i18n('Open in Audio Player')))
52-
]
53-
})
54-
55-
function publishLike (msg, status = true) {
60+
anchor: "reply",
61+
"ev-click": { handleEvent, api, msg },
62+
}, i18n("Reply")),
63+
h("a.tag -right", {
64+
href: "#",
65+
title: i18n("Add / Edit Tags"),
66+
"ev-click": () => api.sheet.editTags({ msgId: msg.key }, console.log),
67+
}, i18n("Tags")),
68+
when(
69+
messageHasAudio(msg),
70+
h("a.audio -right", {
71+
href: "#",
72+
title: i18n("Open in Audio Player"),
73+
"ev-click": (ev) => {
74+
openInPlayer(msg);
75+
ev.preventDefault();
76+
},
77+
}, i18n("Open in Audio Player")),
78+
),
79+
...customActions
80+
];
81+
});
82+
83+
function publishLike(msg, status = true) {
5684
const like = status
5785
? {
58-
type: 'vote',
59-
channel: msg.value.content.channel,
60-
vote: { link: msg.key, value: 1, expression: 'Like' }
61-
}
86+
type: "vote",
87+
channel: msg.value.content.channel,
88+
vote: { link: msg.key, value: 1, expression: "Like" },
89+
}
6290
: {
63-
type: 'vote',
64-
channel: msg.value.content.channel,
65-
vote: { link: msg.key, value: 0, expression: 'Unlike' }
66-
}
91+
type: "vote",
92+
channel: msg.value.content.channel,
93+
vote: { link: msg.key, value: 0, expression: "Unlike" },
94+
};
6795
if (msg.value.content.recps) {
6896
like.recps = msg.value.content.recps.map(function (e) {
69-
return e && typeof e !== 'string' ? e.link : e
70-
})
71-
like.private = true
97+
return e && typeof e !== "string" ? e.link : e;
98+
});
99+
like.private = true;
72100
}
73-
api.sbot.async.publish(like)
101+
api.sbot.async.publish(like);
74102
}
75-
}
103+
};
76104

77-
function handleEvent (ev) {
78-
const { api, msg } = this
79-
const el = getMessageElement(ev.target)
105+
function handleEvent(ev) {
106+
const { api, msg } = this;
107+
const el = getMessageElement(ev.target);
80108

81109
// HACK: if this is the last message in the list, reply to the root message
82110
if (el && !el.nextElementSibling) {
83-
api.app.navigate(getRoot(msg), 'reply')
84-
ev.preventDefault()
111+
api.app.navigate(getRoot(msg), "reply");
112+
ev.preventDefault();
85113
}
86114
}
87115

88-
function openInPlayer (msg) {
89-
console.log("open in player", msg)
90-
electron.ipcRenderer.send("open-in-audio-player", msg)
116+
function openInPlayer(msg) {
117+
console.log("open in player", msg);
118+
electron.ipcRenderer.send("open-in-audio-player", msg);
91119
}
92120

93-
function messageHasAudio (msg) {
121+
function messageHasAudio(msg) {
94122
if (!msg?.value?.content?.mentions) {
95-
return false
123+
return false;
96124
}
97125

98126
if (!Array.isArray(msg.value.content.mentions)) {
99-
return false
127+
return false;
100128
}
101129

102130
for (const mention of msg.value.content.mentions) {
103131
if (mention?.type && mention.type.startsWith("audio/")) {
104-
return true
132+
return true;
105133
}
106134

107135
if (mention?.name && mention.name.endsWith("mp3")) {
108-
return true
136+
return true;
109137
}
110138
}
111-
return false
139+
return false;
112140
}
113141

114-
function getMessageElement (el) {
142+
function getMessageElement(el) {
115143
while (el && el.classList) {
116-
if (el.classList.contains('Message') && el.parentNode && el.parentNode.classList.contains('replies')) {
117-
return el
144+
if (
145+
el.classList.contains("Message") && el.parentNode &&
146+
el.parentNode.classList.contains("replies")
147+
) {
148+
return el;
118149
}
119-
el = el.parentNode
150+
el = el.parentNode;
120151
}
121152
}

0 commit comments

Comments
 (0)