mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
Don't store the mimetype in database
That's useless, it can be deduced from the path Fixes #150
This commit is contained in:
parent
deaf17a005
commit
10df0ada07
@ -3,7 +3,7 @@
|
|||||||
# This file is part of Supysonic.
|
# This file is part of Supysonic.
|
||||||
# Supysonic is a Python implementation of the Subsonic server API.
|
# Supysonic is a Python implementation of the Subsonic server API.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2013-2018 Alban 'spl0k' Féron
|
# Copyright (C) 2013-2019 Alban 'spl0k' Féron
|
||||||
# 2018-2019 Carey 'pR0Ps' Metcalfe
|
# 2018-2019 Carey 'pR0Ps' Metcalfe
|
||||||
#
|
#
|
||||||
# Distributed under terms of the GNU AGPLv3 license.
|
# Distributed under terms of the GNU AGPLv3 license.
|
||||||
@ -65,7 +65,7 @@ def stream_media():
|
|||||||
src_suffix = res.suffix()
|
src_suffix = res.suffix()
|
||||||
dst_suffix = res.suffix()
|
dst_suffix = res.suffix()
|
||||||
dst_bitrate = res.bitrate
|
dst_bitrate = res.bitrate
|
||||||
dst_mimetype = res.content_type
|
dst_mimetype = res.mimetype
|
||||||
|
|
||||||
prefs = request.client
|
prefs = request.client
|
||||||
if prefs.format:
|
if prefs.format:
|
||||||
@ -153,7 +153,7 @@ def download_media():
|
|||||||
|
|
||||||
try: # Track -> direct download
|
try: # Track -> direct download
|
||||||
rv = Track[uid]
|
rv = Track[uid]
|
||||||
return send_file(rv.path, mimetype = rv.content_type, conditional=True)
|
return send_file(rv.path, mimetype = rv.mimetype, conditional=True)
|
||||||
except ObjectNotFound:
|
except ObjectNotFound:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# This file is part of Supysonic.
|
# This file is part of Supysonic.
|
||||||
# Supysonic is a Python implementation of the Subsonic server API.
|
# Supysonic is a Python implementation of the Subsonic server API.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2013-2018 Alban 'spl0k' Féron
|
# Copyright (C) 2013-2019 Alban 'spl0k' Féron
|
||||||
#
|
#
|
||||||
# Distributed under terms of the GNU AGPLv3 license.
|
# Distributed under terms of the GNU AGPLv3 license.
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from urlparse import urlparse, parse_qsl
|
from urlparse import urlparse, parse_qsl
|
||||||
|
|
||||||
SCHEMA_VERSION = '20190324'
|
SCHEMA_VERSION = '20190518'
|
||||||
|
|
||||||
def now():
|
def now():
|
||||||
return datetime.now().replace(microsecond = 0)
|
return datetime.now().replace(microsecond = 0)
|
||||||
@ -229,7 +229,6 @@ class Track(PathMixin, db.Entity):
|
|||||||
|
|
||||||
path = Required(str, 4096, autostrip = False) # unique
|
path = Required(str, 4096, autostrip = False) # unique
|
||||||
_path_hash = Required(buffer, column = 'path_hash')
|
_path_hash = Required(buffer, column = 'path_hash')
|
||||||
content_type = Required(str)
|
|
||||||
created = Required(datetime, precision = 0, default = now)
|
created = Required(datetime, precision = 0, default = now)
|
||||||
last_modification = Required(int)
|
last_modification = Required(int)
|
||||||
|
|
||||||
@ -254,7 +253,7 @@ class Track(PathMixin, db.Entity):
|
|||||||
artist = self.artist.name,
|
artist = self.artist.name,
|
||||||
track = self.number,
|
track = self.number,
|
||||||
size = os.path.getsize(self.path) if os.path.isfile(self.path) else -1,
|
size = os.path.getsize(self.path) if os.path.isfile(self.path) else -1,
|
||||||
contentType = self.content_type,
|
contentType = self.mimetype,
|
||||||
suffix = self.suffix(),
|
suffix = self.suffix(),
|
||||||
duration = self.duration,
|
duration = self.duration,
|
||||||
bitRate = self.bitrate,
|
bitRate = self.bitrate,
|
||||||
@ -296,6 +295,10 @@ class Track(PathMixin, db.Entity):
|
|||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mimetype(self):
|
||||||
|
return mimetypes.guess_type(self.path, False)[0] or 'application/octet-stream'
|
||||||
|
|
||||||
def duration_str(self):
|
def duration_str(self):
|
||||||
ret = '%02i:%02i' % ((self.duration % 3600) / 60, self.duration % 60)
|
ret = '%02i:%02i' % ((self.duration % 3600) / 60, self.duration % 60)
|
||||||
if self.duration >= 3600:
|
if self.duration >= 3600:
|
||||||
|
@ -3,12 +3,11 @@
|
|||||||
# This file is part of Supysonic.
|
# This file is part of Supysonic.
|
||||||
# Supysonic is a Python implementation of the Subsonic server API.
|
# Supysonic is a Python implementation of the Subsonic server API.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2013-2018 Alban 'spl0k' Féron
|
# Copyright (C) 2013-2019 Alban 'spl0k' Féron
|
||||||
#
|
#
|
||||||
# Distributed under terms of the GNU AGPLv3 license.
|
# Distributed under terms of the GNU AGPLv3 license.
|
||||||
|
|
||||||
import os, os.path
|
import os, os.path
|
||||||
import mimetypes
|
|
||||||
import mutagen
|
import mutagen
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -145,7 +144,6 @@ class Scanner:
|
|||||||
trdict['has_art'] = bool(Track._extract_cover_art(path))
|
trdict['has_art'] = bool(Track._extract_cover_art(path))
|
||||||
|
|
||||||
trdict['bitrate'] = int(tag.info.bitrate if hasattr(tag.info, 'bitrate') else os.path.getsize(path) * 8 / tag.info.length) // 1000
|
trdict['bitrate'] = int(tag.info.bitrate if hasattr(tag.info, 'bitrate') else os.path.getsize(path) * 8 / tag.info.length) // 1000
|
||||||
trdict['content_type'] = mimetypes.guess_type(path, False)[0] or 'application/octet-stream'
|
|
||||||
trdict['last_modification'] = mtime
|
trdict['last_modification'] = mtime
|
||||||
|
|
||||||
tralbum = self.__find_album(albumartist, album)
|
tralbum = self.__find_album(albumartist, album)
|
||||||
|
1
supysonic/schema/migration/mysql/20190518.sql
Normal file
1
supysonic/schema/migration/mysql/20190518.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE track DROP COLUMN content_type;
|
1
supysonic/schema/migration/postgres/20190518.sql
Normal file
1
supysonic/schema/migration/postgres/20190518.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE track DROP COLUMN content_type;
|
43
supysonic/schema/migration/sqlite/20190518.sql
Normal file
43
supysonic/schema/migration/sqlite/20190518.sql
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
DROP INDEX index_track_album_id_fk;
|
||||||
|
DROP INDEX index_track_artist_id_fk;
|
||||||
|
DROP INDEX index_track_folder_id_fk;
|
||||||
|
DROP INDEX index_track_root_folder_id_fk;
|
||||||
|
DROP INDEX index_track_path;
|
||||||
|
|
||||||
|
ALTER TABLE track RENAME TO track_old;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS track (
|
||||||
|
id CHAR(36) PRIMARY KEY,
|
||||||
|
disc INTEGER NOT NULL,
|
||||||
|
number INTEGER NOT NULL,
|
||||||
|
title VARCHAR(256) NOT NULL COLLATE NOCASE,
|
||||||
|
year INTEGER,
|
||||||
|
genre VARCHAR(256),
|
||||||
|
duration INTEGER NOT NULL,
|
||||||
|
has_art BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
album_id CHAR(36) NOT NULL REFERENCES album,
|
||||||
|
artist_id CHAR(36) NOT NULL REFERENCES artist,
|
||||||
|
bitrate INTEGER NOT NULL,
|
||||||
|
path VARCHAR(4096) NOT NULL,
|
||||||
|
path_hash BLOB NOT NULL,
|
||||||
|
created DATETIME NOT NULL,
|
||||||
|
last_modification INTEGER NOT NULL,
|
||||||
|
play_count INTEGER NOT NULL,
|
||||||
|
last_play DATETIME,
|
||||||
|
root_folder_id CHAR(36) NOT NULL REFERENCES folder,
|
||||||
|
folder_id CHAR(36) NOT NULL REFERENCES folder
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_track_album_id_fk ON track(album_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_track_artist_id_fk ON track(artist_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_track_folder_id_fk ON track(folder_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_track_root_folder_id_fk ON track(root_folder_id);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS index_track_path ON track(path_hash);
|
||||||
|
|
||||||
|
INSERT INTO track(id, disc, number, title, year, genre, duration, has_art, album_id, artist_id, bitrate, path, path_hash, created, last_modification, play_count, last_play, root_folder_id, folder_id)
|
||||||
|
SELECT id, disc, number, title, year, genre, duration, has_art, album_id, artist_id, bitrate, path, path_hash, created, last_modification, play_count, last_play, root_folder_id, folder_id
|
||||||
|
FROM track_old;
|
||||||
|
|
||||||
|
DROP TABLE track_old;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
VACUUM;
|
@ -37,7 +37,6 @@ CREATE TABLE IF NOT EXISTS track (
|
|||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
path VARCHAR(4096) NOT NULL,
|
path VARCHAR(4096) NOT NULL,
|
||||||
path_hash BINARY(20) UNIQUE NOT NULL,
|
path_hash BINARY(20) UNIQUE NOT NULL,
|
||||||
content_type VARCHAR(32) NOT NULL,
|
|
||||||
created DATETIME NOT NULL,
|
created DATETIME NOT NULL,
|
||||||
last_modification INTEGER NOT NULL,
|
last_modification INTEGER NOT NULL,
|
||||||
play_count INTEGER NOT NULL,
|
play_count INTEGER NOT NULL,
|
||||||
|
@ -37,7 +37,6 @@ CREATE TABLE IF NOT EXISTS track (
|
|||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
path VARCHAR(4096) NOT NULL,
|
path VARCHAR(4096) NOT NULL,
|
||||||
path_hash BYTEA UNIQUE NOT NULL,
|
path_hash BYTEA UNIQUE NOT NULL,
|
||||||
content_type VARCHAR(32) NOT NULL,
|
|
||||||
created TIMESTAMP NOT NULL,
|
created TIMESTAMP NOT NULL,
|
||||||
last_modification INTEGER NOT NULL,
|
last_modification INTEGER NOT NULL,
|
||||||
play_count INTEGER NOT NULL,
|
play_count INTEGER NOT NULL,
|
||||||
|
@ -38,7 +38,6 @@ CREATE TABLE IF NOT EXISTS track (
|
|||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
path VARCHAR(4096) NOT NULL,
|
path VARCHAR(4096) NOT NULL,
|
||||||
path_hash BLOB NOT NULL,
|
path_hash BLOB NOT NULL,
|
||||||
content_type VARCHAR(32) NOT NULL,
|
|
||||||
created DATETIME NOT NULL,
|
created DATETIME NOT NULL,
|
||||||
last_modification INTEGER NOT NULL,
|
last_modification INTEGER NOT NULL,
|
||||||
play_count INTEGER NOT NULL,
|
play_count INTEGER NOT NULL,
|
||||||
|
@ -39,7 +39,6 @@ class AlbumSongsTestCase(ApiTestBase):
|
|||||||
root_folder = folder,
|
root_folder = folder,
|
||||||
duration = 2,
|
duration = 2,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
last_modification = 0
|
last_modification = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ class AnnotationTestCase(ApiTestBase):
|
|||||||
root_folder = root,
|
root_folder = root,
|
||||||
duration = 2,
|
duration = 2,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
last_modification = 0
|
last_modification = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,7 +54,6 @@ class BrowseTestCase(ApiTestBase):
|
|||||||
artist = artist,
|
artist = artist,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
path = 'tests/assets/{0}rtist/{0}{1}lbum/{2}'.format(letter, lether, song),
|
path = 'tests/assets/{0}rtist/{0}{1}lbum/{2}'.format(letter, lether, song),
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
last_modification = 0,
|
last_modification = 0,
|
||||||
root_folder = root,
|
root_folder = root,
|
||||||
folder = afolder
|
folder = afolder
|
||||||
|
@ -48,7 +48,6 @@ class MediaTestCase(ApiTestBase):
|
|||||||
folder = folder,
|
folder = folder,
|
||||||
duration = 2,
|
duration = 2,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
last_modification = 0
|
last_modification = 0
|
||||||
)
|
)
|
||||||
self.trackid = track.id
|
self.trackid = track.id
|
||||||
@ -66,7 +65,6 @@ class MediaTestCase(ApiTestBase):
|
|||||||
folder = folder,
|
folder = folder,
|
||||||
duration = 2,
|
duration = 2,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
content_type = 'audio/{0}'.format(self.formats[i][1]),
|
|
||||||
last_modification = 0
|
last_modification = 0
|
||||||
)
|
)
|
||||||
self.formats[i] = track_embeded_art.id
|
self.formats[i] = track_embeded_art.id
|
||||||
@ -82,7 +80,6 @@ class MediaTestCase(ApiTestBase):
|
|||||||
|
|
||||||
rv = self.client.get('/rest/stream.view', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests', 'id': str(self.trackid) })
|
rv = self.client.get('/rest/stream.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(len(rv.data), 23)
|
self.assertEqual(len(rv.data), 23)
|
||||||
with db_session:
|
with db_session:
|
||||||
self.assertEqual(Track[self.trackid].play_count, 1)
|
self.assertEqual(Track[self.trackid].play_count, 1)
|
||||||
@ -95,7 +92,6 @@ class MediaTestCase(ApiTestBase):
|
|||||||
# download single file
|
# 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(len(rv.data), 23)
|
self.assertEqual(len(rv.data), 23)
|
||||||
with db_session:
|
with db_session:
|
||||||
self.assertEqual(Track[self.trackid].play_count, 0)
|
self.assertEqual(Track[self.trackid].play_count, 0)
|
||||||
|
@ -36,7 +36,6 @@ class PlaylistTestCase(ApiTestBase):
|
|||||||
artist = artist,
|
artist = artist,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
path = 'tests/assets/' + song,
|
path = 'tests/assets/' + song,
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
last_modification = 0,
|
last_modification = 0,
|
||||||
root_folder = root,
|
root_folder = root,
|
||||||
folder = root
|
folder = root
|
||||||
|
@ -47,7 +47,6 @@ class SearchTestCase(ApiTestBase):
|
|||||||
artist = artist,
|
artist = artist,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
path = 'tests/assets/{0}rtist/{0}{1}lbum/{2}'.format(letter, lether, song),
|
path = 'tests/assets/{0}rtist/{0}{1}lbum/{2}'.format(letter, lether, song),
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
last_modification = 0,
|
last_modification = 0,
|
||||||
root_folder = root,
|
root_folder = root,
|
||||||
folder = afolder
|
folder = afolder
|
||||||
|
@ -74,7 +74,6 @@ class DbTestCase(unittest.TestCase):
|
|||||||
has_art = True,
|
has_art = True,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
path = 'tests/assets/formats/silence.ogg',
|
path = 'tests/assets/formats/silence.ogg',
|
||||||
content_type = 'audio/ogg',
|
|
||||||
last_modification = 1234,
|
last_modification = 1234,
|
||||||
root_folder = root,
|
root_folder = root,
|
||||||
folder = child
|
folder = child
|
||||||
@ -89,7 +88,6 @@ class DbTestCase(unittest.TestCase):
|
|||||||
duration = 5,
|
duration = 5,
|
||||||
bitrate = 96,
|
bitrate = 96,
|
||||||
path = 'tests/assets/23bytes',
|
path = 'tests/assets/23bytes',
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
last_modification = 1234,
|
last_modification = 1234,
|
||||||
root_folder = root,
|
root_folder = root,
|
||||||
folder = child
|
folder = child
|
||||||
@ -110,7 +108,6 @@ class DbTestCase(unittest.TestCase):
|
|||||||
has_art = has_art,
|
has_art = has_art,
|
||||||
bitrate = 96,
|
bitrate = 96,
|
||||||
path = 'tests/assets/formats/silence.flac',
|
path = 'tests/assets/formats/silence.flac',
|
||||||
content_type = 'audio/flac',
|
|
||||||
last_modification = 1234,
|
last_modification = 1234,
|
||||||
root_folder = root,
|
root_folder = root,
|
||||||
folder = folder
|
folder = folder
|
||||||
|
@ -35,7 +35,6 @@ class PlaylistTestCase(FrontendTestBase):
|
|||||||
duration = 2,
|
duration = 2,
|
||||||
disc = 1,
|
disc = 1,
|
||||||
number = 1,
|
number = 1,
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
last_modification = 0
|
last_modification = 0
|
||||||
)
|
)
|
||||||
|
@ -59,7 +59,6 @@ class FolderManagerTestCase(unittest.TestCase):
|
|||||||
folder = root,
|
folder = root,
|
||||||
root_folder = root,
|
root_folder = root,
|
||||||
duration = 2,
|
duration = 2,
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
last_modification = 0
|
last_modification = 0
|
||||||
)
|
)
|
||||||
|
@ -48,7 +48,6 @@ class UserManagerTestCase(unittest.TestCase):
|
|||||||
path = 'tests/assets/empty',
|
path = 'tests/assets/empty',
|
||||||
folder = folder,
|
folder = folder,
|
||||||
root_folder = folder,
|
root_folder = folder,
|
||||||
content_type = 'audio/mpeg',
|
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
last_modification = 0
|
last_modification = 0
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user