-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebcal-cleaner.php
executable file
·151 lines (120 loc) · 3.55 KB
/
webcal-cleaner.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/php
<?php
# Webcal cleaner (aka clean that huge iCloud calendars)
# Copyright (C) 2021 Valerio Bozzolan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
// webcal separator of each event
define( 'EVENT_SEPARATOR', "BEGIN:VEVENT" );
// do not display events older than this number of days
define( 'MAX_DAYS', 30 * 6 );
// url
$url = $argv[ 1 ] ?? null;
if( !$url ) {
echo "RTFM missing URL\n";
exit( 1 );
}
// output filename
$OUT_FILE = $argv[ 2 ] ?? null;
if( !$OUT_FILE ) {
echo "RTFM missing output filename\n";
exit( 2 );
}
$start_time = new DateTime();
$cal = file_get_contents( $url );
// how much time to download this shit asd
$download_time = ( new DateTime() )->getTimestamp() - $start_time->getTimestamp();
//
//CREATED:20141203T080231Z
//UID:002455D8-719B-435B-84F9-AC5D56C4B6E9
//DTEND;TZID=Europe/Rome:20141211T233000
//SUMMARY:asd
//DTSTART;TZID=Europe/Rome:20141211T190000
//DTSTAMP:20141203T080231Z
//SEQUENCE:0
//END:VEVENT
//
$events_raw = explode( EVENT_SEPARATOR, $cal );
// header of the calendar
$calendar_start = array_shift( $events_raw );
// counter of filtered events
$filtered = 0;
// interesting events
$events_interesting = $calendar_start;
// total number of events
$last_i = count( $events_raw ) - 1;
// for each raw event
foreach( $events_raw as $i => $event_raw ) {
// the event can be empty (or the first line)
if( $event_raw ) {
// restore separator
$event_raw = EVENT_SEPARATOR . $event_raw;
if( $i > 1 ) {
$event_lines = explode( "\r\n", $event_raw );
$event_sections = event_sections( $event_lines );
// creation date
$created_raw = $event_sections['CREATED'] ?? null;
// no creation date? try last modified
if(!$created_raw) {
$created_raw = $event_sections['LAST-MODIFIED'] ?? null;
}
// check if the creation date has sense
if( !$created_raw ) {
echo "Missing date\n";
var_dump( $event_raw );
continue;
}
// parse the date
$created = DateTime::createFromFormat( 'Ymd\THisO', $created_raw );
if( !$created ) {
echo "Bad date $created_raw\n";
var_dump( $event_raw );
continue;
}
// date diff
$diff = $start_time->diff( $created );
// days ago
$days = $diff->days;
// take only interesting events
// note that the last event is always taken,
// to preserve END:VCALENDAR shit asd
if( $days < MAX_DAYS || $i === $last_i ) {
$events_interesting .= $event_raw;
} else {
$filtered++;
}
}
}
}
// print the shit
file_put_contents( $OUT_FILE, $events_interesting );
// remanining events
$remainings = $last_i - $filtered;
// print stats
echo "Download in {$download_time}s. Filtered $filtered. Kept $remainings.\n";
/**
* Parse event sections in a key=>value form
*/
function event_sections( $event_lines ) {
$lines = [];
foreach( $event_lines as $event_line ) {
if( $event_line ) {
$parts = explode( ':', $event_line, 2 );
if( count( $parts ) === 2 ) {
$lines[ $parts[0] ] = $parts[1];
}
}
}
return $lines;
}