Skip to content

Commit

Permalink
use Google Calendar instead of an iCal link (4.1.0)
Browse files Browse the repository at this point in the history
  • Loading branch information
RedyAu committed Jan 17, 2024
1 parent 391b81b commit 3edf66f
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 104 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Record On Calendar

An overcomplicated, but pretty smart program to record multitrack audio automatically according to iCal calendar events.
An overcomplicated, but pretty smart program to record multitrack audio automatically according to Google Calendar events.
Fully configurable. (Currently only supports 128 kbps mp3 recording, this can be easily expanded if needed - drop an issue)

_Using FFMPEG / DirectShow (downloads runtime automatically)._
Expand All @@ -12,19 +12,22 @@ _Using FFMPEG / DirectShow (downloads runtime automatically)._
# █▀▄ ██▄ █▄▄ █▄█ █░▀█ █▄▄ █▀█ █▄▄

# Config file generated by Record on Calendar
version: 4.0.1 # Don't change this!
version: 4.1.0 # Don't change this!

# Config file format is YAML. The RecOnCal will try to migrate it to new versions if updated.
# Made by Benedek Fodor in 2022
# Made by Benedek Fodor (RedyAu) in 2022-2024

debug: false # Set to true to see additional messages on console.

##########

# CALENDAR

# iCal link for calendar
link: = PLEASE PUT AN ICAL LINK HERE =
# ID of Google Calendar
calendar_id: = PLEASE PUT A GOOGLE CALENDAR ID HERE =
# API key for Google Calendar
api_key: = PLEASE PUT A GOOGLE API KEY HERE =

# Update frequency of calendar (minutes)
frequency: 30
# Start recording minutes earlier then calendar event start
Expand Down
11 changes: 4 additions & 7 deletions bin/globals.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,13 @@ import 'utils/event.dart';
import 'utils/history.dart';

//TODO changeme
final String version = "4.0.3";
final String version = "4.1.0";

final Directory homeDir = Directory('RecordOnCalendar');
final File configFile = File(p.join(homeDir.path, 'config.yaml'));
final File tracksFile = File(p.join(homeDir.path, 'tracks.yaml'));
final Directory ffmpegDir = Directory(p.join(homeDir.path, 'ffmpeg'));
final Directory ffmpegVersionDir = Directory(p.join(
ffmpegDir.path,
'ffmpeg-5.0.1-essentials_build',
'bin',
));
late final Directory ffmpegVersionDir;
final File ffmpegExe = File(p.join(ffmpegVersionDir.path, 'ffmpeg.exe'));
final Directory recordingsDir = Directory(p.join(homeDir.path, 'recordings'));
final File historyFile = File(p.join(homeDir.path, 'history.json'));
Expand All @@ -28,7 +24,8 @@ int startEarlierByMinutes = 5;
int endLaterByMinutes = 30;
int keepRecordings = 0;
RegExp eventSelectedForRecordMatcher = RegExp(r".");
Uri iCalUri = Uri();
String googleCalendarId = "";
String googleApiKey = "";
int iCalUpdateFrequencyMinutes = 30;

String? smtpHost;
Expand Down
108 changes: 30 additions & 78 deletions bin/utils/calendar.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:http/http.dart';
import 'package:icalendar_parser/icalendar_parser.dart';
import 'package:rrule/rrule.dart';
import 'package:googleapis/calendar/v3.dart' as g;
import 'package:googleapis_auth/googleapis_auth.dart';

import '../globals.dart';
import 'email.dart';
Expand Down Expand Up @@ -32,7 +31,7 @@ Event? getCurrentEvent() {
}
}

Future updateICal() async {
Future updateGoogleCalendar() async {
logger.log("\n${DateTime.now().toFormattedString()} | Updating Calendar");

int nextEventsHash = events
Expand All @@ -42,94 +41,47 @@ Future updateICal() async {
.hashCode;

try {
var req = await get(iCalUri).timeout(Duration(seconds: 30));
String iCalString = req.body;

List<Event> _events = [];

ICalendar iCalendar = ICalendar.fromString(iCalString);

for (Map vEvent
in iCalendar.data.where((data) => data["type"] == "VEVENT")) {
List<Event> _eventsFromEntry = [];

RecurrenceRule? rrule = (vEvent['rrule'] != null)
? RecurrenceRule.fromString('RRULE:${vEvent['rrule']}')
: null;

String uid = vEvent["uid"];
DateTime start =
DateTime.parse((vEvent["dtstart"] as IcsDateTime).dt).toLocal();
DateTime end =
DateTime.parse((vEvent["dtend"] as IcsDateTime).dt).toLocal();
String summary = vEvent["summary"];
String description = vEvent["description"] ?? "";

if (eventSelectedForRecordMatcher.hasMatch(summary + description)) {
//? Add single event when no RRULE is set
if (rrule == null) {
_eventsFromEntry.add(Event(
uid,
start,
end,
summary,
description,
rruleGenerated: false,
));
} else {
Duration duration = end.difference(start);

//? Make events based on RRULE
for (DateTime generatedStart in rrule
.getAllInstances(
start: start.toUtc(),
before: DateTime.now().add(Duration(days: 90)).toUtc(),
)
.map((e) => e.toLocal())
.toList()) {
DateTime generatedEnd = generatedStart.add(duration);
try {
if ((vEvent["exdate"] as List<IcsDateTime?>?)?.any((element) =>
element?.toDateTime()?.isAtSameMomentAs(generatedStart) ??
false) ??
false)
continue; //If excluded date list is null, don't exclude event. If excluded date parse fails, don't exclude event.
} catch (e, s) {
logger.log(
"WARNING: Error while parsing excluded date list for event. Skipping.\n$e\n$s");
continue;
}
_eventsFromEntry.add(Event(
uid,
generatedStart,
generatedEnd,
summary,
description,
rruleGenerated: true,
));
}
g.CalendarApi calendar = await g.CalendarApi(clientViaApiKey(googleApiKey));

for (g.Event gEvent in (await calendar.events.list(
googleCalendarId,
singleEvents: true, // THANK YOU GOOGLE 💖
timeMin: DateTime.now().subtract(Duration(days: 1)).toUtc(),
maxResults: 100,
orderBy: "startTime",
timeZone: "Europe/Budapest",
))
.items!) {
try {
var event = Event(
gEvent.iCalUID!,
gEvent.start!.dateTime!.toLocal(),
gEvent.end!.dateTime!.toLocal(),
gEvent.summary!,
gEvent.description ?? "",
);
if (eventSelectedForRecordMatcher
.hasMatch(event.title + '\n' + event.description)) {
_events.add(event);
}
} catch (e) {
logger.log("Couldn't parse an event from the calendar, skipping: $e");
continue;
}

_events.addAll(_eventsFromEntry);
}

_events.removeWhere((generatedEvent) => _events
.where((allEventsMember) => allEventsMember.rruleGenerated == false)
.any((notGeneratedEvent) =>
notGeneratedEvent.start.isAtSameMomentAs(generatedEvent.start) &&
generatedEvent.rruleGenerated == true));

_events.sort((a, b) => a.title.compareTo(b.title));
_events.sort((a, b) => a.start.compareTo(b.start));

events.clear();
events.addAll(_events);

logger.log("Got ${events.length} events marked for recording.");
} catch (e, stack) {
} catch (e, s) {
logger.log(
"Exception occured while updating calendar: $e\nContinuing with already downloaded events.\n$stack");
"Exception occured while updating calendar: $e\nContinuing with already downloaded events.\n$s");
}

int updatedNextEventsHash = events
Expand Down
28 changes: 17 additions & 11 deletions bin/utils/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import 'log.dart';

String generateConfigText({
bool? debug = false,
String link = "= PLEASE PUT AN ICAL LINK HERE =",
int frequency = 30,
int earlier = 5,
int later = 30,
String regex = ".",
String? google_calendar_id = "= PLEASE PUT A GOOGLE CALENDAR ID HERE =",
String? google_api_key = "= PLEASE PUT A GOOGLE API KEY HERE =",
int? frequency = 30,
int? earlier = 5,
int? later = 30,
String? regex = ".",
String? ftphost,
String? username,
String? password,
Expand Down Expand Up @@ -40,16 +41,19 @@ String generateConfigText({
version: $version # Don't change this!
# Config file format is YAML. The RecOnCal will try to migrate it to new versions if updated.
# Made by Benedek Fodor in 2022
# Made by Benedek Fodor (RedyAu) in 2022-2024
debug: ${debug ?? false} # Set to true to see additional messages on console.
##########
# CALENDAR
# iCal link for calendar
link: $link
# ID of Google Calendar
calendar_id: $google_calendar_id
# API key for Google Calendar
api_key: $google_api_key
# Update frequency of calendar (minutes)
frequency: $frequency
# Start recording minutes earlier then calendar event start
Expand Down Expand Up @@ -137,7 +141,8 @@ loadConfig() {
configFile.writeAsStringSync(
generateConfigText(
debug: config['debug'],
link: config['link'],
google_calendar_id: config['calendar_id'],
google_api_key: config['api_key'],
frequency: config['frequency'],
earlier: config['earlier'],
later: config['later'],
Expand Down Expand Up @@ -170,7 +175,8 @@ loadConfig() {
//! Load
try {
debug = config['debug'];
iCalUri = Uri.parse(config['link']!);
googleCalendarId = config['calendar_id']!;
googleApiKey = config['api_key']!;
iCalUpdateFrequencyMinutes = config['frequency'];
startEarlierByMinutes = config['earlier'];
endLaterByMinutes = config['later'];
Expand All @@ -194,7 +200,7 @@ loadConfig() {
calendarEmailContent = config['calendarEmailContent'];
} catch (e, s) {
logger.log(
"Could not get config values! If this error persists, please delete config.yaml and let the program regenerate it by restarting.\n\n ####> Are you sure you supplied an iCal link? <####\n\n$e\n$s");
"Could not get config values! If this error persists, please delete config.yaml and let the program regenerate it by restarting.\n\n$e\n$s");
stdin.readLineSync();
exit(1);
}
Expand Down
4 changes: 1 addition & 3 deletions bin/utils/event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ class Event {
DateTime end;
String title;
String description;
bool rruleGenerated;

Event(this.uid, this.start, this.end, this.title, this.description,
{required bool this.rruleGenerated});
Event(this.uid, this.start, this.end, this.title, this.description);

String get fileName =>
'${start.toFormattedString()} - $title'.getSanitizedForFilename();
Expand Down

0 comments on commit 3edf66f

Please sign in to comment.