A full-featured interactive polling web application for playing "Marry, F, Kill" with custom images. Built with Flask, Socket.IO for real-time updates, and designed to run in Docker on Unraid.
- Folder-Based Organization: Organize images into folders by theme, event, or category
- Selective Polling: Create polls from specific folders or all folders combined
- Advanced Image Upload: Multi-file support via browser/drag/paste, URL paste, auto-resize, preview & rename
- Image Management: Upload, rename, delete images, and toggle their availability for polls
- Admin Control Panel: Full control over poll creation, execution, and results
- Real-time Updates: Live results using WebSockets
- Mobile-First Design: Optimized for mobile devices with drag-and-drop interface
- QR Code Access: Generate QR codes for users to join polls easily
- No Login Required: Users join via session-based identifiers
- Persistent Storage: SQLite database stores all data locally
- Live Results: See results update in real-time as users submit
- Cumulative Results: View overall statistics across all poll groups
MarryFKill_Quiz/
├── app.py # Main Flask application
├── database.py # Database models and initialization
├── requirements.txt # Python dependencies
├── Dockerfile # Docker configuration
├── .dockerignore # Docker ignore file
├── .gitignore # Git ignore file
├── README.md # This file
├── images/ # Image storage (organized by folders)
│ ├── default/ # Default folder
│ ├── characters/ # Example folder
│ └── party2024/ # Example folder
├── static/
│ ├── css/
│ │ └── style.css # Main stylesheet
│ └── js/
│ ├── main.js # Common JavaScript
│ ├── admin.js # Admin panel JavaScript
│ └── poll.js # Poll interface JavaScript
└── templates/
├── base.html # Base template
├── index.html # Home page
├── admin.html # Admin panel
└── poll.html # User poll interface
- Docker installed on your system
- Images to use for polls (JPEG, PNG, GIF, or WebP)
-
Clone or download this repository
-
Add your images
- Organize images into folders:
images/default/,images/characters/, etc. - Supported formats:
.png,.jpg,.jpeg,.gif,.webp - Images are automatically detected on startup
- Use the Folder Manager UI at
/admin/folders/manageto create folders - Note: On first run, existing images are migrated to
images/default/
- Organize images into folders:
-
Build the Docker image
docker build -t fmk-quiz . -
Run the container
docker run -d \ --name fmk-quiz \ -p 5000:5000 \ -v /path/to/your/images:/app/images \ -v /path/to/your/data:/app/data \ fmk-quiz
Replace
/path/to/your/imageswith the path to your images folder.
-
Open Unraid Docker tab
-
Add Container with these settings:
- Name:
fmk-quiz - Repository:
fmk-quiz(after building the image) - Network Type:
bridge - Port:
5000→5000 - Volume 1:
/mnt/user/appdata/fmk-quiz/images→/app/images - Volume 2:
/mnt/user/appdata/fmk-quiz/data→/app/data
- Name:
-
Create the directories on Unraid:
mkdir -p /mnt/user/appdata/fmk-quiz/images mkdir -p /mnt/user/appdata/fmk-quiz/data
-
Add your images to
/mnt/user/appdata/fmk-quiz/images -
Start the container
This instance runs on an Unraid server (root@Tower) at /mnt/user/appdata/CakeSite/,
where the repo is cloned and run via docker-compose (host port 8765 → container 5000).
It is served publicly at https://cake.saltychart.net via a reverse proxy.
To deploy a code change (no database schema change), from the project directory on the server:
cd /mnt/user/appdata/CakeSite
git pull origin main
docker-compose build # code is baked into the image (COPY . .), so a rebuild is required
docker-compose up -d # recreates the container — `docker-compose down` is NOT needed
docker-compose logs -f # optional: confirm a clean startDo not delete
data/fmk_quiz.dbfor ordinary updates — that step inUPDATE_GUIDE.mdapplies only to the one-time folder-schema migration.
- Live site: https://cake.saltychart.net
- Home Page:
http://your-server-ip:8765/ - Admin Panel:
http://your-server-ip:8765/admin - User Poll:
http://your-server-ip:8765/poll
-
Manage Folders (
/admin/folders/manage):- Create new folders (e.g., "characters", "party2024")
- View folders with image counts
- Delete empty folders
-
Upload Images (
/admin/images/manage):- Select folder from dropdown
- Upload, rename, or delete images
- Toggle images as Active/Inactive
-
Navigate to Admin Panel (
/admin) -
Manage Images Tab:
- View all images organized by folder
- Toggle images as Active/Inactive
- Only active images will be included in polls
-
Poll Control Tab:
- Select folder from dropdown (specific folder or "All Folders")
- Click "Generate QR Code" to create a QR code for users
- Click "Create New Poll" to generate a poll with images from selected folder(s)
- Click "Start Poll" to activate the first group
- Monitor live submissions for the current group
- Click "Next Group" to move to the next set of 3 images
- Click "End Poll" when finished
-
Results Tab:
- Current Group: See results for the active group
- Cumulative Results: See overall results across all groups
- Results update automatically in real-time
-
Scan QR Code or navigate to
/poll -
Wait for poll to start (if not already active)
-
Drag and drop each of the 3 images into the appropriate category:
- 💍 Marry: The one you'd marry
- 🔥 F: The one you'd... well, you know
- 💀 Kill: The one you'd eliminate
-
Click Submit once all three images are assigned
-
View Results immediately after submitting
-
Wait for next group - the page will automatically update when the admin moves to the next group
When you create a poll, the system:
- Gets all active images
- Shuffles them randomly
- Creates groups of 3 images (non-overlapping)
- Stores all groups in the database
- User assigns each image to exactly one category
- Backend validates that all three images are different
- Submission is saved to the database
- Results are calculated and broadcast to all connected clients
- User sees live results immediately
The application uses Socket.IO for real-time communication:
- Poll start notifications
- Group changes
- Live result updates
- Submission counts
All data is stored in a SQLite database (fmk_quiz.db):
- Images: Filenames and active status
- Polls: Poll sessions with start/end times
- Poll Groups: Sets of 3 images for each round
- Submissions: User choices for each group
id: Primary keyfilename: Image filenamefolder: Folder name (nullable)is_active: Boolean for availabilitycreated_at: Timestamp- Unique Constraint: (folder, filename) - Same filename allowed in different folders
id: Primary keyname: Folder name (unique, alphanumeric + underscore/hyphen)display_name: Human-readable namecreated_at: Timestamp
id: Primary keystatus: setup, active, or endedstarted_at: Poll start timeended_at: Poll end timecurrent_group: Active group numbercreated_at: Timestamp
id: Primary keypoll_id: Foreign key to Pollsgroup_number: Group sequence numberimage1_id,image2_id,image3_id: Foreign keys to Imagescreated_at: Timestamp
id: Primary keypoll_id: Foreign key to Pollsgroup_id: Foreign key to PollGroupsuser_id: Session-based user identifiermarry_image_id: Foreign key to Imagesf_image_id: Foreign key to Imageskill_image_id: Foreign key to Imagessubmitted_at: Timestamp
Folder Management:
GET /admin/folders- Get all folders with image countsPOST /admin/folders- Create new folderDELETE /admin/folders/<id>- Delete folder (only if empty)
Image Management:
GET /admin/images- Get all imagesPOST /admin/images/upload- Upload image (requires folder parameter)POST /admin/images/<id>/toggle- Toggle image active statusPOST /admin/images/<id>/rename- Rename imagePOST /admin/images/<id>/delete- Delete image
Poll Management:
POST /admin/poll/create- Create new poll (optional folder parameter)GET /admin/poll/current- Get current poll statusPOST /admin/poll/<id>/start- Start pollPOST /admin/poll/<id>/next-group- Move to next groupPOST /admin/poll/<id>/end- End pollGET /admin/poll/<id>/results/current- Get current group resultsGET /admin/poll/<id>/results/cumulative- Get cumulative resultsGET /admin/qr- Generate QR code
Smash or Pass:
POST /smashpass/session/create- Create session (optional folder parameter)GET /smashpass/session/current- Get current sessionPOST /smashpass/session/<id>/next- Move to next imagePOST /smashpass/session/<id>/end- End sessionGET /smashpass/remote- Authenticated remote-control page (Next/End only) for the active session
GET /poll/current- Get current active poll and groupPOST /poll/submit- Submit poll choicesGET /poll/results/<group_id>- Get results for a group
poll_started- Emitted when poll startsgroup_changed- Emitted when moving to next grouppoll_ended- Emitted when poll endsresults_updated- Emitted when new submissions arrive
Edit the docker run command or Dockerfile to use a different port:
docker run -p 8080:5000 fmk-quizVia UI (Recommended):
- Navigate to
/admin/folders/manageto create folders - Go to
/admin/images/manageto upload images:- Single/Multiple files: Click "Upload Images" or drag & drop
- From clipboard: Copy image files → Ctrl+V (supports multiple!)
- From URL: Copy image URL → Ctrl+V → Preview & rename
- Auto-resize: Large images (>1920px) automatically optimized
Via Filesystem:
- Create folders in
images/directory (e.g.,images/party2024/) - Add image files to the folders
- Restart the container - new images will be automatically detected
- Use "Sync Database" button to add them to database
Modify static/css/style.css to customize the appearance.
For production, set a secure secret key:
docker run -e SECRET_KEY='your-secret-key-here' -p 5000:5000 fmk-quiz- Check that images are in the
images/folder - Verify the volume mount is correct
- Restart the container
- Verify the server IP and port
- Check firewall settings
- Ensure the container is running:
docker ps
- Delete the database file and restart:
rm fmk_quiz.db - Check volume permissions
- Ensure port 5000 is accessible
- Check browser console for errors
- Try refreshing the page
To run in development mode:
# Install dependencies
pip install -r requirements.txt
# Run with Flask development server
python app.pyThe app will be available at http://localhost:5000 with debug mode enabled.
- Change the
SECRET_KEYin production - Consider adding authentication for the admin panel
- Use HTTPS in production (reverse proxy recommended)
- The application is designed for trusted networks (parties, events, etc.)
This project is provided as-is for educational and entertainment purposes.
For issues or questions, please check the troubleshooting section or review the code comments.
Built with:
- Flask
- Flask-SocketIO
- SQLAlchemy
- Socket.IO
- QRCode
Enjoy your FMK Quiz! 🎉