Closed jq6l43d1 closed 6 months ago
Here is another code sample to demonstrate this bug. when this code is executed using reflex run --env=prod
and a video or image is uploaded it doesn't display on the page.
import reflex as rx
class State(rx.State):
img: list[str] = []
vid: list[str] = []
val: str = "new"
uploading: bool = False
async def handle_upload(self, files: list[rx.UploadFile]):
for file in files:
upload_data = await file.read()
outfile = f"assets/{file.filename}"
# Save the file.
with open(outfile, "wb") as file_object:
file_object.write(upload_data)
# get the file extension
ext = file.filename.split(".")[-1]
# If the file is a video, add it to the vid var.
if ext in ["mp4", "mkv"]:
self.vid.append(file.filename)
# If the file is an image, add it to the img var.
if ext in ["jpg", "jpeg", "png"]:
self.img.append(file.filename)
self.uploading = False
self.val = "Finished uploading"
async def start_vars(self):
self.uploading = True
self.val = "Uploading files"
async def clear_state(self):
self.reset()
def index():
return rx.center(
rx.script("""
setInterval(function() {
var elements = document.querySelectorAll('.chakra-input.css-1kp110w');
elements.forEach(function(element) {
element.style.display = 'flex';
});
}, 500);
"""),
rx.vstack(
rx.text(State.val),
rx.text("Upload an image (png, jpg, jpeg) or video (mp4, mkv) file."),
rx.upload(
accept={
"image/png": [".png"],
"image/jpeg": [".jpg"],
"video/mp4": [".mp4"],
"video/x-matroska": [".mkv"],
},
border="1px dotted black",
padding="1em",
height="4.5em",
no_drag=True,
no_click=True,
),
rx.cond(
State.uploading,
rx.button(
is_loading=True,
is_disabled=True,
),
rx.button(
"Upload",
on_click=[
State.start_vars(),
State.handle_upload(rx.upload_files()),
],
),
),
rx.button(
"Reset",
on_click=[
State.clear_state(),
],
),
rx.foreach(State.img, lambda img: rx.image(src=img)),
rx.foreach(State.vid, lambda vid: rx.video(url=vid)),
),
)
app = rx.App(state=State)
app.add_page(index)
app.compile()
Hi @jq6l43d1 , did you find a solution for updating and displaying the video?
I was told by a dev a while ago that this isn't really how the assets folder is supposed to be used. Files that are placed in the .uploaded_files directory are now mounted on the /_upload API endpoint and are publicly accessible from a URL so putting your videos/images/etc there might be a better solution.
https://reflex.dev/docs/library/forms/upload#saving-the-file
@david1309 As mentioned, the approach for this now is to use the new rx.get_upload_dir()
method on the backend to save the file, then reference it on the frontend with rx.get_upload_url(relative_path)
. This will serve the file from the backend rather than the frontend (assets is frontend-only).
I updated the code sample above to follow the latest standards as a reference
import reflex as rx
class State(rx.State):
img: list[str] = []
vid: list[str] = []
val: str = "new"
uploading: bool = False
async def handle_upload(self, files: list[rx.UploadFile]):
for file in files:
outfile = rx.get_upload_dir() / file.filename
outfile.write_bytes(await file.read())
# get the file extension
ext = outfile.suffix[1:].lower()
# If the file is a video, add it to the vid var.
if ext in ["mp4", "mkv"]:
self.vid.append(file.filename)
# If the file is an image, add it to the img var.
if ext in ["jpg", "jpeg", "png"]:
self.img.append(file.filename)
self.uploading = False
self.val = "Finished uploading"
async def start_vars(self):
self.uploading = True
self.val = "Uploading files"
async def clear_state(self):
self.reset()
def index():
return rx.center(
rx.vstack(
rx.text(State.val),
rx.text("Upload an image (png, jpg, jpeg) or video (mp4, mkv) file."),
rx.upload(
rx.foreach(
rx.selected_files,
rx.text,
),
accept={
"image/png": [".png"],
"image/jpeg": [".jpg"],
"video/mp4": [".mp4"],
"video/x-matroska": [".mkv"],
},
border="1px dotted black",
padding="1em",
height="4.5em",
width="100%",
),
rx.cond(
State.uploading,
rx.button(
"Uploading...",
disabled=True,
),
rx.button(
"Upload",
on_click=[
State.start_vars(),
State.handle_upload(rx.upload_files()),
],
),
),
rx.button(
"Reset",
on_click=[
State.clear_state(),
],
),
rx.foreach(State.img, lambda img: rx.image(src=rx.get_upload_url(img))),
rx.foreach(State.vid, lambda vid: rx.video(url=rx.get_upload_url(vid))),
align="center",
),
)
app = rx.App()
app.add_page(index)
Marking this issue as resolved.
Describe the bug I have a reflex site where a user can make a clip from a larger video. When the clip is created it is stored in the assets folder. I'm using rx.video to view the clip on the page. If I run my site with
reflex run
the clip is copied to the .web/public folder and everything works. If I run the site withreflex run --env=prod
the clip isn't copied to the .web/public folder and the clip can't be played with the rx.video.I've tried adding a line of code to copy the clip to the .web/public folder manually but this didn't work.
To Reproduce Run the site with
reflex run --env=prod
, create a clip in the assets folder and try to play it with rx.video.Expected behavior The video should be playable like it is when using
reflex run
Screenshots
Specifics (please complete the following information):
Additional context Add any other context about the problem here.