jimmywarting / StreamSaver.js

StreamSaver writes stream to the filesystem directly asynchronous
https://jimmywarting.github.io/StreamSaver.js/example.html
MIT License
3.97k stars 413 forks source link

How to Download album, which has set of images? #246

Closed desislellp closed 2 years ago

desislellp commented 2 years ago

Hi, I've created a short code with div which has set of images. I want to download this as album from the storage. This project is done in Laravel. Would be great if someone can help! Below is the code!

<ul id="gallery-albums">
                        <li class="album-cover-image mb-4" id="{{ $expense['title'] }}">
                            @foreach($expense['images'] as $img)
                                <a class="album-image-link" href='{{ asset("storage")."/".$img["file_name"] }}' data-lightbox="album-set" data-title="{{ $expense['title'] }}" ><img class="album-image" src='{{ asset("storage")."/".$img["file_name"] }}' alt=""/></a>
                            @endforeach
                            <h6 id="album-upload-title"><span class="title_oly">{{ $expense['title'] }}</span><span id="album-upload-date">{{ date('d-m-Y',strtotime($expense['date'])) }} <i class="bi bi-download m-lg-2 album" onclick="downloadAlbum()" cust="{{ $expense['images'] }}"></i></span></h6>
                        </li>
                    </ul>
function downloadAlbum() {
    const fileStream = streamSaver.createWriteStream('archive.zip')

        const file1 = new File(['file1 content'], 'streamsaver-zip-example/file1.txt')

        // File Like object works too
        const file2 = {
          name: 'streamsaver-zip-example/file2.txt',
          stream () {
            // if you want to play it cool and use new api's
            //
            // const { readable, writable } = new TextEncoderStream()
            // writable.write('file2 content')
            // writable.close()
            // return readable

            return new ReadableStream({
              start (ctrl) {
                ctrl.enqueue(new TextEncoder().encode('file2 generated with readableStream'))
                ctrl.close()
              }
            })
          }
        }

        const blob = new Blob(['support blobs too'])

        const file3 = {
          name: 'streamsaver-zip-example/blob-example.txt',
          stream: () => blob.stream()
        }

        // In a ideall world i would just have used a TransformStream
        // where you would get `{ readable writable } = new TransformStream()`
        // `readable` would be piped to streamsaver, and the writer would accept
        // file-like object, but that made it dependent on TransformStream and WritableStream
        // So i built ZIP-Stream simular to a ReadbleStream but you enqueue
        // file-like objects meaning it should have at at the very least { name, stream() }
        //
        // it supports pull() too that gets called when it ask for more files.
        //
        // NOTE: My zip library can't generate zip's over 4gb and has no compresseion
        //       it was built solo for the purpus of saving multiple files in browser
        //
        //       windows gets confused when file & folders starts with /
        const readableZipStream = new ZIP({
          start (ctrl) {
            ctrl.enqueue(file1)
            ctrl.enqueue(file2)
            ctrl.enqueue(file3)
            ctrl.enqueue({name: 'streamsaver-zip-example/empty folder', directory: true})
            // ctrl.close()
          },
          async pull (ctrl) {
            // Gets executed everytime zip.js asks for more data
            const url = '{{ asset("storage")."/".$img["file_name"] }}';
            const res = await fetch(url)
            const stream = () => res.body
            const name = '{{ $expense["title"] }}'

            ctrl.enqueue({ name, stream })

            // if (done adding all files)
            ctrl.close()
          }
        })

        // more optimized
        if (window.WritableStream && readableZipStream.pipeTo) {
          return readableZipStream.pipeTo(fileStream).then(() => console.log('done writing'))
        }

        // less optimized
        const writer = fileStream.getWriter()
        const reader = readableZipStream.getReader()
        const pump = () => reader.read()
          .then(res => res.done ? writer.close() : writer.write(res.value).then(pump))

        pump()  
  }
desislellp commented 2 years ago

Hi, can someone please help me with this issue? Would be great help! Thanks

jimmywarting commented 2 years ago

Can you strip it down to the things you don't need?

seems like you only want to download stuff from urls? maybe this can help u?

const urls = [
    { name: '...', url: '...' },
    { name: '...', url: '...' },
    { name: '...', url: '...' }
].values()

const readableZipStream = new ZIP({
    async pull (ctrl) {
        const next = urls.next()
        if (next.done) return ctrl.close()
        const res = await fetch(next.value.url)
        const stream = () => res.body
        const name = next.value.name

        ctrl.enqueue({ name, stream })
        ctrl.close()
    }
})
desislellp commented 2 years ago

Thanks for the response jimmy. So the problem is, when user uploads multiple photos for a task, it saves all photos of that particular task as an album. And now I want that user to download that particular task album which has multiple images present in it. Can you please give an advice how to do this? Thanks in advance.

jimmywarting commented 2 years ago

show me what you have tried so far, i can't help you if you don't give me something to go on

jimmywarting commented 2 years ago

it's behind a lock login screen.

can you please turn to stackoverflow for this kind of questions?