Skip to content

enh(relay): pass media paths on relative to the camera dir - #3379

Merged
MichaIng merged 2 commits into
motioneye-project:devfrom
JamBalaya56562:enh/relay-relative-path
Oct 13, 2026
Merged

MichaIng merged 2 commits into
motioneye-project:devfrom
JamBalaya56562:enh/relay-relative-path

Conversation

@JamBalaya56562

@JamBalaya56562 JamBalaya56562 commented Jun 29, 2026 •

Copy link
Copy Markdown
Contributor

What

Pass media paths on relative to the camera dir inside motionEye. motion still calls the relay with its absolute %f path; the relay-event API strips the camera dir once, validates the remaining relative path and passes it on. The absolute path is joined again only where a file is accessed (ffmpeg, upload).

Follows the discussion in #3374 and #3379 (comment): the conversion lives in the API, where the motion → motionEye camera ID mapping already is, rather than in relayevent.sh. motion's commands and relayevent.sh are unchanged, so existing motion configs keep working.

How

  • handlers/relay_event.py: strip the camera dir with remove_prefix, validate the relative path, pass it to make_movie_preview, and join it again for the upload call, so the upload subsystem is unchanged.
  • mediafiles.make_movie_preview: takes a relative path, validates it and joins it with the camera dir; get_media_preview passes the relative path it already had.

Scope / not included

The upload services (UploadService.upload_file, incl. the S3 override) still receive an absolute path and keep deriving the cloud-relative name themselves; that naming is tied to @upload_subfolders. Making it relative would be a follow-up.

Testing

  • Full suite in a Linux container (python:3.12-bookworm): 230 passed, 168 subtests passed.
  • tests/test_mediafiles.py: the make_movie_preview traversal/escape tests pass relative malicious paths (the form it now receives); a new test asserts the absolute path is joined again for ffmpeg.
  • ruff check / ruff format --check pass.
  • Not run: an end-to-end run with a real motion and camera.

🤖 Generated with Claude Code

@JamBalaya56562
JamBalaya56562 force-pushed the enh/relay-relative-path branch 2 times, most recently from 8b9953d to 9f3e441 Compare June 30, 2026 22:53
@JamBalaya56562
JamBalaya56562 force-pushed the enh/relay-relative-path branch from 9f3e441 to 0e11ca7 Compare July 15, 2026 20:05
@JamBalaya56562
JamBalaya56562 force-pushed the enh/relay-relative-path branch from 0e11ca7 to 1ddeb65 Compare October 12, 2026 12:09
@MichaIng

Copy link
Copy Markdown
Member

Hmm, I am not happy with adding a redundant argument to the relay event call.

We could read the camera dir in relayevent.sh from the config file. motion assigns its camera IDs by the order of camera config keys in motion.conf. So an ID of 5 means the 5th camera key in the main config:

camera_conf=$(awk -v "id=$motion_camera_id" '$1=="camera"{c++} c==id{print $2;exit}' "$motion_conf")
camera_dir=$(awk '/^target_dir /{print $2}' "$camera_conf")

The same way, also the motionEye camera_id could be obtained:

camera_id=$(awk '/^# @id /{print $3;exit}' "$camera_conf")

But I am not sure sure anymore whether doing all this in shell really is the way to go, or whether we should accept that motion passes its own ID and absolute paths, and deal with that in the API, that is supposed to be used by motion only. From there, we could pass the path as relative one strictly, like you do for preview generation now. It only inverts the strip/join requirements, as absolute paths are still needed along the pipeline for file operations, and are also more valuable in logs. But I still like the idea to pass only relative paths around within motionEye, and merge them with the known/trusted camera dir to absolute paths only where needed for final file operations or logs.

This is a design decision, I want to hear other opinions about. @zagrim @Marijn0 but also @JamBalaya56562 and @free-cup-holder-exe both incredibly active recently, be it with AI agent or not: Shall we require relative paths (and/or the motionEye camera ID) at the API already, outsource the conversion requirements to the relay shell script? Or shall we do that in the relay API, as a special case that is used by motion only, and where we have the Python functions to do the conversion? Or, since the absolute path is needed along the pipeline anyway, keep things as they are, leave it to the path validation function or caller to deal with absolute paths where needed?

@Marijn0

Marijn0 commented Oct 12, 2026

Copy link
Copy Markdown
Member

I'd rather not do this in the shell either, I would do the conversion in the relay API, so basically the way outlined above:

we should accept that motion passes its own ID and absolute paths, and deal with that in the API, that is supposed to be used by motion only. From there, we could pass the path as relative one strictly, like you do for preview generation now. It only inverts the strip/join requirements, as absolute paths are still needed along the pipeline for file operations, and are also more valuable in logs. But I still like the idea to pass only relative paths around within motionEye, and merge them with the known/trusted camera dir to absolute paths only where needed for final file operations or logs.

@JamBalaya56562

Copy link
Copy Markdown
Contributor Author

I'd go with the relay API (your second option). It already maps the motion camera ID to the motionEye one in Python (motionctl.motion_camera_id_to_camera_id(), same "Nth camera line" rule), so the shell would only duplicate it. Parsing configs with awk '{print $2}' also breaks on spaces, which target_dir may contain: with target_dir /media/usb/My Camera, your snippet yields /media/usb/My.
The handler in this PR already strips the camera dir from the absolute path motion sends, validates the remaining relative path, and passes it on; absolute paths are only built again for file operations, the upload and logs. So I'd drop the extra argument from relayevent.sh and config.py and keep the conversion in the API, which also needs no regenerated motion config.

motion calls relayevent.sh with its %f specifier, an absolute path, and
the relay-event API passed that absolute filename on, so every consumer
had to strip the camera dir off again for validation.

The relay API now does that once: it strips the camera dir from the path
motion sends, validates the remaining relative path and passes it on.
The absolute path is joined again only where a file is accessed. motion's
commands and relayevent.sh stay unchanged, so existing motion configs
keep working.

- relay_event.py: strip and validate once; pass the relative path to
  make_movie_preview and join it again for the upload subsystem.
- mediafiles.make_movie_preview: take a relative path, validate it and
  join it with the camera dir; get_media_preview passes the relative
  path it already has.
- tests: the make_movie_preview validation tests use relative paths; add
  a test that the absolute path is joined again for ffmpeg.

The upload services (incl. S3) still receive an absolute path; making
that relative is a separate upload-subsystem change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JamBalaya56562
JamBalaya56562 force-pushed the enh/relay-relative-path branch from 1ddeb65 to 9f315e2 Compare October 12, 2026 22:02
@JamBalaya56562 JamBalaya56562 changed the title enh(relay): send the relay API a path relative to the camera dir enh(relay): pass media paths on relative to the camera dir Oct 12, 2026
Comment thread tests/test_mediafiles.py Outdated
Comment thread tests/test_mediafiles.py Outdated
Co-authored-by: MichaIng <micha@dietpi.com>
@MichaIng MichaIng added this to the v0.45.0 milestone Oct 13, 2026
@MichaIng
MichaIng merged commit 7502fea into motioneye-project:dev Oct 13, 2026
20 checks passed
@JamBalaya56562
JamBalaya56562 deleted the enh/relay-relative-path branch October 13, 2026 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

3 participants