forked from Ippo343/splitics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
splitvcs.py
executable file
·98 lines (72 loc) · 2.66 KB
/
splitvcs.py
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
#!/usr/bin/env python3
# -*- coding: utf8 -*-
"""
This script takes an .vcs card and splits
"""
# This script is full of globals. Please don't program like this.
# It's 11PM on a saturday. I'll come back and refactor it, I swear [1]
import argparse
import io
import re
import sys
def parse_size(s):
"""
Parses a human-readable size to a number of bytes.
Only accepts kilos and megs because seriously, there's no point in other units (not for ics files anyway).
"""
sizes = {
'K': 1024,
'M': 1024 * 1024,
}
pattern = re.compile('^(\d+)([Kk]|M)[Bb]?$')
match = pattern.match(s)
if not match:
raise ValueError("Cannot understand size specification {}".format(s))
v, u = match.groups()
return int(v) * sizes[u.upper()]
BEGIN_CARD = "BEGIN:VCARD\n"
END_CARD = "END:VCARD"
def dump():
"""
Dumps the current stream to file.
"""
with open("{}.{}.vcs".format(args.input.name, file_count), "w", encoding=args.encoding) as outfile:
outfile.write(stream.getvalue())
if __name__ == '__main__':
# region Setup argparse
parser = argparse.ArgumentParser()
parser.add_argument('input', type=argparse.FileType('r'), help='The .ics input file')
parser.add_argument('-s', '--size', type=str, default='1M', help='Maximum size of each file (approximate)')
parser.add_argument('-n', '--number', type=int, default=float('inf'), help='Maximum number of events in each file')
parser.add_argument('-e', '--encoding', type=str, default='utf8', help='Encoding of the input file')
args = parser.parse_args(sys.argv[1:])
try:
args.size = parse_size(args.size)
except ValueError as e:
print(e)
sys.exit(1)
# endregion
stream = io.StringIO()
size, event_count, file_count = 0, 0, 0
for line in args.input:
# Copy the file line by line, tracking the current file size
stream.write(line)
size += len(line)
if line.startswith(END_CARD):
event_count += 1
if size > args.size or event_count >= args.number:
# Reached a rollover point: write the calendar's end and flush the file.
dump()
# Reset the stream (adding a new header for the calendar)
stream = io.StringIO()
stream.write(BEGIN_CARD)
size, event_count = 0, 0
file_count += 1
else:
continue
else:
# Finished the file, nothing to do except flushing
pass
# Flush the last part of the file. There's no need to add the calendar's end (the file already has it).
dump()
# [1] Never gonna happen