how to store image / video file using gundb?

2.7k Views Asked by At

I know the traditional way is to store image/video file in one place and then just save the reference index into db's table.

Now I am learning about gundb, I can store key-value json type data very easily, but since it is decentralized, if I wanna make a say chatroom app, how should I handle image storing (eg: user's avatar)?

I am also wondering if it is possible to make a movie-sharing app using gundb?

2

There are 2 best solutions below

1
On BEST ANSWER

@Retric, great question! I'm not sure why people are downvoting you, they must be haters.

You are right, it is better to store that image/video and reference it via GUN. For videos specifically, WebTorrent/BitTorrent has done P2P video sharing for over a decade now and at one point handled 40% of the world's internet traffic!

However WebTorrent/BitTorrent is not very good with discovering/sharing those URIs (magnet links, etc.) but GUN is. So I'd recommend that as one option.

For images, especially small ones like avatars/icons/profiles, I do often store them in GUN directly by Base64 encoding them (many websites around the world inline images/icons/sprites/avatars into CSS files with base64 data-URLs, except now you could use GUN for this).

If you are interested in this, I wrote a small utility using jQuery that lets you drag&drop images into your website, and it'll auto-resize (pass options to overwrite it) and base64 encode it for you to then save to GUN:

https://github.com/amark/gun/blob/master/lib/upload.js

Here is a small example of how I use it:

$('#profile').upload(function resize(e, up){
    if(e.err){ return } // handle error
    $('#profile').addClass('pulse'); // css to indicate image processing
    if(up){ return up.shrink(e, resize, 64) } // pass it `e` drag&drop/upload event, then I reuse the current function (named resize) as the callback for it, and tell it resize to 64px.
    $('#profile').removeClass('pulse'); // css indicate done processing.
    $("#profile img").attr('src', e.base64).removeClass('none'); // set photo in HTML!
    gun.user().get('who').get('face').get('small').put(e.base64); // save profile thumbnail to GUN
});

Finally, what about storing videos in GUN if you don't want to use BitTorrent?

I would highly recommend using the HLS format to store videos in GUN, this would allow you to do decentralized realtime video streaming. It is a beautifully simple format that allows video streaming to work even from static files, because it stores the video in small chunks that can be streamed - which fits perfectly with GUN.

There already is a JS based video-player for the HLS format:

https://github.com/video-dev/hls.js/

Based off the demo page, you can see an example of how the video is stored, like here on GitHub:

https://github.com/video-dev/streams/tree/master/x36xhzz

(if you click on the m3u8 file, you'll see it has metadata that 720p is stored in url_0 folder, which themselves have sub-files)

Rather than storing the HLS video files on BitTorrent or a centralized server, you could store it in GUN using the same folder structure gun.get('videos').get('x36xhzz').get('url_0').get('url_496').get('193039199_mp4_h264_aac_hd_7.ts').once(function(video_chunk){ passToHLSplayer(video_chunk) }) such that it would be easy for HLS.js to integrate with GUN.

Now you'll have P2P decentralized video streaming!!!

And even cooler, you can combine it with GUN's lib/webrtc adapter and do this fully browser to browser!

I hope this helped.

0
On

The thing to understand here is the difference between content addressed space (frozen space) and user space in gun.

Let's say you have some media encoded as base64, and you know its content type (I've used text here to keep example short, but you could use image video etc):

// put avatar in frozen space:
let media = JSON.stringify({ b64 : "U2hlIHdhcyBib3JuIGFuIGFkdmVudHVyZXIuLi4=", type : "text/plain"})
// get hash of stringified media obj using gun's SEA lib:
let mediaID = await SEA.work(media, null, null, {name: "SHA-256"});
// put media in hash-addressed gundb
gun.get('#').get(mediaID).put(media,(r)=>console.log('Media put acknowledged?',r))

For a hypothetical chat app, you could use user space and put the media under the "avatar" name:

// put avatar in user space:
let user = await SEA.pair();
await gun.user().auth(user) 
gun.get('~' + user.pub).get('avatar').put('#' + mediaID)

// retrieve a user's avatar
gun.get('~' + usera.pub).get('avatar').once((hashid,k)=>{
    gun.get('#').get(hashid).once(media=>{
      console.log("Got user's avatar :-)",media)
      //do something with media
    })
})