-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpical2org.py
More file actions
234 lines (186 loc) · 6.64 KB
/
Copy pathpical2org.py
File metadata and controls
234 lines (186 loc) · 6.64 KB
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#!/usr/bin/python3
import os
import sys
import argparse
from datetime import datetime, timedelta
from icalendar import Calendar
import recurring_ical_events
from urllib.request import urlopen
import validators
WINDOW = 365
def org_date(dateTime):
if isinstance(dateTime, datetime):
return dateTime.astimezone().strftime("<%Y-%m-%d %a %H:%M>")
else:
return dateTime.strftime("<%Y-%m-%d %a>")
def create_header(title="Calendar", author="", email=""):
results = ""
results += "#+TITLE: {}\n".format(title)
results += "#+AUTHOR: {}\n".format(author)
results += "#+EMAIL: {}\n".format(email)
results += "#+DESCRIPTION: converted using the Pical2org python script\n"
results += "#+CATEGORY: calendar\n"
results += "\n\n"
return results
class orgEvent:
def __init__(self, event):
# Store the summary of the event
if event.get("summary") is not None:
self.summary = event.get("summary")
self.summary = self.summary.replace("\\,", ",")
else:
self.summary = "(No title)"
# Store the start and end time of the event
self.dtstart = event.get("dtstart").dt
self.isDateTime = isinstance(self.dtstart, datetime)
if event.get("dtend") is not None:
self.dtend = event.get("dtend").dt
# If all day event, then dtstart and dtend are datetime.date
# objects and dtend is exactly one day in the future.
# The dtend can be removed to make it more elegant in org-mode
if not self.isDateTime and self.dtend == self.dtstart + timedelta(days=1):
self.dtend = None
else:
self.dtend = None
# Store the description of the event
if event.get("description") is not None:
self.description = "\n".join(event.get("description").split("\\n"))
self.description = self.description.replace("\\,", ",")
else:
self.description = ""
def __str__(self):
results = ""
results = "* {}\n".format(self.summary)
# Event has a start time and end time
if self.dtstart and self.dtend:
results += "{}--{}\n".format(
org_date(self.dtstart),
org_date(self.dtend),
)
# Event only has a start time
elif self.dtstart and not self.dtend:
results += "{}\n".format(org_date(self.dtstart))
results += "{}\n".format(self.description)
return results
class Convertor:
def __init__(self, args):
icalFile = self.read_file(args.INPUT_FILE)
self.calendar = Calendar.from_ical(icalFile.read())
self.startDate = datetime.now() - timedelta(days=WINDOW)
self.endDate = datetime.now() + timedelta(days=WINDOW)
def __call__(self):
results = ""
results = create_header()
events = recurring_ical_events.of(self.calendar).between(
self.startDate, self.endDate
)
for component in events:
event = orgEvent(component)
results += str(event)
return results
def read_file(self, path):
"""Open the file from the local system or a url and return it
Take a string representing either a url of a file or a name of
a local file and return the open file.
Parameters
----------
file_name : str
A url of a remote file or a path to a local file
"""
# Check to see if path is a remote url
if validators.url(path) is True:
f = urlopen(path)
# Otherwise, assume it is a local path
else:
try:
f = open(path, "r", encoding="utf-8")
except OSError:
print("Could not open/read file: ", f)
sys.exit()
return f
def create_parser():
"""Creates the default ArgumentParser object for the script
Creates a parser using the argparse library to collect arguments
from the command line. These arguments are then stored as and
ArgumentParser object and returned.
Returns
-------
ArgumentParser
An ArgumentParser object
"""
# Create the parser
parser = argparse.ArgumentParser(
description=(
"Converts an ical (.ics) file into a text file formatted for use in Emacs"
" org-mde."
),
add_help=True,
fromfile_prefix_chars="@",
)
# Tell the parser which version of the script this is
parser.version = "1.0"
# Add an argument to accept an input file
parser.add_argument(
"INPUT_FILE",
help=(
"A ical (.ics) file to be read. This can either be a path to a local or it"
" may be a url to a remote file."
),
)
# Add an option to output results to a file instead of stdout
parser.add_argument(
"-o",
"--output",
help="Name of file to store the output results.",
action="store",
type=str,
nargs=1,
metavar="OUTPUT_FILE",
)
# Add a window determining how many days to convert events
parser.add_argument(
"-w",
"--window",
help="Length of time before and after today in which events will be collected",
action="store",
type=int,
nargs="?",
default=365,
)
# Add an option to force clobbering of the output file
parser.add_argument(
"-f",
"--force_clobber",
help=(
"Force clobbering of and output file i the file already exists. If this"
" option is provided, the output file will overwrite the existing file with"
" the same name."
),
action="store_true",
default=False,
)
return parser
def main():
parser = create_parser()
args = parser.parse_args()
WINDOW = args.window
# Check to see if results should be saved to a file
if args.output:
# Check if a file with the same name as output file exists
if os.path.exists(args.output[0]) and not args.force_clobber:
print(
"File {outfile} exists.\nPlease specify a new name or run"
"script again with -f to force clobbering of existing "
"file".format(outfile=args.output[0])
)
else:
convertor = Convertor(args)
with open(args.output[0], "w") as outFile:
outFile.write(convertor())
# If no output file is given print data to stdout
else:
convertor = Convertor(args)
print(convertor())
# If this file is called directly, then execute main()
if __name__ == "__main__":
main()