AppsScript - Automate Google Calendar Colors

title: Contents 
style: nestedList # TOC style (nestedList|inlineFirstLevel)
minLevel: 1 # Include headings from the specified level
maxLevel: 4 # Include headings up to the specified level
includeLinks: true # Make headings clickable
debugInConsole: false # Print debug info in Obsidian console
// Global debug setting
// true: print info for every event
// false: print info for only newly colorized event
const DEBUG = false
 
 
/* Entry for the whole colorizing magic.
   Select this function when deploying it and assigning a trigger function
*/
function colorizeCalendar() {
 
  const pastDays = 1 // looking 1 day back to catch last minute changes
  const futureDays = 7 * 4 // looking 4 weeks into the future
 
  const now       = new Date()
  const startDate = new Date(now.setDate(now.getDate() - pastDays))
  const endDate   = new Date(now.setDate(now.getDate() + futureDays))
  // Extracting the domain of your email, e.g. company.com
  const myOrg     = CalendarApp.getDefaultCalendar().getName().split("@")[1];
 
  // Get all calender events within the defined range
  // For now only from the default calendar
  var calendarEvents = CalendarApp.getDefaultCalendar().getEvents(startDate, endDate)
 
 
  if (DEBUG) {
   console.log("Calendar default org: " + myOrg)
  }
 
 
  // Walk through all events, check and colorize
  for (var i=0; i<calendarEvents.length; i++) {
 
 
    // Skip for better performance, else go to colorizing below
    if (skipCheck(calendarEvents[i])) {
      continue
    }
    colorizeByRegex(calendarEvents[i], myOrg)
  }
}
 
 
/* Performance tweak: skip all events, that do no longer have the DEFAULT color,
   or have been declined already.
   This avoids overriding user settings and doesn't burn regex / string ops
   for allready adjusted event colors.
 
 
   @param CalendarEvent
*/  
function skipCheck(event) {
 
 
 if(event.getColor() != "" || event.getMyStatus() == CalendarApp.GuestStatus.NO) {
      if(DEBUG) {
        console.log("Skipping already colored / declined event:" + event.getTitle())
      }
      return true
    }
 return false
}
 
 
/* Actual colorizing of events based on Regex matching.
   Makes only sense for frequent stuff you want to auto colorize.
   Order matters for performance! Function exits after first matching color set.
   
   https://developers.google.com/apps-script/reference/calendar/event-color
   Mapping of Google Calendar color names to API color names (Kudos to Jason!):
   https://lukeboyle.com/blog/posts/google-calendar-api-color-id
   @param CalendarEvent
   @param String
*/
function colorizeByRegex(event, myOrg) {
 
 
  // Converting to lower case for easier matching.
  // Keep lower case in mind when defining your regex(s) below!
  eventTitle = event.getTitle().toLowerCase()
 
  // Check for "blockers" in my calendar
    if (/dnb/.test(eventTitle) ||
        /blocker/.test(eventTitle)) {
     
      console.log("Colorizing DNB found: " + eventTitle)
      event.setColor(CalendarApp.EventColor.YELLOW)
      return
    }
 
 
    // Check for travel related entries
    if(/journey from/.test(eventTitle) ||
       /stay at/.test(eventTitle ||
       /flight to/.test(eventTitle))) {
 
 
      console.log("Colorizing travel found: " + eventTitle)
      event.setColor(CalendarApp.EventColor.GREEN)
      return
    }
 
 
    /* Check external participation.
       NB: If there are no external participants, one could mark this
       with the "INTERNAL" color. But that would also colorize
       e.g. trainings or events as "INTERNAL", which is technically
       correct, but you might want to give those a "special" color.
    */
    if (checkForExternal(event, myOrg)) {
     
      console.log("Colorizing external event found: " + eventTitle)
      event.setColor(CalendarApp.EventColor.RED)
      return
    }
 
 
    // Check for my team name to mark internal meetings
    // or myself for 1:1s
    if (/my team name/.test(eventTitle) ||
        /shortname/.test(eventTitle) ||
        /mathias/.test(eventTitle)) {
 
 
      console.log("Colorizing internal stuff found: " + eventTitle)
      event.setColor(CalendarApp.EventColor.BLUE)
      return
    }
 
 
    // Check for interviews
    if (/interview/.test(eventTitle)) {
 
 
      console.log("Colorizing interview stuff found: " + eventTitle)
      event.setColor(CalendarApp.EventColor.PALE_RED)
      return
    }
 
 
    // Check for training related meetings
    if (/training/.test(eventTitle) ||
        /class/.test(eventTitle) ||
        /'some thing' release demo/.test(eventTitle)) {
     
      console.log("Colorizing training found: " + eventTitle)
      event.setColor(CalendarApp.EventColor.ORANGE)
      return
    }
 
 
    // No match found, therefore no colorizing
    else {
      console.log("No matching rule for: " + eventTitle)
    }
}
 
 
/* Check participants for external domain other than myOrg. Requires adjustment
   if you have multiple "internal" domains, like company.com and company.de.
   The first external participant match exits this function.
   @param CalendarEvent
   @param String
*/
function checkForExternal(event, myOrg) {
 
  // Create guest list including organizer -> true parameter
  const guestList = event.getGuestList(true)
 
  // Building guest email and domain arrays, not needed by me.
  // Uncomment if you need it
  /*
  var guestEmails = []
  var guestDomains = []
 
 
  for (guest of guestList) {
    guestEmails.push(guest.getEmail())
    guestDomains.push(guest.getEmail().split("@")[1])
    if (DEBUG)
    console.log("Participant emails are: " + guestEmails)
  }
  */
 
 
  for (guest of guestList) {
 
 
    // get domain of guest and match to my domain
    if (guest.getEmail().split("@")[1] != myOrg) {
     
      console.log("External domain found: " +
        guest.getEmail().split("@")[1] + " in " + event.getTitle())
      return true
    }
  }
  return false
}