🌺 Midori's 70th Birthday Camera 🌺

Complete Setup Guide with All Code

Print this document for easy reference during setup

ā±ļø TOTAL SETUP TIME: 15-20 minutes
Everything you need is in this document. Follow the steps in order!

šŸ“‹ Quick Checklist

STEP 1: Create Google Apps Script

1.1 Open Google Apps Script

  1. Go to: https://script.google.com
  2. Sign in with your Google account
  3. Click "New Project" button
  4. You'll see a blank code editor

1.2 Paste the Backend Code

  1. Delete any default code in the editor
  2. Copy ALL the code below
  3. Paste it into the editor
  4. Click the disk icon šŸ’¾ to save
  5. Name it: "Midori Birthday Backend"

šŸ“„ GOOGLE APPS SCRIPT CODE (Copy Everything Below)

/**
 * 🌺 MIDORI'S 70TH BIRTHDAY CAMERA - GOOGLE APPS SCRIPT
 * This script saves photos to Google Drive and logs data to a spreadsheet
 */

// šŸ“ CONFIGURATION - Edit these names if you want
var FOLDER_NAME = "Midori 70th Birthday Photos";
var SPREADSHEET_NAME = "Midori Birthday Submissions";

/**
 * Main function that handles POST requests from the camera
 */
function doPost(e) {
  try {
    var data = JSON.parse(e.postData.contents);
    var folder = getOrCreateFolder(FOLDER_NAME);
    var photoFile = savePhotoToDrive(data.photo, data.name, data.frame, data.timestamp, folder);
    logToSpreadsheet(data, photoFile.getUrl());
    
    return ContentService.createTextOutput(JSON.stringify({
      success: true,
      message: "Photo uploaded successfully!",
      photoUrl: photoFile.getUrl(),
      photoId: photoFile.getId()
    })).setMimeType(ContentService.MimeType.JSON);
    
  } catch (error) {
    return ContentService.createTextOutput(JSON.stringify({
      success: false,
      error: error.toString()
    })).setMimeType(ContentService.MimeType.JSON);
  }
}

function getOrCreateFolder(folderName) {
  var folders = DriveApp.getFoldersByName(folderName);
  if (folders.hasNext()) {
    return folders.next();
  } else {
    return DriveApp.createFolder(folderName);
  }
}

function savePhotoToDrive(photoBase64, name, frame, timestamp, folder) {
  var base64Data = photoBase64.split(',')[1];
  var blob = Utilities.newBlob(
    Utilities.base64Decode(base64Data),
    'image/jpeg',
    sanitizeFileName(name) + '_' + frame + '_' + new Date().getTime() + '.jpg'
  );
  var file = folder.createFile(blob);
  file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
  return file;
}

function logToSpreadsheet(data, photoUrl) {
  var spreadsheet = getOrCreateSpreadsheet(SPREADSHEET_NAME);
  var sheet = spreadsheet.getActiveSheet();
  
  if (sheet.getLastRow() === 0) {
    sheet.appendRow(['Timestamp', 'Name', 'Comment', 'Frame Type', 'Photo URL', 'Date/Time']);
    sheet.getRange(1, 1, 1, 6).setFontWeight('bold').setBackground('#ff6b9d').setFontColor('white');
  }
  
  sheet.appendRow([
    data.timestamp,
    data.name,
    data.comment || '(No message)',
    data.frame,
    photoUrl,
    new Date()
  ]);
  
  sheet.autoResizeColumns(1, 6);
}

function getOrCreateSpreadsheet(name) {
  var files = DriveApp.getFilesByName(name);
  if (files.hasNext()) {
    return SpreadsheetApp.open(files.next());
  } else {
    return SpreadsheetApp.create(name);
  }
}

function sanitizeFileName(name) {
  return name.replace(/[^a-z0-9]/gi, '_').substring(0, 50);
}

function testSetup() {
  Logger.log("Testing setup...");
  var folder = getOrCreateFolder(FOLDER_NAME);
  Logger.log("āœ“ Folder created: " + folder.getName());
  Logger.log("Folder URL: " + folder.getUrl());
  var spreadsheet = getOrCreateSpreadsheet(SPREADSHEET_NAME);
  Logger.log("āœ“ Spreadsheet created: " + spreadsheet.getName());
  Logger.log("Spreadsheet URL: " + spreadsheet.getUrl());
  Logger.log("\nāœ… Setup complete!");
}

function generateGalleryHTML() {
  var folder = getOrCreateFolder(FOLDER_NAME);
  var files = folder.getFiles();
  var html = '<div class="birthday-gallery" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; padding: 20px;">\n';
  
  while (files.hasNext()) {
    var file = files.next();
    var imageUrl = "https://drive.google.com/uc?export=view&id=" + file.getId();
    html += '  <div style="border-radius: 15px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.1);">\n';
    html += '    <img src="' + imageUrl + '" style="width: 100%; height: auto; display: block;">\n';
    html += '  </div>\n';
  }
  
  html += '</div>';
  Logger.log(html);
  return html;
}

STEP 2: Deploy the Script

2.1 Create Deployment

  1. Click "Deploy" button (top right)
  2. Select "New deployment"
  3. Click the gear icon āš™ļø next to "Select type"
  4. Choose "Web app"

2.2 Configure Settings

Click "Deploy"

2.3 Authorize Access

  1. Click "Authorize access"
  2. Choose your Google account
  3. You'll see a warning "Google hasn't verified this app"
  4. Click "Advanced"
  5. Click "Go to [project name] (unsafe)"
  6. Click "Allow"
āœļø WRITE DOWN YOUR WEB APP URL:
After deployment, you'll see a URL like:
https://script.google.com/macros/s/AKfycbxXXXXXXXXX/exec

Copy this entire URL! You'll need it in the next step.

MY WEB APP URL: _________________________________

STEP 3: Test the Script

3.1 Run Test Function

  1. In the script editor, find the dropdown at the top (says "Select function")
  2. Click it and select "testSetup"
  3. Click the ā–¶ļø Run button
  4. Wait a few seconds
  5. Click "View" → "Logs" at the bottom

3.2 Verify Success

You should see in the logs:

Click the URLs to verify they exist in your Google Drive!

STEP 4: Update Camera Code

4.1 Find the Line to Edit

  1. Open your cam.html file
  2. Press Ctrl+F (or Cmd+F on Mac)
  3. Search for: YOUR_SCRIPT_ID_HERE
  4. You'll find this line (around line 590):
var SCRIPT_URL = 'https://script.google.com/macros/s/YOUR_SCRIPT_ID_HERE/exec';

4.2 Replace with Your URL

  1. Replace YOUR_SCRIPT_ID_HERE with your actual URL from Step 2.3
  2. Make sure to keep the quotes!
  3. Example of correct line:
var SCRIPT_URL = 'https://script.google.com/macros/s/AKfycbxXXXXXXXX/exec';

4.3 Save and Upload

  1. Save the cam.html file
  2. Upload to your website
  3. Replace the old version if it exists

STEP 5: Test Everything

5.1 Take a Test Photo

  1. Open your website in a browser
  2. Allow camera permissions
  3. Select a frame (Hibiscus, Pineapple, etc.)
  4. Click the camera button to take a photo
  5. Enter your name: "Test User"
  6. Enter a message (optional)
  7. Click "Send to Gallery"
  8. Wait for "Mahalo!" success message

5.2 Verify Upload

  1. Go to Google Drive
  2. Open "Midori 70th Birthday Photos" folder
  3. You should see your test photo!
  4. Open "Midori Birthday Submissions" spreadsheet
  5. You should see your name and data logged!
āœ… If everything works, you're done!
The camera is now live and ready for guests to use!

BONUS: Display Photos on WordPress

Option 1: Auto-Generated Gallery (Recommended)

  1. Go back to your Google Apps Script
  2. Select function: "generateGalleryHTML"
  3. Click ā–¶ļø Run
  4. Click "View" → "Logs"
  5. Copy ALL the HTML code from the logs
  6. In WordPress, create a new page
  7. Add a "Custom HTML" block
  8. Paste the HTML code
  9. Publish!

Re-run this function whenever you want to update the gallery with new photos

Option 2: Embed Live Spreadsheet

  1. Open your "Midori Birthday Submissions" spreadsheet
  2. Click File → Share → Publish to web
  3. Choose "Embed" tab
  4. Copy the iframe code
  5. Paste into WordPress Custom HTML block
  6. Visitors see live updates!

Option 3: WordPress Plugin

  1. Install plugin: "Google Drive WP Media"
  2. Connect your Google account
  3. Select your "Midori 70th Birthday Photos" folder
  4. Create gallery
  5. Auto-updates when new photos arrive!

šŸ“± Using the Camera

For Guests:

Photo Quality:

šŸ”§ Troubleshooting

Camera shows "too zoomed"

Fixed! The updated code uses natural aspect ratio. If still zoomed, try a different browser.

Photos not appearing in Google Drive

  1. Check your Web App URL is correct in cam.html
  2. Make sure script is deployed as "Anyone" can access
  3. Try running testSetup() function again
  4. Check browser console (F12) for error messages

"Script authorization required" error

  1. Go back to Step 2.3
  2. Complete authorization process
  3. Click "Advanced" → "Go to project" → "Allow"

Upload button shows "Uploading..." forever

  1. Check your internet connection
  2. Verify Web App URL is correct
  3. Make sure script is deployed
  4. Try redeploying the script

šŸ“„ Downloading All Photos

Get All Photos at Once

  1. Go to Google Drive
  2. Find "Midori 70th Birthday Photos" folder
  3. Right-click the folder
  4. Click "Download"
  5. Google will create a ZIP file with all photos
  6. Download completes automatically

šŸŽØ Customization Options

Change Folder/Spreadsheet Names

Edit these lines in the Google Apps Script:

var FOLDER_NAME = "Midori 70th Birthday Photos";
var SPREADSHEET_NAME = "Midori Birthday Submissions";

Make Photos Private

In the Google Apps Script, find and remove this line (around line 79):

file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);

Get Email Notifications

Add this code after line 47 in the doPost function:

MailApp.sendEmail({
  to: "your@email.com",
  subject: "New Birthday Photo from " + data.name,
  body: "New submission!\n\nName: " + data.name + "\nMessage: " + data.comment
});

āœ… Final Checklist

šŸŽ‰ You're Ready for the Party!

All photos will automatically save to Google Drive.
Guest information logs to your spreadsheet.
Everything is backed up safely.

Happy 70th Birthday, Midori! 🌺

Need Help?

Check the Google Apps Script "Execution log" for error messages

Use the testSetup() function to verify connections

All photos are timestamped automatically - no duplicates!


Made with aloha 🌺