-
- >
- )
-}
-
const LinkedGameField = ({ game, onLink, onUnlink, alertHandler }) => {
if (game) {
return (
diff --git a/app/client/src/views/FolderView.js b/app/client/src/views/FolderView.js
index 4f1e7fc4..fcc8ad16 100644
--- a/app/client/src/views/FolderView.js
+++ b/app/client/src/views/FolderView.js
@@ -87,6 +87,7 @@ const FolderView = ({ authenticated, cardSize, searchText }) => {
...(update.private !== undefined && { private: update.private }),
},
...(update.game !== undefined && { game: update.game }),
+ ...(update.created_at !== undefined && { created_at: update.created_at }),
}
}
setMedia((prev) => prev.map(updateImage))
diff --git a/app/client/src/views/GameVideos.js b/app/client/src/views/GameVideos.js
index c51ab436..cf6ca987 100644
--- a/app/client/src/views/GameVideos.js
+++ b/app/client/src/views/GameVideos.js
@@ -331,6 +331,7 @@ const GameVideos = ({ cardSize, authenticated, searchText }) => {
...(update.private !== undefined && { private: update.private }),
},
...(update.game !== undefined && { game: update.game }),
+ ...(update.created_at !== undefined && { created_at: update.created_at }),
}
}),
)
@@ -345,6 +346,7 @@ const GameVideos = ({ cardSize, authenticated, searchText }) => {
...(update.private !== undefined && { private: update.private }),
},
...(update.game !== undefined && { game: update.game }),
+ ...(update.created_at !== undefined && { created_at: update.created_at }),
}
}),
)
diff --git a/app/client/src/views/ImageFeed.js b/app/client/src/views/ImageFeed.js
index 48196f13..0f806575 100644
--- a/app/client/src/views/ImageFeed.js
+++ b/app/client/src/views/ImageFeed.js
@@ -285,6 +285,7 @@ const ImageFeed = ({ authenticated, searchText, cardSize, selectedImageFolder, o
...(update.private !== undefined && { private: update.private }),
},
...(update.game !== undefined && { game: update.game }),
+ ...(update.created_at !== undefined && { created_at: update.created_at }),
}
}
setImages((prev) => prev.map(updateImage))
diff --git a/app/nginx/prod.conf b/app/nginx/prod.conf
index 54cc7b28..7f60c6fe 100644
--- a/app/nginx/prod.conf
+++ b/app/nginx/prod.conf
@@ -51,7 +51,7 @@ http {
proxy_cache_lock_timeout 10s;
server {
- listen 80 default_server reuseport;
+ listen __FIRESHARE_PORT__ default_server reuseport;
server_name _;
gzip on;
diff --git a/app/server/fireshare/api/image.py b/app/server/fireshare/api/image.py
index 430070a9..103b2b75 100644
--- a/app/server/fireshare/api/image.py
+++ b/app/server/fireshare/api/image.py
@@ -303,6 +303,18 @@ def update_image_details(image_id):
img.info.description = data['description']
if 'private' in data:
img.info.private = bool(data['private'])
+ if 'created_at' in data:
+ created_at = data['created_at']
+ if not created_at:
+ img.created_at = None
+ else:
+ try:
+ # Strip any timezone suffix and store as naive local datetime,
+ # matching how video recorded_at is persisted.
+ dt = datetime.fromisoformat(created_at.replace('Z', '+00:00'))
+ img.created_at = dt.replace(tzinfo=None)
+ except (ValueError, AttributeError):
+ pass
db.session.commit()
return Response(status=200)
diff --git a/app/server/fireshare/cli.py b/app/server/fireshare/cli.py
index bd549aed..bf712aae 100755
--- a/app/server/fireshare/cli.py
+++ b/app/server/fireshare/cli.py
@@ -417,7 +417,7 @@ def scan_videos(root):
if generic_webhook_url:
logger.info(f"Posting to Generic webhook for {nv.video_id}")
payload_str = json.dumps(generic_webhook_payload)
- processed_payload_str = payload_str.replace("[[video_url]]", video_url)
+ processed_payload_str = payload_str.replace("[[video_url]]", video_url or "")
final_payload = json.loads(processed_payload_str)
send_generic_webhook(
webhook_url=generic_webhook_url,
@@ -652,7 +652,7 @@ def scan_video(ctx, path, tag_ids, game_id, title):
video_url = get_public_watch_url(video_id, config, domain)
payload_str = json.dumps(generic_webhook_payload)
#Replaces plain text json [[video_url]] with the real video_url python var
- processed_payload_str = payload_str.replace("[[video_url]]", video_url)
+ processed_payload_str = payload_str.replace("[[video_url]]", video_url or "")
final_payload = json.loads(processed_payload_str)
send_generic_webhook(
webhook_url=generic_webhook_url,
diff --git a/docker-compose.yml b/docker-compose.yml
index 1247672b..cd227c0b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -22,10 +22,15 @@ services:
# - STEAMGRIDDB_API_KEY=
# The location in the video thumbnails are generated. A value between 0-100 where 50 would be the frame in the middle of the video file and 0 would be the first frame of the video.
- THUMBNAIL_VIDEO_LOCATION=0
- # The domain your instance is hosted at. (do not add http or https) e.x: v.fireshare.net, this is required for opengraph to work correctly for shared links. DO NOT SURROUND IN QUOTES.
+ # The domain your instance is hosted at. (do not add http or https) e.x: demo.fireshare.net, this is required for opengraph to work correctly for shared links. DO NOT SURROUND IN QUOTES.
- DOMAIN=
- PUID=1000
- PGID=1000
+ # The port Fireshare's web server (nginx) listens on inside the container (default: 80).
+ # Most users should leave this alone and change the host-side "ports" mapping above instead.
+ # This is primarily useful when running with network_mode: host, where the "ports" mapping
+ # is ignored and this value becomes the port exposed directly on the host.
+ # - FIRESHARE_PORT=80
# Enable transcoding to create 720p and 1080p variants (default: false)
- ENABLE_TRANSCODING=false
# Enable GPU acceleration for transcoding using NVENC (requires nvidia-docker runtime, default: false)
diff --git a/docs/EnvironmentVariables.md b/docs/EnvironmentVariables.md
index 1e4e426d..a5024886 100644
--- a/docs/EnvironmentVariables.md
+++ b/docs/EnvironmentVariables.md
@@ -37,6 +37,7 @@
| `PUID` | User ID the container process runs as. Useful for matching host file permissions. | `1000` |
| `PGID` | Group ID the container process runs as. Useful for matching host file permissions. | `1000` |
| **Web Server** | | |
+| `FIRESHARE_PORT` | The port the web server (nginx) listens on inside the container. Most users should leave this at `80` and change the host-side `ports` mapping instead; it is primarily useful with `network_mode: host`, where the `ports` mapping is ignored and this value is the port exposed directly on the host. | `80` |
| `GUNICORN_WORKERS` | Number of gunicorn worker processes. On high core-count machines the default formula (`cpu_count × 2 + 1`) can spawn dozens of processes; set this to a fixed value to stay within container PID limits. | `min(cpu_count × 2 + 1, 4)` |
| `GUNICORN_WORKER_CAP` | Upper bound applied to the auto-calculated worker count. Set to `0` to remove the cap entirely and revert to the original `cpu_count × 2 + 1` behaviour. | `4` |
| `GUNICORN_THREADS` | Number of threads per worker process. | `8` |
diff --git a/entrypoint.sh b/entrypoint.sh
index e8c3d7e6..c9452f5c 100755
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -108,6 +108,10 @@ fi
# ── Nginx ─────────────────────────────────────────────────────────────────────
section "Nginx"
+FIRESHARE_PORT=${FIRESHARE_PORT:-80}
+log "Configuring nginx to listen on port ${FIRESHARE_PORT}"
+sed "s/__FIRESHARE_PORT__/${FIRESHARE_PORT}/" \
+ /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
log "Starting nginx"
nginx -g 'daemon on;'
log "Nginx ready"