Touffy / client-zip

A client-side streaming ZIP generator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] Zipped file is empty

mrtnvgr opened this issue · comments

Describe the bug

Hi! For some reason my zipped files are always empty.

To Reproduce

Code snippet
import { downloadZip } from "https://cdn.jsdelivr.net/npm/client-zip/index.js";

async function initRecorder() {
	window._recordings = [];
	window._chunks = [];

	try {
		let audio_stream = await navigator.mediaDevices.getUserMedia({ audio: true });
		window._recorder = new MediaRecorder(audio_stream);
	} catch (e) {
		console.log(e);
		alert("Failed to get microphone permissions\nYour answers won't be recorded");
		return;
	}

	_recorder.ondataavailable = (e) => {
		_chunks.push(e.data);
	};

	_recorder.onstop = (e) => {
		let blob = new Blob(_chunks);

		let task_directory = `Task ${current_task}`;

		let count = 0;
		for (let recording of _recordings) {
			if (recording.name.includes(task_directory)) {
				count++;
			}
		}

		_recordings.push({
			name: `${task_directory}/${count+1}.ogg`,
			input: blob,
		})

		_chunks = [];
	};
}

async function showDownloadPage() {
	console.log(_recordings);
	let blob = await downloadZip(_recordings).blob();
	console.log(blob);
        ...
}

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
20231203_19h25m50s_grim

Desktop:

  • OS: Linux
  • Browser: firefox
  • Version: 119.0.1

Additional context
Add any other context about the problem here.

Oh, thats interesting. It seems that multiple files zipping works just fine 🤔

20231203_20h52m20s_grim

So… does the empty archive occur only when you add a single file ?

I can't spot anything wrong with your code, anyway.

So… does the empty archive occur only when you add a single file ?

I can't spot anything wrong with your code, anyway.

Yep

When debugging I found out that _recordings.length appears to be incorrect for some reason...

async function showDownloadPage() {
	console.log(_recordings);

	// TODO: https://github.com/Touffy/client-zip/issues/79
	if (_recordings.length == 1) {
		_recordings.push({ name: "ignore_me", input: "nothing" });
		console.log(_recordings);
	} else {
		console.warn(_recordings.length);
	}

	let blob = await downloadZip(_recordings).blob();
	console.log(blob);
        ...

20231206_20h51m12s_grim

...
console.warn(_recordings.length, _recordings);
...

20231206_21h04m07s_grim

@Touffy I'm not good in javascript, would you mind helping me please?

The issue seems to be with the _recordings array. Because it has apparently a length of 0, even though it contains an item. There may be some corruption of Array.prototype in your surrounding code, or something weird when * _recordings* is created. I cannot understand the issue without seeing more code.

One way to get that strange behaviour would be to set _recordings.length to zero explicitly… perhaps somewhere in a condition you wrote _recordings.length = 0 instead of _recordings.length == 0 ? (though that should also remove the item) Nevermind, there is clearly no such thing in your code. So what's left is some other library on your page doing something weird to Array.prototype.

The issue seems to be with the _recordings array. Because it has apparently a length of 0, even though it contains an item. There may be some corruption of Array.prototype in your surrounding code, or something weird when * _recordings* is created. I cannot understand the issue without seeing more code.

One way to get that strange behaviour would be to set _recordings.length to zero explicitly… perhaps somewhere in a condition you wrote _recordings.length = 0 instead of _recordings.length == 0 ? (though that should also remove the item)

Thanks for your help, here is the full file

Ah ! I think I found it. You are calling showDownloadPage() too soon. _recordings is empty when the archive is created (set a breakpoint at the call to downloadZip — after the await — and you will see).

But console.log is somewhat asynchronous when you give it an object, and shows the contents of _recordings at the time when the browser actually renders the message, not the instant when you called console.log. In that tiny amount of time, _recordings has been updated, so you see an array with one item in your console.

breakpoint

The _recorder.onstop event is triggered immediately after that, and that's where you push the recording to the array.

Oh, thank you so much! ❤️

What is the best way to fix this? To wait until the event hooks are finished their tasks? How can I do it?

Maybe a custom state attribute, something like processing?

All fixed now, thanks again!