diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..8ab6294
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+flask
\ No newline at end of file
diff --git a/templates/camera_view.html b/templates/camera_view.html
new file mode 100644
index 0000000..3633165
--- /dev/null
+++ b/templates/camera_view.html
@@ -0,0 +1,790 @@
+
+
+
+
+
+ {{ camera_view_name }} Camera - TeslaCam
+
+
+
+
+
+
+
+
+
+
{{ camera_view_name }} Camera
+ {{ videos | length }} Clips
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Select a video clip from the queue to play
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..6da8288
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,1051 @@
+
+
+
+
+
+ TeslaCam Video Player
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Front
+
+
+
+
Select a clip from the list to begin playback
+
+
+
+
+
+
Camera Angles — Same Timestamp
+
+ Select a video to unlock synchronized camera switching.
+
+
+
+
+ Now Playing: —
+ —
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/videoplayer.py b/videoplayer.py
new file mode 100644
index 0000000..8f0c922
--- /dev/null
+++ b/videoplayer.py
@@ -0,0 +1,135 @@
+"""
+TeslaCam Video Player
+
+This web app displays TeslaCam videos and allows users to change the camera view.
+
+It scans the TeslaCam folder for all videos and stores a list sorted by filename
+and categorized by camera view (format YYYY-MM-DD_HH-MM-SS-${camera_view}.mp4).
+The app then displays the videos in a web interface, allowing users to select and
+play videos from different camera views.
+"""
+
+import os
+import re
+from flask import Flask, render_template, send_from_directory, abort
+
+app = Flask(__name__)
+
+# Root TeslaCam directory containing RecentClips, SavedClips, SentryClips, etc.
+TESLACAM_DIRECTORY = r'W:\2026\USA2026\TeslaCam'
+
+# Regular expression matching TeslaCam filenames: YYYY-MM-DD_HH-MM-SS-${camera_view}.mp4
+VIDEO_FILENAME_REGEX = re.compile(
+ r'^(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})-(\w+)\.mp4$'
+)
+
+# Friendly display names for camera views
+CAMERA_VIEW_MAPPING = {
+ 'front': 'Front',
+ 'left_repeater': 'Left Repeater',
+ 'right_repeater': 'Right Repeater',
+ 'rear': 'Rear',
+ 'left_pillar': 'Left Pillar',
+ 'right_pillar': 'Right Pillar'
+}
+
+
+def scan_teslacam_videos():
+ """
+ Recursively scans the TeslaCam directory tree for video files and categorizes
+ them by camera view.
+
+ Returns:
+ dict: Keys are raw camera view identifiers (e.g. 'front'), values are lists
+ of dictionaries containing file details sorted chronologically.
+ """
+ videos_by_camera = {}
+
+ if not os.path.exists(TESLACAM_DIRECTORY):
+ return videos_by_camera
+
+ # Recursive directory walk to catch nested folders in SavedClips/SentryClips
+ for root, _, files in os.walk(TESLACAM_DIRECTORY):
+ for filename in files:
+ match = VIDEO_FILENAME_REGEX.match(filename)
+ if match:
+ timestamp, camera_view = match.groups()
+
+ # Get path relative to TESLACAM_DIRECTORY for safe web serving
+ full_path = os.path.join(root, filename)
+ rel_path = os.path.relpath(
+ full_path, TESLACAM_DIRECTORY).replace('\\', '/')
+
+ video_entry = {
+ 'filename': filename,
+ 'timestamp': timestamp,
+ 'rel_path': rel_path,
+ 'url': f'/video/{rel_path}'
+ }
+
+ if camera_view not in videos_by_camera:
+ videos_by_camera[camera_view] = []
+ videos_by_camera[camera_view].append(video_entry)
+
+ # Sort each camera list chronologically by filename/timestamp
+ for camera_view in videos_by_camera:
+ videos_by_camera[camera_view].sort(key=lambda item: item['filename'])
+
+ return videos_by_camera
+
+
+def get_camera_display_name(camera_view):
+ """Returns human-readable title for a camera view key."""
+ return CAMERA_VIEW_MAPPING.get(camera_view, camera_view.replace('_', ' ').title())
+
+
+@app.route('/')
+def index():
+ """
+ Main page listing all videos categorized by human-readable camera view.
+ """
+ all_videos = scan_teslacam_videos()
+
+ # Map raw camera keys to display names for rendering
+ categorized_videos = {}
+ for camera_view, video_list in all_videos.items():
+ display_name = get_camera_display_name(camera_view)
+ categorized_videos[display_name] = {
+ 'raw_key': camera_view,
+ 'videos': video_list
+ }
+
+ return render_template('index.html', categorized_videos=categorized_videos)
+
+
+@app.route('/camera/')
+def camera_view(camera_view):
+ """
+ Displays all available videos for a single camera view.
+ """
+ all_videos = scan_teslacam_videos()
+ videos = all_videos.get(camera_view, [])
+ display_name = get_camera_display_name(camera_view)
+
+ return render_template(
+ 'camera_view.html',
+ camera_view_key=camera_view,
+ camera_view_name=display_name,
+ videos=videos
+ )
+
+
+@app.route('/video/')
+def serve_video(filepath):
+ """
+ Safely streams video files from the TeslaCam directory structure.
+ """
+ full_path = os.path.join(TESLACAM_DIRECTORY, filepath)
+ if not os.path.exists(full_path):
+ abort(404, description="Video file not found")
+
+ return send_from_directory(TESLACAM_DIRECTORY, filepath)
+
+
+if __name__ == '__main__':
+ app.run(debug=True)