make_book_from_comic_list()   F
last analyzed

Complexity

Conditions 11

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
c 1
b 0
f 0
dl 0
loc 38
rs 3.1764

How to fix   Complexity   

Complexity

Complex classes like make_book_from_comic_list() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#! /usr/bin/python3
2
# vim: set expandtab tabstop=4 shiftwidth=4 :
3
"""Module to create ebooks"""
4
5
import html
6
import sys
7
import subprocess
8
import os
9
import urllib.parse
10
import datetime
11
from itertools import chain
12
from comic_abstract import get_date_for_comic, get_info_before_comic, get_info_after_comic
13
14
# http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000234621
15
KINDLEGEN_PATH = './kindlegen_linux_2.6_i386_v2_9/kindlegen'
16
HTML_HEADER = """
17
<html>
18
    <head>
19
        <title>%s</title>
20
        <meta name='book-type' content='comic'/>
21
        <meta name='orientation-lock' content='landscape'/>
22
        <meta name='cover' content='%s'>
23
    </head>
24
    <body>
25
        Generated with '%s' at %s<br>
26
        <a name='TOC'><h1>Table of Contents</h1></a>"""
27
HTML_TOC_ITEM = """
28
        <a href='#%d'>%s</a><br>"""
29
HTML_START = """
30
    <mbp:pagebreak />
31
    <h1>Comics</h1>
32
    <a name='start' />"""
33
HTML_COMIC_INFO = """
34
        <mbp:pagebreak />
35
        <a name='%d'/><h2>%s</h2>
36
            %s %s<br>"""
37
HTML_COMIC_ADDITIONAL_INFO = """
38
            %s<br>"""
39
HTML_COMIC_IMG = """
40
            <img src='%s' style='width:100%%'><br>"""
41
HTML_FOOTER = """
42
    </body>
43
</html>"""
44
45
XHTML_HEADER = """
46
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
47
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
48
<html xmlns="http://www.w3.org/1999/xhtml">
49
50
<head>
51
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
52
  <title>%s</title>
53
  <meta name='cover' content='%s'/>
54
</head>
55
56
<body>
57
  Generated with '%s' at %s
58
"""
59
60
XHTML_TOC_ITEM = """
61
        <a href='#%d'>%s</a><br/>"""
62
63
XHTML_START = """
64
    <h1>Comics</h1>"""
65
66
XHTML_COMIC_INFO = """
67
        <a name='%d'/><h2>%s</h2>
68
            %s %s<br/>"""
69
70
XHTML_COMIC_ADDITIONAL_INFO = """
71
            %s<br/>"""
72
73
XHTML_COMIC_IMG = """
74
            <img src='%s' style='width:100%%'><br>"""
75
76
XHTML_FOOTER = """
77
</body>
78
79
</html>"""
80
81
HTML_TAGS = HTML_HEADER, HTML_TOC_ITEM, HTML_START, HTML_COMIC_INFO, HTML_COMIC_ADDITIONAL_INFO, HTML_COMIC_IMG, HTML_FOOTER
82
XHTML_TAGS = XHTML_HEADER, XHTML_TOC_ITEM, XHTML_START, XHTML_COMIC_INFO, XHTML_COMIC_ADDITIONAL_INFO, XHTML_COMIC_IMG, XHTML_FOOTER
83
84
85
def collect_comics(comic_classes):
86
    """Retrieve all comics for the list of comic classes provided."""
87
    return chain.from_iterable(c.get_comics() for c in comic_classes)
88
89
90
def filter_comics(comics):
91
    """Filter comics based on (hardcoded) criterias.
92
93
    On the long run, I'd like the criteria to be provided via command-line
94
    arguments."""
95
    return [c for c in comics if 'new' in c]
96
97
98
def sort_comics(comics):
99
    """Sort comics based on (hardcoded) criterias.
100
101
    On the long run, I'd like the criteria to be provided via command-line
102
    arguments."""
103
    return sorted(comics, key=get_date_for_comic, reverse=True)
104
105
106
def truncate_comics(comics):
107
    """Truncate the list of comics based on (hardcoded) criterias.
108
109
    On the long run, I'd like the criteria to be provided via command-line
110
    arguments."""
111
    return comics[:3000]
112
113
114
def make_book(comic_classes):
115
    """Create ebook - not finished."""
116
    comics = truncate_comics(sort_comics(filter_comics(collect_comics(comic_classes))))
117
    for i, c in enumerate(comics):
118
        print(i, c['url'], get_date_for_comic(c))
119
    if comics:
120
        make_book_from_comic_list(
121
            comics,
122
            '%s from %s to %s' %
123
            (' - '.join(sorted({c['comic'] for c in comics})),
124
             min(get_date_for_comic(c) for c in comics).strftime('%x'),
125
             max(get_date_for_comic(c) for c in comics).strftime('%x')),
126
            'book.html')
127
128
129
def convert_unicode_to_html(text):
130
    """Convert unicode text to HTML by escaping it."""
131
    return html.escape(text).encode('ascii', 'xmlcharrefreplace').decode()
132
133
134
def make_book_from_comic_list(comics, title, file_name, mobi=True):
135
    """Create book from a list of comics."""
136
    cover = 'empty.jpg'
137
    output_dir = 'generated_books'
138
    os.makedirs(output_dir, exist_ok=True)
139
    html_book = os.path.join(output_dir, file_name)
140
141
    header, toc_item, start, com_info, com_add_info, com_img, footer = HTML_TAGS if mobi else XHTML_TAGS
142
143
    with open(html_book, 'w+') as book:
144
        book.write(header % (
145
            title,
146
            cover,
147
            ' '.join(sys.argv),
148
            datetime.datetime.now().strftime('%c')
149
        ))
150
151
        for i, com in enumerate(comics):
152
            book.write(toc_item % (i, com['url']))
153
154
        book.write(start)
155
156
        for i, com in enumerate(comics):
157
            book.write(com_info % (
158
                i, com['url'], com['comic'], get_date_for_comic(com).strftime('%x')))
159
            for info in get_info_before_comic(com):
160
                book.write(com_add_info % convert_unicode_to_html(info))
161
            for path in com['local_img']:
162
                if path is not None:
163
                    assert os.path.isfile(path)
164
                    book.write(
165
                        com_img % urllib.parse.quote(os.path.relpath(path, output_dir)))
166
            for info in get_info_after_comic(com):
167
                book.write(com_add_info % convert_unicode_to_html(info))
168
        book.write(footer)
169
170
    if mobi:
171
        subprocess.call([KINDLEGEN_PATH, '-verbose', '-dont_append_source', html_book])
172