memegen.routes.image.get_without_text_jpeg()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
from flask import Blueprint, current_app, request, redirect
2
from webargs import fields, flaskparser
3
import log
4
5
from .. import domain
6
7
from ._cache import Cache
8
from ._utils import route, track, display
9
10
11
blueprint = Blueprint('image', __name__)
12
cache_filtered = Cache()
13
cache_unfiltered = Cache(filtered=False)
14
15
PLACEHOLDER = "https://raw.githubusercontent.com/jacebrowning/memegen-flask/main/memegen/static/images/missing.png"
16
OPTIONS = {
17
    'alt': fields.Str(missing=None),
18
    'font': fields.Str(missing=None),
19
    'preview': fields.Bool(missing=False),
20
    'share': fields.Bool(missing=False),
21
    'width': fields.Int(missing=None),
22
    'height': fields.Int(missing=None),
23
    'watermark': fields.Str(missing=None),
24
}
25
26
27
@blueprint.route("/latest.jpg")
28
@blueprint.route("/latest<int:index>.jpg")
29
@flaskparser.use_kwargs({'filtered': fields.Bool(missing=True)})
30
def get_latest(index=1, filtered=True):
31
    cache = cache_filtered if filtered else cache_unfiltered
32
    kwargs = cache.get(index - 1)
33
34
    if kwargs:
35
        kwargs['preview'] = True
36
    else:
37
        kwargs['key'] = 'custom'
38
        kwargs['path'] = "your_meme/goes_here"
39
        kwargs['alt'] = PLACEHOLDER
40
41
    return redirect(route('.get', _external=True, **kwargs))
42
43
44
@blueprint.route("/<key>.jpg")
45
@flaskparser.use_kwargs(OPTIONS)
46
def get_without_text(key, **options):
47
    options.pop('preview')
48
    options.pop('share')
49
50
    template = current_app.template_service.find(key)
51
    text = domain.Text(template.default_path)
52
53
    return redirect(route('.get', key=key, path=text.path, **options))
54
55
56
@blueprint.route("/<key>.jpeg")
57
def get_without_text_jpeg(key):
58
    return redirect(route('.get_without_text', key=key))
59
60
61
@blueprint.route("/<key>/<path:path>.jpg", endpoint='get')
62
@flaskparser.use_kwargs(OPTIONS)
63
def get_with_text(key, path, alt, font, watermark, preview, share, **size):
64
    assert len(size) == 2
65
    options = dict(key=key, path=path,
66
                   alt=alt, font=font, watermark=watermark, **size)
67
    if preview:
68
        options['preview'] = True
69
    if share:
70
        options['share'] = True
71
72
    text = domain.Text(path)
73
    fontfile = current_app.font_service.find(font)
74
75
    template = current_app.template_service.find(key, allow_missing=True)
76
    if template.key != key:
77
        options['key'] = template.key
78
        return redirect(route('.get', **options))
79
80
    if path != text.path:
81
        options['path'] = text.path
82
        return redirect(route('.get', **options))
83
84
    if alt and "://memegen.link/" in alt:
85
        options.pop('alt')
86
        options['key'] = alt.split('/')[3]
87
        return redirect(route('.get', **options))
88
89
    if alt and "://" in alt and key != 'custom':
90
        options['key'] = 'custom'
91
        return redirect(route('.get', **options))
92
93
    if alt and template.path == template.get_path(alt, download=False):
94
        options.pop('alt')
95
        return redirect(route('.get', **options))
96
97
    if font and not fontfile:
98
        options.pop('font')
99
        return redirect(route('.get', **options))
100
101
    final_watermark, valid = _get_watermark(request, text, watermark, share)
102
    if not valid:
103
        options.pop('watermark')
104
        return redirect(route('.get', **options))
105
106
    image = current_app.image_service.create(
107
        template, text,
108
        style=PLACEHOLDER if alt == 'none' else alt,
109
        font=fontfile, size=size, watermark=final_watermark,
110
    )
111
112
    if not preview:
113
        cache_filtered.add(key=key, path=path, alt=alt, font=font)
114
        cache_unfiltered.add(key=key, path=path, alt=alt, font=font)
115
        track(image.text)
116
117
    return display(image.text, image.path, share=share)
118
119
120
@blueprint.route("/<key>/<path:path>.jpeg")
121
def get_with_text_jpeg(key, path):
122
    return redirect(route('.get', key=key, path=path))
123
124
125
@blueprint.route("/_<code>.jpg")
126
@flaskparser.use_kwargs(OPTIONS)
127
def get_encoded(code, alt, font, watermark, preview, share, **size):
128
    assert len(size) == 2
129
    options = dict(code=code, font=font, watermark=watermark, **size)
130
    if share:
131
        options['share'] = True
132
133
    if alt or preview:
134
        return redirect(route('.get_encoded', **options))
135
136
    key, path = current_app.link_service.decode(code)
137
    template = current_app.template_service.find(key)
138
    text = domain.Text(path)
139
    fontfile = current_app.font_service.find(font)
140
141
    if font and not fontfile:
142
        options.pop('font')
143
        return redirect(route('.get_encoded', **options))
144
145
    watermark, valid = _get_watermark(request, text, watermark, share)
146
    if not valid:
147
        options.pop('watermark')
148
        return redirect(route('.get_encoded', **options))
149
150
    image = current_app.image_service.create(
151
        template, text, font=fontfile, size=size, watermark=watermark,
152
    )
153
154
    track(image.text)
155
156
    return display(image.text, image.path, share=share)
157
158
159
def _get_watermark(_request, text: domain.Text, watermark: str, share: bool):
160
    referrer = _request.environ.get('HTTP_REFERER', "").lower()
161
    agent = _request.environ.get('HTTP_USER_AGENT', "").lower()
162
    log.debug("Referrer=%r Agent=%r", referrer, agent)
163
164
    if not text:
165
        log.debug("Watermark disabled (no text)")
166
        if watermark:
167
            return None, False
168
        else:
169
            return None, True
170
171
    if watermark == 'none':
172
        if share:
173
            log.debug("Watermark disabled (share=true)")
174
            return None, True
175
        for option in current_app.config['WATERMARK_OPTIONS']:
176
            for identity in (referrer, agent):
177
                if option and identity and option in identity:
178
                    log.debug(f"Watermark disabled ({option} in {identity})")
179
                    return None, True
180
181
        log.warning("Request does not support unmarked images")
182
        return None, False
183
184
    if watermark and watermark not in current_app.config['WATERMARK_OPTIONS']:
185
        log.warning("Unsupported custom watermark: %r", watermark)
186
        return watermark, False
187
188
    if watermark:
189
        log.debug("Using custom watermark: %r", watermark)
190
        return watermark, True
191
192
    default = current_app.config['WATERMARK_OPTIONS'][0]
193
    log.debug("Using default watermark: %r", default)
194
    return default, True
195