mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
fix: chunked audio stream
desc: faulty content range headers + fix: tracks not being removed from db on root dirs change + implement implicit jwt refreshing + remove enableGuest from configs + set jwt validity to 30 days
This commit is contained in:
+1
-2
@@ -63,12 +63,11 @@ def create_api():
|
||||
)
|
||||
|
||||
app = OpenAPI(__name__, info=api_info, doc_prefix="/docs")
|
||||
print("userid", UserConfig().userId)
|
||||
# JWT CONFIGS
|
||||
app.config["JWT_SECRET_KEY"] = UserConfig().userId
|
||||
app.config["JWT_TOKEN_LOCATION"] = ["cookies"]
|
||||
app.config["JWT_COOKIE_CSRF_PROTECT"] = False
|
||||
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = datetime.timedelta(days=1)
|
||||
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = datetime.timedelta(days=30)
|
||||
|
||||
# CORS
|
||||
CORS(app, origins="*", supports_credentials=True)
|
||||
|
||||
+5
-9
@@ -191,11 +191,6 @@ def delete_user(body: DeleteUseBody):
|
||||
return {"msg": "Cannot delete the only admin"}, 400
|
||||
|
||||
authdb.delete_user_by_username(body.username)
|
||||
|
||||
# if user is guest, update config
|
||||
if body.username == "guest":
|
||||
UserConfig().enableGuest = False
|
||||
|
||||
return {"msg": f"User {body.username} deleted"}
|
||||
|
||||
|
||||
@@ -225,7 +220,7 @@ def get_all_users(query: GetAllUsersQuery):
|
||||
# config.enableGuest = True
|
||||
# config.usersOnLogin = True
|
||||
settings = {
|
||||
"enableGuest": config.enableGuest,
|
||||
"enableGuest": False,
|
||||
"usersOnLogin": config.usersOnLogin,
|
||||
}
|
||||
|
||||
@@ -234,7 +229,10 @@ def get_all_users(query: GetAllUsersQuery):
|
||||
"users": [],
|
||||
}
|
||||
|
||||
users = authdb.get_all_users()
|
||||
|
||||
is_admin = current_user and "admin" in current_user["roles"]
|
||||
settings['enableGuest'] = [user for user in users if user.username == "guest"].__len__() > 0
|
||||
|
||||
# if user is admin, also return settings
|
||||
if is_admin:
|
||||
@@ -254,13 +252,12 @@ def get_all_users(query: GetAllUsersQuery):
|
||||
):
|
||||
return res
|
||||
|
||||
users = authdb.get_all_users()
|
||||
|
||||
# remove guest user
|
||||
# if not settings["enableGuest"]:
|
||||
# users = [user for user in users if user.username != "guest"]
|
||||
|
||||
if not is_admin or not settings["usersOnLogin"]:
|
||||
if not settings["usersOnLogin"]:
|
||||
users = [user for user in users if user.username == "guest"]
|
||||
|
||||
# reverse list to show latest users first
|
||||
@@ -268,7 +265,6 @@ def get_all_users(query: GetAllUsersQuery):
|
||||
|
||||
# bring admins to the front
|
||||
users = sorted(users, key=lambda x: "admin" in x.roles, reverse=True)
|
||||
|
||||
# bring current user to index 0
|
||||
if current_user:
|
||||
users = sorted(
|
||||
|
||||
+26
-9
@@ -68,15 +68,31 @@ def send_track_file(path: TrackHashSchema, query: SendTrackFileQuery):
|
||||
|
||||
|
||||
def send_file_as_chunks(filepath: str, audio_type: str) -> Response:
|
||||
"""
|
||||
Returns a Response object that streams the file in chunks.
|
||||
"""
|
||||
# NOTE: +1 makes sure the last byte is included in the range.
|
||||
# NOTE: -1 is used to convert the end index to a 0-based index.
|
||||
chunk_size = 1024 * 512
|
||||
|
||||
# Get file size
|
||||
file_size = os.path.getsize(filepath)
|
||||
start = 0
|
||||
end = file_size - 1
|
||||
end = chunk_size
|
||||
|
||||
# Read range header
|
||||
range_header = request.headers.get("Range")
|
||||
if range_header:
|
||||
start, end = parse_range_header(range_header, file_size)
|
||||
start = get_start_range(range_header)
|
||||
|
||||
chunk_size = 1024 * 1024 # 1MB chunk size (adjust as needed)
|
||||
# If start + chunk_size is greater than file_size,
|
||||
# set end to file_size - 1
|
||||
_end = start + chunk_size - 1
|
||||
|
||||
if _end > file_size:
|
||||
end = file_size - 1
|
||||
else:
|
||||
end = _end
|
||||
|
||||
def generate_chunks():
|
||||
with open(filepath, "rb") as file:
|
||||
@@ -84,8 +100,11 @@ def send_file_as_chunks(filepath: str, audio_type: str) -> Response:
|
||||
remaining_bytes = end - start + 1
|
||||
|
||||
while remaining_bytes > 0:
|
||||
# Read the chunk size or all the remaining bytes
|
||||
chunk = file.read(min(chunk_size, remaining_bytes))
|
||||
yield chunk
|
||||
|
||||
# Update the remaining bytes
|
||||
remaining_bytes -= len(chunk)
|
||||
|
||||
response = Response(
|
||||
@@ -102,15 +121,13 @@ def send_file_as_chunks(filepath: str, audio_type: str) -> Response:
|
||||
return response
|
||||
|
||||
|
||||
def parse_range_header(range_header: str, file_size: int) -> tuple[int, int]:
|
||||
def get_start_range(range_header: str):
|
||||
try:
|
||||
range_start, range_end = range_header.strip().split("=")[1].split("-")
|
||||
start = int(range_start)
|
||||
end = min(int(range_end), file_size - 1)
|
||||
except ValueError:
|
||||
return 0, file_size - 1
|
||||
return int(range_start)
|
||||
|
||||
return start, end
|
||||
except ValueError:
|
||||
return 0
|
||||
|
||||
|
||||
class GetAudioSilenceBody(BaseModel):
|
||||
|
||||
+9
-8
@@ -7,6 +7,7 @@ from app.api.auth import admin_required
|
||||
|
||||
from app.db.sqlite.plugins import PluginsMethods as pdb
|
||||
from app.db.sqlite.settings import SettingsSQLMethods as sdb
|
||||
from app.db.sqlite.tracks import SQLiteTrackMethods as trackdb
|
||||
from app.lib import populate
|
||||
from app.lib.watchdogg import Watcher as WatchDog
|
||||
from app.logger import log
|
||||
@@ -51,12 +52,12 @@ def reload_everything(instance_key: str):
|
||||
@background
|
||||
def rebuild_store(db_dirs: list[str]):
|
||||
"""
|
||||
Restarts the watchdog and rebuilds the music library.
|
||||
Restarts watchdog and rebuilds the music library.
|
||||
"""
|
||||
instance_key = get_random_str()
|
||||
|
||||
log.info("Rebuilding library...")
|
||||
TrackStore.remove_tracks_by_dir_except(db_dirs)
|
||||
trackdb.remove_tracks_not_in_folders(db_dirs)
|
||||
reload_everything(instance_key)
|
||||
|
||||
try:
|
||||
@@ -106,10 +107,10 @@ def add_root_dirs(body: AddRootDirsBody):
|
||||
removed_dirs = body.removed
|
||||
|
||||
db_dirs = sdb.get_root_dirs()
|
||||
_h = "$home"
|
||||
home = "$home"
|
||||
|
||||
db_home = any([d == _h for d in db_dirs]) # if $home is in db
|
||||
incoming_home = any([d == _h for d in new_dirs]) # if $home is in incoming
|
||||
db_home = any([d == home for d in db_dirs]) # if $home is in db
|
||||
incoming_home = any([d == home for d in new_dirs]) # if $home is in incoming
|
||||
|
||||
# handle $home case
|
||||
if db_home and incoming_home:
|
||||
@@ -119,8 +120,8 @@ def add_root_dirs(body: AddRootDirsBody):
|
||||
sdb.remove_root_dirs(db_dirs)
|
||||
|
||||
if incoming_home:
|
||||
finalize([_h], [], [Paths.USER_HOME_DIR])
|
||||
return {"root_dirs": [_h]}
|
||||
finalize([home], [], [Paths.USER_HOME_DIR])
|
||||
return {"root_dirs": [home]}
|
||||
|
||||
# ---
|
||||
|
||||
@@ -135,7 +136,7 @@ def add_root_dirs(body: AddRootDirsBody):
|
||||
pass
|
||||
|
||||
db_dirs.extend(new_dirs)
|
||||
db_dirs = [dir_ for dir_ in db_dirs if dir_ != _h]
|
||||
db_dirs = [dir_ for dir_ in db_dirs if dir_ != home]
|
||||
|
||||
finalize(new_dirs, removed_dirs, db_dirs)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user