FileSystem.createDownloadResumable Callback - Help

#1

Hi all.

I’ve spent the last couple of days trying to figure out a solution to this, and I’m really struggling to come up with anything.

Basically, in my app, I have a downloadSong Redux action creator that gets a link from an external API and downloads a file from it. The files download just fine, but the callback that provides download progress data is behaving strangely.

The first run goes as expected - the file downloads correctly, and the callback gets called until download completion, correctly updating download progress along the way.

For any subsequent downloads, the callback is called until the new download ends, but callbacks for previous (completed) downloads are also called simultaneously.

The callbacks from previous downloads contain new totalBytesWritten / totalBytesExpectedToWrite values, but the _id value is the same as when the callback was originally passed to createDownloadResumable.

Ultimately the reducer receives the following actions from the callbacks, and I really don’t understand why the callback is firing for old downloads as well as current.

{
    type: UPDATE_DOWNLOAD_PROGRESS,
    payload: {
      songId: VALUE FROM PREVIOUSLY COMPLETED DOWNLOAD,
      totalBytesWritten: VALUE FROM NEW DOWNLOAD,
      totalBytesExpectedToWrite: VALUE FROM NEW DOWNLOAD
    }
}
{
    type: UPDATE_DOWNLOAD_PROGRESS,
    payload: {
      songId: VALUE FROM NEW DOWNLOAD,
      totalBytesWritten: VALUE FROM NEW DOWNLOAD,
      totalBytesExpectedToWrite: VALUE FROM NEW DOWNLOAD
    }
}

The same thing also happens with simultaneous downloads. The callback for the older downloads starts getting called with totalBytesWritten / totalBytesExpectedToWrite for the newest download. Again, why?

All I want is the callbacks to fire independently of other downloads. The file themselves actually download properly and independently from each other, so I don’t understand why the callbacks are different.

If anyone has any ideas, solutions, or tips regarding this, I would be eternally grateful!

The appropriate code can be seen below.

export const downloadSong = song => async dispatch => {
  const { youTubeUrl, _id } = song;
  dispatch(downloadSongStart(_id));

    let { data } = await axios.get(`http://www.youtubeinmp3.com/fetch/?format=json&video=${youTubeUrl}`);
    let { link } = data;

    const callback = ({ totalBytesWritten, totalBytesExpectedToWrite }) => dispatch(updateDownloadProgress(
      _id,
      totalBytesWritten,
      totalBytesExpectedToWrite
    ));

    const downloadResumable = FileSystem.createDownloadResumable(
      link,
      FileSystem.documentDirectory + `${_id}.mp3`,
      {},
      callback
    );

    const { uri } = await downloadResumable.downloadAsync();
    console.log('Finished downloading to ', uri);

    const updatedSong = { ...song, localUri: uri, downloadedOn: Date.now() };
    return dispatch(downloadSongSuccess(updatedSong));

  } catch (err) {
    console.log(err);
    dispatch(downloadSongFailure(song, err));
  }
};


const updateDownloadProgress = (songId, totalBytesWritten, totalBytesExpectedToWrite) => {
  return {
    type: UPDATE_DOWNLOAD_PROGRESS,
    payload: {
      songId,
      totalBytesWritten,
      totalBytesExpectedToWrite,
    }
  };
};
0 Likes

#2

Hello,

We found this bug as well. The callback is being fired without any regard to the id of the download. The fix will be included in the next release which is about 2 weeks away.

1 Like

#3

That’s great news! I’ll keep my eyes peeled.

0 Likes