edition = "2023"; package ottrec.v1; import "google/protobuf/timestamp.proto"; option features.field_presence = IMPLICIT; // underscored fields are ones which contain data parsed or otherwise enriched // by the scraper rather than coming directly from the source page, and are set // on a best-effort basis (if an error occurs, it is ignored) erring on the side // of safety // non-underscored fields have minimal processing done to them message Data { repeated Facility facilities = 1; repeated string attribution = 2; } message Facility { string name = 1; string description = 2 [json_name="desc"]; Source source = 3; string address = 4; LngLat _lnglat = 5 [json_name="_lnglat", features.field_presence=EXPLICIT]; string notifications_html = 6; // raw html string special_hours_html = 7; // raw html repeated ScheduleGroup schedule_groups = 8; repeated string _errors = 9 [json_name="_errors"]; // scrape errors } message Source { string url = 1; google.protobuf.Timestamp _date = 2 [json_name="_date", features.field_presence=EXPLICIT]; // unix epoch seconds } message LngLat { float lng = 1; float lat = 2; } message ScheduleGroup { string label = 1; string _title = 2 [json_name="_title"]; // for display and filtering, parsed out from the label and normalized, title case string schedule_changes_html = 3; // raw html repeated Schedule schedules = 4; repeated ReservationLink reservation_links = 5; bool _noresv = 6 [json_name="_noresv"]; // set if there's top-level text explicitly saying reservations not required (also see Activity._resv) } message Schedule { message ActivityDay { repeated TimeRange times = 1; } message Activity { string label = 1; string _name = 2 [json_name="_name"]; // for filtering, cleaned up and normalized, lowercase bool _resv = 4 [json_name="_resv", features.field_presence=EXPLICIT]; // unset if no explicit reservation requirement stated, false or true otherwise repeated ActivityDay days = 3; // corresponds to days } string caption = 1; string _name = 2 [json_name="_name"]; // for filtering, parsed out from the caption and normalized (i.e., without facility name or date range), lowercase string _date = 5 [json_name="_date"]; // raw date range, not set if something which looks like a date can't be found in the caption int32 _from = 6 [json_name="_from", features.field_presence=EXPLICIT]; // inclusive from date (YYYYMMDDW), not set if none, parse error, or ambiguous int32 _to = 7 [json_name="_to", features.field_presence=EXPLICIT]; // inclusive to date (YYYYMMDDW), not set if none, parse error, or ambiguous repeated string days = 3; // free-form, but usually the day of the week repeated int32 _daydates = 8 [json_name="_daydates"]; // best-effort parsed version of days (YYYYMMDDW), zero if cannot be parsed unambiguously (note: this is stricter than the TimeRange._wkday field) repeated Activity activities = 4; } message TimeRange { string label = 1; int32 _start = 2 [json_name="_start", features.field_presence=EXPLICIT]; // minutes from 00:00, not set if parse error int32 _end = 3 [json_name="_end", features.field_presence=EXPLICIT]; // minutes from 00:00, not set if parse error Weekday _wkday = 4 [json_name="_wkday", features.field_presence=EXPLICIT];// sunday = 0, not set if parse error } message ReservationLink { string label = 1; string url = 2; } enum Weekday { option features.enum_type = CLOSED; SUNDAY = 0; MONDAY = 1; TUESDAY = 2; WEDNESDAY = 3; THURSDAY = 4; FRIDAY = 5; SATURDAY = 6; }