This commit is contained in:
Mateusz Gruszczyński
2026-06-20 17:41:25 +02:00
parent fc03b7755b
commit e1b5822a59
12 changed files with 38 additions and 31 deletions
+16 -6
View File
@@ -372,9 +372,21 @@ def _annotate_path_directories(profile: dict, payload: dict) -> dict:
return payload
def _path_profile_from_request(*, require_write_access: bool = False):
profile_id = 0
try:
profile_id = int((request.args.get("profile_id") if request.method == "GET" else (request.get_json(silent=True) or {}).get("profile_id")) or 0)
except Exception:
profile_id = 0
profile = preferences.get_profile(profile_id, auth.current_user_id() or default_user_id()) if profile_id else request_profile()
if profile and require_write_access:
require_profile_write(profile.get("id"))
return profile
@bp.get("/path/default")
def path_default():
profile = request_profile()
profile = _path_profile_from_request()
if not profile:
return jsonify({"ok": False, "error": "No profile"}), 400
try:
@@ -386,7 +398,7 @@ def path_default():
@bp.get("/path/browse")
def path_browse():
profile = request_profile()
profile = _path_profile_from_request()
if not profile:
return jsonify({"ok": False, "error": "No profile"}), 400
base = request.args.get("path") or ""
@@ -398,10 +410,9 @@ def path_browse():
@bp.post("/path/directories")
def path_directory_create():
profile = request_profile()
profile = _path_profile_from_request(require_write_access=True)
if not profile:
return jsonify({"ok": False, "error": "No profile"}), 400
require_profile_write(profile.get("id"))
data = request.get_json(silent=True) or {}
try:
# Note: This endpoint only creates an empty directory and does not alter any torrent state.
@@ -413,10 +424,9 @@ def path_directory_create():
@bp.post("/path/directories/rename")
def path_directory_rename():
profile = request_profile()
profile = _path_profile_from_request(require_write_access=True)
if not profile:
return jsonify({"ok": False, "error": "No profile"}), 400
require_profile_write(profile.get("id"))
data = request.get_json(silent=True) or {}
path = str(data.get("path") or "").strip()
if _path_has_cached_torrents(int(profile.get("id") or 0), path):
+1 -1
View File
@@ -613,7 +613,7 @@ def _profile_transfer_payload(source_profile: dict, data: dict, *, require_hashe
"target_write_check": write_check,
"label_mode": str(data.get("label_mode") or "none").strip(),
"label_value": str(data.get("label_value") or "").strip(),
"post_action": str(data.get("post_action") or "none").strip(),
"post_action": str(data.get("post_action") or "current").strip(),
}
+4 -4
View File
@@ -370,7 +370,7 @@ def _enqueue_automation_job(profile: dict[str, Any], rule: dict[str, Any], actio
if action_name == 'move':
extra.update({'target_path': str(part_payload.get('path') or ''), 'move_data': bool(part_payload.get('move_data'))})
if action_name == 'profile_transfer':
extra.update({'target_profile_id': int(part_payload.get('target_profile_id') or 0), 'target_path': str(part_payload.get('target_path') or ''), 'move_data': bool(part_payload.get('move_data')), 'post_action': str(part_payload.get('post_action') or 'none')})
extra.update({'target_profile_id': int(part_payload.get('target_profile_id') or 0), 'target_path': str(part_payload.get('target_path') or ''), 'move_data': bool(part_payload.get('move_data')), 'post_action': str(part_payload.get('post_action') or 'current')})
if action_name == 'remove':
extra.update({'remove_data': bool(part_payload.get('remove_data'))})
effect_type = str(context_extra.get('effect_type') if context_extra else action_name)
@@ -435,9 +435,9 @@ def _automation_profile_transfer_payload(profile: dict[str, Any], eff: dict[str,
move_data = bool(check.get('ok'))
if not move_data:
downgrade_reason = str(check.get('message') or check.get('error') or 'target path is not writable by source rTorrent user')
post_action = str(eff.get('post_action') or 'none').strip().lower()
if post_action not in {'none', 'start', 'stop', 'pause', 'check', 'recheck'}:
post_action = 'none'
post_action = str(eff.get('post_action') or 'current').strip().lower()
if post_action not in {'none', 'current', 'start', 'stop', 'pause', 'check', 'recheck'}:
post_action = 'current'
label_mode = str(eff.get('label_mode') or 'none').strip().lower()
if label_mode not in {'none', 'custom', 'moved_from', 'moved_to'}:
label_mode = 'none'
+2 -8
View File
@@ -583,16 +583,10 @@ def start_scheduler(socketio=None) -> None:
def loop():
while True:
try:
from .preferences import active_profile
from .websocket import emit_profile_event
from . import auth
profiles: list[dict]
if auth.enabled():
with connect() as conn:
profiles = conn.execute("SELECT * FROM rtorrent_profiles ORDER BY id").fetchall()
else:
profile = active_profile()
profiles = [profile] if profile else []
with connect() as conn:
profiles = [dict(row) for row in conn.execute("SELECT * FROM rtorrent_profiles ORDER BY id").fetchall()]
for profile in profiles:
try:
result = enforce(profile, force=False)
+4 -1
View File
@@ -200,7 +200,10 @@ def start_scheduler(socketio=None) -> None:
with connect() as conn:
profiles = conn.execute("SELECT DISTINCT profile_id FROM rss_feeds WHERE enabled=1 AND profile_id IS NOT NULL").fetchall()
for row in profiles:
profile = get_profile(int(row["profile_id"]))
profile_id = int(row["profile_id"])
with connect() as conn:
owner = conn.execute("SELECT user_id FROM rtorrent_profiles WHERE id=?", (profile_id,)).fetchone()
profile = get_profile(profile_id, int(owner["user_id"] if owner and owner.get("user_id") else default_user_id()))
if profile:
result = check(profile, only_due=True)
if socketio and result.get("queued"):
+3 -3
View File
@@ -842,7 +842,7 @@ def transfer_profile(source_profile: dict, target_profile: dict, torrent_hashes:
target_path = _remote_clean_path(payload.get("target_path") or payload.get("path") or "")
move_data = bool(payload.get("move_data"))
post_action = str(payload.get("post_action") or "none").strip().lower()
if post_action not in {"none", "start", "stop", "pause", "check", "recheck"}:
if post_action not in {"none", "current", "start", "stop", "pause", "check", "recheck"}:
raise ValueError("Unsupported post-transfer action")
label_mode = str(payload.get("label_mode") or "none").strip().lower()
label_value = str(payload.get("label_value") or "").strip()
@@ -902,8 +902,8 @@ def transfer_profile(source_profile: dict, target_profile: dict, torrent_hashes:
move_result = _move_profile_transfer_data(source_client, h, target_path)
item.update(move_result)
moved_to = str(move_result.get("moved_to") or "")
# Note: Explicit post-transfer actions override state restoration and keep command effects predictable.
start_on_target = bool(move_data and (was_state or was_active)) if post_action == "none" else post_action == "start"
# Note: The default keeps the torrent status from the source profile; explicit actions override it.
start_on_target = bool(was_state or was_active) if post_action in {"none", "current"} else post_action == "start"
try:
added = add_torrent_raw(target_profile, data, start_on_target, target_path, target_label)
if not added.get("ok"):
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long