1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-11-09 19:52:16 +00:00

Add support for downloadong folders and albums

Ref #131
This commit is contained in:
spl0k 2019-01-13 17:18:27 +01:00
parent 6b86f3a43a
commit 25c5c8277e
3 changed files with 35 additions and 4 deletions

View File

@ -21,7 +21,8 @@ reqs = [
'pony>=0.7.6', 'pony>=0.7.6',
'Pillow', 'Pillow',
'requests>=1.0.0', 'requests>=1.0.0',
'mutagen>=1.33' 'mutagen>=1.33',
'zipstream'
] ]
extras = { extras = {
'watcher': [ 'watchdog>=0.8.0' ] 'watcher': [ 'watchdog>=0.8.0' ]

View File

@ -14,11 +14,15 @@ import os.path
import requests import requests
import shlex import shlex
import subprocess import subprocess
import uuid
from flask import request, Response, send_file from flask import request, Response, send_file
from flask import current_app from flask import current_app
from PIL import Image from PIL import Image
from pony.orm import ObjectNotFound
from xml.etree import ElementTree from xml.etree import ElementTree
from zipfile import ZIP_DEFLATED
from zipstream import ZipFile
from .. import scanner from .. import scanner
from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now
@ -129,8 +133,29 @@ def stream_media():
@api.route('/download.view', methods = [ 'GET', 'POST' ]) @api.route('/download.view', methods = [ 'GET', 'POST' ])
def download_media(): def download_media():
res = get_entity(Track) id = request.values['id']
return send_file(res.path, mimetype = res.content_type, conditional=True) uid = uuid.UUID(id)
try: # Track -> direct download
rv = Track[uid]
return send_file(rv.path, mimetype = rv.content_type, conditional=True)
except ObjectNotFound:
pass
try: # Folder -> stream zipped tracks, non recursive
rv = Folder[uid]
except ObjectNotFound:
try: # Album -> stream zipped tracks
rv = Album[uid]
except ObjectNotFound:
raise NotFound('Track, Folder or Album')
z = ZipFile(compression = ZIP_DEFLATED)
for track in rv.tracks:
z.write(track.path, os.path.basename(track.path))
resp = Response(z, mimetype = 'application/zip')
resp.headers['Content-Disposition'] = 'attachment; filename={}.zip'.format(rv.name)
return resp
@api.route('/getCoverArt.view', methods = [ 'GET', 'POST' ]) @api.route('/getCoverArt.view', methods = [ 'GET', 'POST' ])
def cover_art(): def cover_art():

View File

@ -89,8 +89,8 @@ class MediaTestCase(ApiTestBase):
self._make_request('download', error = 10) self._make_request('download', error = 10)
self._make_request('download', { 'id': 'string' }, error = 0) self._make_request('download', { 'id': 'string' }, error = 0)
self._make_request('download', { 'id': str(uuid.uuid4()) }, error = 70) self._make_request('download', { 'id': str(uuid.uuid4()) }, error = 70)
self._make_request('download', { 'id': str(self.folderid) }, error = 70)
# download single file
rv = self.client.get('/rest/download.view', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests', 'id': str(self.trackid) }) rv = self.client.get('/rest/download.view', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests', 'id': str(self.trackid) })
self.assertEqual(rv.status_code, 200) self.assertEqual(rv.status_code, 200)
self.assertEqual(rv.mimetype, 'audio/mpeg') self.assertEqual(rv.mimetype, 'audio/mpeg')
@ -98,6 +98,11 @@ class MediaTestCase(ApiTestBase):
with db_session: with db_session:
self.assertEqual(Track[self.trackid].play_count, 0) self.assertEqual(Track[self.trackid].play_count, 0)
# dowload folder
rv = self.client.get('/rest/download.view', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests', 'id': str(self.folderid) })
self.assertEqual(rv.status_code, 200)
self.assertEqual(rv.mimetype, 'application/zip')
def test_get_cover_art(self): def test_get_cover_art(self):
self._make_request('getCoverArt', error = 10) self._make_request('getCoverArt', error = 10)
self._make_request('getCoverArt', { 'id': 'string' }, error = 0) self._make_request('getCoverArt', { 'id': 'string' }, error = 0)