The frame data for Ugoira files is stored like this:
[{"file"=>"000000.jpg", "delay"=>65},
{"file"=>"000001.jpg", "delay"=>65},
{"file"=>"000002.jpg", "delay"=>65},
{"file"=>"000003.jpg", "delay"=>65},
{"file"=>"000004.jpg", "delay"=>65},
{"file"=>"000005.jpg", "delay"=>65},
{"file"=>"000006.jpg", "delay"=>65},
{"file"=>"000007.jpg", "delay"=>65},
{"file"=>"000008.jpg", "delay"=>65},
{"file"=>"000009.jpg", "delay"=>65},
{"file"=>"000010.jpg", "delay"=>65}]
This is stored in the pixiv_ugoira_frame_data table in YAML format. This
is a problem because a) we only need the frame delays to play the Ugoira,
not the filenames, and b) storing the data in YAML format is a security
issue that's blocking the upgrade to Rails 7.0.4 (see [1]).
This commit changes the Ugoira Javascript player so that it only uses
the list of frame delays, not the filenames, to play the Ugoira. This
paves the way for storing the frame delays as a simple integer array
instead as a serialized YAML object.
This assumes that the images in a Ugoira zip file are stored in the same
order they should be played back in. This was confirmed by checking every
zip file and verifying that files are actually stored in filename order.
[1]: https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
76 lines
1.9 KiB
JavaScript
76 lines
1.9 KiB
JavaScript
import { ZipImagePlayer } from '../../vendor/pixiv-ugoira-player';
|
|
require("jquery-ui/ui/widgets/progressbar");
|
|
require("jquery-ui/ui/widgets/slider");
|
|
require("jquery-ui/themes/base/progressbar.css");
|
|
require("jquery-ui/themes/base/slider.css");
|
|
|
|
let Ugoira = {};
|
|
|
|
Ugoira.create_player = (frames, file_url) => {
|
|
var meta_data = {
|
|
frames: frames
|
|
};
|
|
var options = {
|
|
canvas: $("#image")[0],
|
|
source: file_url,
|
|
metadata: meta_data,
|
|
chunkSize: 300000,
|
|
loop: true,
|
|
autoStart: true,
|
|
debug: false,
|
|
}
|
|
|
|
Ugoira.player = new ZipImagePlayer(options);
|
|
Ugoira.player_manually_paused = false;
|
|
|
|
$(Ugoira.player).on("loadProgress.danbooru", (ev, progress) => {
|
|
$("#seek-slider").progressbar("value", Math.floor(progress * 100));
|
|
});
|
|
|
|
$("#ugoira-play").on("click.danbooru", e => {
|
|
Ugoira.player.play();
|
|
$("#ugoira-play").hide();
|
|
$("#ugoira-pause").show();
|
|
Ugoira.player_manually_paused = false;
|
|
e.preventDefault();
|
|
})
|
|
|
|
$("#ugoira-pause").on("click.danbooru", e => {
|
|
Ugoira.player.pause();
|
|
$("#ugoira-pause").hide();
|
|
$("#ugoira-play").show();
|
|
Ugoira.player_manually_paused = true;
|
|
e.preventDefault();
|
|
});
|
|
|
|
$("#seek-slider").progressbar({
|
|
value: 0
|
|
});
|
|
|
|
$("#seek-slider").slider({
|
|
min: 0,
|
|
max: Ugoira.player._frameCount - 1,
|
|
start: (event, ui) => {
|
|
// Need to pause while slider is being dragged or playback speed will bug out
|
|
Ugoira.player.pause();
|
|
},
|
|
slide: (event, ui) => {
|
|
Ugoira.player._frame = ui.value;
|
|
Ugoira.player._displayFrame();
|
|
},
|
|
stop: (event, ui) => {
|
|
// Resume playback when dragging stops, but only if player was not paused by the user earlier
|
|
if (!(Ugoira.player_manually_paused)) {
|
|
Ugoira.player.play();
|
|
}
|
|
}
|
|
});
|
|
|
|
$(Ugoira.player).on("frame.danbooru", (frame, frame_number) => {
|
|
$("#seek-slider").slider("option", "value", frame_number);
|
|
});
|
|
}
|
|
|
|
export default Ugoira;
|
|
|