Skip to content

Commit 5e3e78c

Browse files
committed
Add hotkey functionality
Rework browser source and lua script to enable hotkey control Update readme
1 parent a10b85b commit 5e3e78c

File tree

4 files changed

+368
-88
lines changed

4 files changed

+368
-88
lines changed

BrowserImageSlideshow.html

Lines changed: 107 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,14 @@
6464
topImage.id = "topImage";
6565
botImage.id = "botImage";
6666

67-
// prevent white outline by setting initial transparency
68-
topImage.style.opacity = "0.0";
69-
botImage.style.opacity = "0.0";
70-
7167
let fadeDuration = slideDuration * 0.25;
7268
let slideshowFunc;
7369
let index = 0;
7470
let fadeInTop = true; // bool for deciding if top image fades in or out
75-
71+
let isSlideshowPaused = false;
72+
let isSlideshowVisible = true;
73+
let isTransitionInProgress = false; // skip animation if already in progress
74+
7675
function shuffle(a) {
7776
for (let i = a.length - 1; i > 0; i--) {
7877
const j = Math.floor(Math.random() * (i + 1));
@@ -85,6 +84,7 @@
8584
index = Math.floor(Math.random() * max); // [0, max)
8685
}
8786

87+
// called each interval of setInterval()
8888
function update() {
8989
if (index === images.length-1 && stopOnLastImage === true) {
9090
clearInterval(slideshowFunc);
@@ -103,44 +103,125 @@
103103
fadeInImage(imageSrc);
104104
}
105105

106+
function getPreviousSlide() {
107+
index = index === 0 ? images.length - 1 : index - 1;
108+
let imageSrc = images[indexes[index]];
109+
fadeInImage(imageSrc);
110+
}
111+
106112
function fadeInImage(imageSrc) {
107113
if (fadeInTop) { topImage.src = imageSrc; }
108114
else { botImage.src = imageSrc; }
109115

110-
const botTarget = fadeInTop ? 0.0 : 1.0;
111-
const topTarget = fadeInTop ? 1.0 : 0.0;
116+
if (isTransitionInProgress) {
117+
$("#topImage").stop(true, true);
118+
$("#botImage").stop(true, true);
119+
}
112120

121+
isTransitionInProgress = true;
113122
$("#botImage").animate(
114-
{ opacity: botTarget },
123+
{ opacity: fadeInTop ? 0.0 : 1.0 },
115124
{ duration: fadeDuration }
116125
);
117126

118127
$("#topImage").animate(
119-
{ opacity: topTarget },
120-
{ duration: fadeDuration }
128+
{ opacity: fadeInTop ? 1.0 : 0.0 },
129+
{
130+
duration: fadeDuration,
131+
done: function() {
132+
isTransitionInProgress = false;
133+
}
134+
}
121135
);
122-
136+
123137
fadeInTop = !fadeInTop;
124138
}
125139

126-
if (mode === 0) { // random mode
127-
shuffle(indexes);
128-
} else if (mode === 2) { // choose random image to start on
129-
randomizeIndex(images.length);
140+
function pause() {
141+
console.log("pause");
142+
if (isSlideshowPaused) return;
143+
clearInterval(slideshowFunc);
144+
isSlideshowPaused = true;
130145
}
131146

132-
// if only 1 image in slide show, fade in the image
133-
if (images.length > 0) {
134-
botImage.src = images[indexes[0]];
135-
136-
$("#botImage").animate(
137-
{ opacity: 1.0 },
138-
{ duration: fadeDuration }
139-
);
147+
function resume() {
148+
if (!isSlideshowPaused) return;
149+
update(); // trigger a single update to fill setInterval delay
150+
slideshowFunc = setInterval(update, slideDuration);
151+
isSlideshowPaused = false;
140152
}
141153

142-
// start slideshow
143-
if (images.length > 1) {
144-
slideshowFunc = setInterval(update, slideDuration);
154+
function restart() {
155+
$("#topImage").stop(true, true);
156+
$("#botImage").stop(true, true);
157+
clearInterval(slideshowFunc);
158+
start();
159+
}
160+
161+
// called once when the browser source loads or restarts
162+
function start() {
163+
topImage.style.opacity = "0.0";
164+
botImage.style.opacity = "0.0";
165+
166+
if (images.length > 0) { // if at least 1 image, show the first image
167+
168+
if (mode === 0) { // random mode
169+
shuffle(indexes);
170+
} else if (mode === 2) { // choose random image to start on
171+
randomizeIndex(images.length);
172+
}
173+
174+
botImage.src = images[indexes[index]];
175+
$("#botImage").animate(
176+
{ opacity: 1.0 },
177+
{ duration: fadeDuration }
178+
);
179+
}
180+
181+
if (startWithAutoplay && images.length > 1) {
182+
slideshowFunc = setInterval(update, slideDuration);
183+
} else {
184+
isSlideshowPaused = true;
185+
}
145186
}
187+
188+
start();
189+
190+
// handle hotkey events from OBS
191+
document.addEventListener("keydown", (event) => {
192+
let key = "";
193+
try { key = event.key; }
194+
catch (error) {
195+
console.log(error);
196+
return;
197+
}
198+
199+
switch (key) {
200+
case "1": pause(); break;
201+
case "2": resume(); break;
202+
case "3": getNextSlide(); break;
203+
case "4": getPreviousSlide(); break;
204+
case "5": // toggle visibilty
205+
if (isSlideshowVisible) {
206+
imageContainer.style.opacity = 0.0;
207+
isSlideshowVisible = false;
208+
} else {
209+
imageContainer.style.opacity = 1.0;
210+
isSlideshowVisible = true;
211+
}
212+
break;
213+
case "6": // toggle pause
214+
if (isSlideshowPaused) {
215+
resume();
216+
} else {
217+
pause();
218+
}
219+
break;
220+
case "7": restart(); break;
221+
default:
222+
console.log("Unhandled hotkey: " + key);
223+
break;
224+
}
225+
});
226+
146227
</script>

README.txt

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,70 @@ BrowserImageSlideshow
22
https://github.com/dustymethod/BrowserImageSlideshow
33
Discussion & support: https://obsproject.com/forum/threads/browser-image-slideshow.110157/
44

5-
A local browser source that plays images in random or alphabetical order.
6-
Displays each image exactly once per loop.
7-
Useful for slideshows that may exceed OBS's slideshow's 250mb ram limit. Works offline.
5+
A slideshow that can be added to OBS as a browser source.
6+
- Plays images in random or alphabetical order, or manually via hotkeys in OBS
7+
- Displays each image exactly once per loop
8+
- local, works offline
9+
Useful for slideshows that may exceed 250mb uncompressed limit in OBS's current built-in slideshow
810

9-
settings.js (open in any text editor. ex right click > Open with > Notepad)
11+
> Setup
12+
0. Download the latest release https://github.com/dustymethod/BrowserImageSlideshow/releases
13+
1. Add browser source in OBS:
14+
+ Add Source > Browser
15+
- Choose local file "BrowserImageSlideshow.html"
16+
- Delete Custom CSS
17+
- Enable "Shutdown source when not visible" and "Refresh browser when scene becomes active" options
18+
2. Place your slideshow images in the "images" folder (ex. png, jpg, gif)
19+
3. Add lua script (optional)
20+
- OBS > Tools > Scripts > Add (+) SlideshowSettings.lua
21+
- adjust settings, and enter name of slideshow browser source (if using hotkeys)
22+
4. Update slideshow & list of images
23+
This can be done 2 different ways, and must be done whenever images are added/removed/renamed, or slideshow settings are changed
24+
25+
A) With Lua script in OBS:
26+
- Press the Refresh button in the script's settings, or press the Refresh hotkey
27+
28+
B) Without Lua:
29+
- Run RefreshImagesW.cmd or RefreshImages.sh to update the list of images (they do the same thing)
30+
- Refresh the browser source by toggling its visibility from the Sources dock in OBS
31+
- settings can be adjusted by opening settings.js in a text editor
32+
5. *** Repeat step 4 whenever you add/remove/rename images or update the settings! ***
33+
34+
> settings.js
1035
mode:
1136
0: Random order (default)
1237
1: Alphabetical order
1338
2: Alphabetical order (start on random image)
1439
slideDuration: duration in milliseconds (default 4000)
1540
stopOnLastImage: if true, the slideshow will not repeat. (default false)
16-
41+
startWithAutoplay: if true, the slideshow will start playing automatically. untick this option if you wish to control slides manually via hotkeys.
42+
autoplaying/paused can be toggled with hotkeys, regardless if this option is enabled or not
1743

18-
Setup
19-
0. Download the zipped files from github or the releases page
20-
- save & unzip somewhere in your Documents folder (not in obs plugins folder)
21-
1. Add a browser source in OBS:
22-
- Add Source > Browser
23-
- Choose local file "BrowserImageSlideshow.html"
24-
- Remove Custom CSS
25-
- Enable "Shutdown source when not visible" and "Refresh browser when scene becomes active" options.
26-
2. Place your slideshow images in the "images" folder (ex. jpg, png, gif)
27-
3. (Optional) Add the lua script:
28-
- in OBS Studio: Tools > Scripts
29-
- Add RefreshImagesLua.lua, select the script to view and change settings.
30-
- this is purely an alternative to using RefreshImagesW.cmd or RefreshImages.sh in step 4
31-
4. Refreshing images/settings
32-
- This must be done whenever images are added/removed/renamed, or when settings are updated.
33-
- Run RefreshImagesW.cmd (windows) or RefreshImages.sh (linux) by double-clicking it.
34-
- (optional) Or, if using lua script: select RefreshImagesLua.lua & press Reload Scripts button next to +-
35-
- Finally, refresh the source in OBS by toggling its visibility
36-
5. *** Repeat step 4 whenever you add/remove/rename images or update the settings! ***
44+
> Additional Lua Settings
45+
Browser source name: this tells the lua script which browser source to send hotkey events to. you can ignore this setting if not using hotkeys
3746

47+
> Hotkeys - Requires lua script (see step 3)
48+
Pause: pause playback
49+
Resume: resume playback (if autoplay setting is off, this will still enable autoplay)
50+
Next: show the next slide
51+
Previous: show the previous slide
52+
Toggle visible: hide/show slideshow without pausing/restarting
53+
Toggle pause: same as pause/resume, but on a single hotkey
54+
Restart: restart the slideshow without checking for new images or settings
55+
Refresh: refresh browser source & restart slideshow. changes to images & settings will be reflected
3856

39-
Notes
40-
- Adding RefreshImageLua.lua to OBS Studio is optional. If not using lua, refreshing images & settings can be done
41-
by running RefreshImages.sh or RefreshImagesW.cmd
42-
- Updating settings via the lua script will overwrite settings.js.
43-
- The optional lua script may not work with OBS on Linux; please use RefreshImages.sh instead.
57+
> Notes & tips
58+
- Save slideshow somewhere that doesn't require admin permissions, such as in your Documents, and not in the default plugins folder
4459
- Filenames with uncommon characters may not display
60+
- Images in subfolders within the "images" folder will not be shown
61+
- RefreshImages.sh and RefreshImagesW.cmd do the same thing; make a list of files within the images folder. depending on your pc, you may be able to run one, but not the other
62+
- This slideshow & its scripts write to settings.js and images/images.js
4563
- EXIF data is ignored; images taken with a camera may not appear rotated correctly
46-
- RefreshImages: these scripts will write the names of all images to a text file, which is used by the browser source.
4764
- This resource has only been tested on Windows. I have not done extensive testing
48-
- RefreshImages.sh and RefreshImagesW.cmd do the same thing. one was added later because of compatibility issues
49-
50-
This script uses compressed jquery (used for animating slide transitions)
65+
- if using multiple slideshows, copy the entire slideshow folder, rathern than individual scripts, and add to OBS.
66+
67+
This script uses compressed jquery
5168
https://jquery.com/
52-
53-
Issues
54-
- because of the way script(s) write to a file, a harmless command window may pop up briefly when the script is run.
55-
Haven't found a way to suppress this yet.
69+
70+
> Issues
71+
- because of the way script(s) write to a file, a harmless command window may pop up briefly when the script is run. Haven't found a way to suppress this yet.

0 commit comments

Comments
 (0)