summaryrefslogtreecommitdiff
path: root/scripts/tellico2lesana
blob: 4bd08100a69e14c7955d17b412735b025a14599e (plain)
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
#!/usr/bin/env python3

import argparse
import datetime
from xml.etree import ElementTree
import zipfile

import lesana


NS = {'tellico': 'http://periapsis.org/tellico/'}

# https://docs.kde.org/trunk5/en/extragear-office/tellico/field-type-values.html
F_TYPE_MAP = {
    '0': 'string',      # not in the specs, but seen in the wild
    '1': 'string',
    '2': 'text',
    '3': 'string',
    '4': 'bool',
    '6': 'integer',
    '7': 'url',
    '8': 'list',       # single column table
    '10': 'file',
    '12': 'timestamp',  # date
    '14': 'integer',    # rating

    }


class T2L():
    """
    Manage collections
    """
    arguments = [
        (['-c', '--collection'], dict(
            help='Name of the new lesana collection',
            default=None,
            )),
        (['file'], dict(
            help='Tellico file to convert to lesana.',
            )),
        ]

    def _load_args(self):
        self.parser = argparse.ArgumentParser()
        for arg in self.arguments:
            self.parser.add_argument(*arg[0], **arg[1])
        self.args = self.parser.parse_args()

    def read_field_data(self, xfield):
        if xfield.tag in self.date_fields:
            for child in xfield:
                if 'year' in child.tag:
                    year = child.text
                elif 'month' in child.tag:
                    month = child.text
                elif 'day' in child.tag:
                    day = child.text
            try:
                data = datetime.date(
                    int(year),
                    int(month),
                    int(day)
                    )
            except ValueError:
                data = None
        elif xfield.iter().__next__():
            data = []
            for child in xfield:
                data.append(self.read_field_data(child))
        else:
            data = xfield.text
        return data

    def main(self):
        self._load_args()
        with zipfile.ZipFile(self.args.file, 'r') as zp:
            tree = ElementTree.parse(zp.open('tellico.xml'))
        # open collection
        xml_collection = tree.getroot().find('tellico:collection', NS)

        # get collection settings
        title = xml_collection.attrib['title']
        xml_fields = xml_collection.find('tellico:fields', NS)
        self.date_fields = []
        fields = []
        for xf in xml_fields:
            if xf.attrib['type'] == '12':
                self.date_fields.append(
                    '{' + NS['tellico'] + '}' + xf.attrib['name']
                    )
            f_type = F_TYPE_MAP.get(xf.attrib['type'])
            # TODO: support fields with the multiple values flag
            # (they should probably become lists)
            try:
                flags = int(xf.attrib['flags'])
            except ValueError:
                flags = 0
            if flags % 2 == 1:
                l_type = f_type
                f_type = 'list'
                plural = 's'
            else:
                l_type = None
                plural = ''
            field = {
                'name': xf.attrib['name'] + plural,
                'type': f_type,
                'help': xf.attrib['title'],
                }
            if l_type:
                field['list'] = l_type
            fields.append(field)
        # Create a collection with the settings we have loaded
        directory = self.args.collection or self.args.file.replace(
            '.tc',
            '.lesana'
            )
        self.collection = lesana.collection.Collection.init(
            directory=directory,
            git_enabled=False,
            settings={
                'name': title,
                'fields': fields,
                }
            )

        # import data
        for xe in xml_collection.findall('tellico:entry', NS):
            data = {
                'uid': xe.attrib['id']
                }
            for xfield in xe.getchildren():
                field_name = xfield.tag.replace(
                    '{'+NS['tellico']+'}',
                    '')
                data[field_name] = self.read_field_data(xfield)
            new_entry = lesana.collection.Entry(self.collection, data=data)
            self.collection.save_entries([new_entry])
        self.collection.update_cache()


if __name__ == '__main__':
    T2L().main()