Skip to content

Commit f65fd99

Browse files
authored
Merge pull request pklaus#18 from DL6ER/new/random
Add {{random[:len]}} and add optional [start] for {{counter}}
2 parents 58a0e52 + 3898d10 commit f65fd99

7 files changed

Lines changed: 52 additions & 33 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,15 @@ Additional printer support comes from [matmair/brother_ql-inventree](https://git
9696
- Dockerized
9797
- Devcontainer for ease of development/contributing
9898

99+
### Supported templates
100+
101+
- `{{counter[:start]}}` — Inserts the current counter value (automatically increments when printing multiple labels at the same time).
102+
- `{{datetime:<format>}}` — Inserts the current date and time, e.g. `%H:%M:%S %d.%m.%Y` (see [strftime](https://strftime.org/)).
103+
- `{{uuid}}` — Inserts a random UUID (Universally Unique Identifier).
104+
- `{{short-uuid}}` — Inserts a shortened version of a UUID.
105+
- `{{env:var}}` — Inserts the value of the environment variable `var`.
106+
- `{{random[:<len>]}}` — Inserts a random string of optional length `len` (defaulting to 64).
107+
99108
## Docker Compose
100109

101110
You may also use the example [`docker-compose.yml`](./docker-compose.yml) file provided in this repository to quickly get started with Docker Compose:

app/labeldesigner/label.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from barcode.writer import ImageWriter
99
import datetime
1010
import re
11+
import random
12+
import string
1113

1214
logger = logging.getLogger(__name__)
1315

@@ -90,6 +92,7 @@ def __init__(
9092
border_distance=(0, 0),
9193
border_color=(0, 0, 0),
9294
timestamp=0,
95+
counter=0,
9396
red_support=False):
9497
self._width = width
9598
self._height = height
@@ -109,7 +112,7 @@ def __init__(
109112
self._border_roundness = border_roundness
110113
self._border_distance = border_distance
111114
self._border_color = border_color
112-
self._counter = 1
115+
self._counter = counter
113116
self._timestamp = timestamp
114117
self._red_support = red_support
115118

@@ -125,7 +128,7 @@ def want_text(self, img):
125128
# We always want to draw text (even when empty) when no image is
126129
# provided to avoid an error 500 because we created no image at all
127130
return img is None or self._label_content not in (LabelContent.QRCODE_ONLY,) and len(self.text) > 0 and len(self.text[0]['text']) > 0
128-
131+
129132
@property
130133
def need_image_text_distance(self):
131134
return self._label_content in (LabelContent.TEXT_QRCODE,
@@ -170,13 +173,17 @@ def label_type(self, value):
170173
self._label_type = value
171174

172175
def process_templates(self):
173-
# Loop over text lines and replace
174-
# {{datetime:x}} by current datetime in specified format x
175-
# {{counter}} by an incrementing counter
176+
# Loop over text lines and replace templates
176177
self.text = self.input_text.copy()
177178
for line in self.text:
178-
# Replace {{counter}} with current counter value
179-
line['text'] = line['text'].replace("{{counter}}", str(self._counter))
179+
if len(line['text']) > 500:
180+
logger.warning("Text line is very long (> 500 characters), this may lead to long processing times.")
181+
182+
# Replace {{counter[:offset]}} with current label counter (x is an optional offset defaulting to 1)
183+
def counter_replacer(match):
184+
offset = int(match.group(1)) if match.group(1) else 1
185+
return str(self._counter + offset)
186+
line['text'] = re.sub(r"\{\{counter(?:\:(\d+))?\}\}", counter_replacer, line['text'])
180187

181188
# Replace {{datetime:x}} with current datetime formatted as x
182189
def datetime_replacer(match):
@@ -186,9 +193,7 @@ def datetime_replacer(match):
186193
else:
187194
now = datetime.datetime.now()
188195
return now.strftime(fmt)
189-
# Performance issue mitigation
190-
if len(line['text']) < 100:
191-
line['text'] = re.sub(r"\{\{datetime:([^}]+)\}\}", datetime_replacer, line['text'])
196+
line['text'] = re.sub(r"\{\{datetime:([^}]+)\}\}", datetime_replacer, line['text'])
192197

193198
# Replace {{uuid}} with a new UUID
194199
if "{{uuid}}" in line['text']:
@@ -202,12 +207,13 @@ def datetime_replacer(match):
202207
def env_replacer(match):
203208
var_name = match.group(1)
204209
return os.getenv(var_name, "")
205-
# Performance issue mitigation
206-
if len(line['text']) < 100:
207-
line['text'] = re.sub(r"\{\{env:([^}]+)\}\}", env_replacer, line['text'])
210+
line['text'] = re.sub(r"\{\{env:([^}]+)\}\}", env_replacer, line['text'])
208211

209-
# Increment counter
210-
self._counter += 1
212+
# Replace {{random[:len]}} with random string of optional length <len>
213+
def random_replacer(match):
214+
length = int(match.group(1)) if match.group(1) else 64
215+
return ''.join(random.choices(string.ascii_letters + string.digits + string.punctuation, k=length))
216+
line['text'] = re.sub(r"\{\{random(?:\:(\d+))?\}\}", random_replacer, line['text'])
211217

212218
def generate(self, rotate = False):
213219
# Process possible templates in the text

app/labeldesigner/printer.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,12 @@ def label_size(self):
4545
def label_size(self, value):
4646
self._label_size = value
4747

48-
def add_label_to_queue(self, label, count, cut_once=False, high_res: bool = False):
49-
for cnt in range(0, count):
50-
cut = (cut_once == False) or (cut_once and cnt == count-1)
51-
52-
self._printQueue.append(
53-
{'label': label,
54-
'cut': cut,
55-
'high_res': high_res
56-
})
48+
def add_label_to_queue(self, label, cut: bool = True, high_res: bool = False):
49+
self._printQueue.append(
50+
{'label': label,
51+
'cut': cut,
52+
'high_res': high_res
53+
})
5754

5855
def process_queue(self) -> bool:
5956
qlr = BrotherQLRaster(self._model)

app/labeldesigner/routes.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ def print_label():
115115
if isinstance(level, int):
116116
current_app.logger.setLevel(level)
117117
printer = create_printer_from_request(request)
118-
label = create_label_from_request(request)
119118
print_count = int(request.values.get('print_count', 1))
120119
if print_count < 1:
121120
raise ValueError("print_count must be greater than 0")
@@ -127,9 +126,15 @@ def print_label():
127126
# Generate error 400 response
128127
return make_response(jsonify(return_dict), 400)
129128

130-
printer.add_label_to_queue(label, print_count, cut_once, high_res)
131-
132129
try:
130+
for i in range(print_count):
131+
label = create_label_from_request(request, i)
132+
# Cut only if we
133+
# - always cut, or
134+
# - we cut only once and this is the last label to be generated
135+
cut = (cut_once == False) or (cut_once and i == print_count-1)
136+
printer.add_label_to_queue(label, cut, high_res)
137+
133138
status = printer.process_queue()
134139
except Exception as e:
135140
return_dict['message'] = str(e)
@@ -159,7 +164,7 @@ def parse_text_form(input):
159164
return []
160165
return json.loads(input)
161166

162-
def create_label_from_request(request):
167+
def create_label_from_request(request, counter: int = 0):
163168
d=request.values
164169
label_size = d.get('label_size', "62")
165170
kind = [label.form_factor for label in ALL_LABELS if label.identifier == label_size][0]
@@ -312,5 +317,6 @@ def get_uploaded_image(image):
312317
border_roundness=context['border_roundness'],
313318
border_distance=(context['border_distanceX'], context['border_distanceY']),
314319
border_color=border_color,
315-
timestamp=context['timestamp']
320+
timestamp=context['timestamp'],
321+
counter=counter
316322
)

app/labeldesigner/templates/labeldesigner.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,12 +356,13 @@ <h6>Additional Font Options:</h6>
356356
<li><code>{{'{{datetime:%H:%M:%S %d.%m.%Y'}}}}</code> — Inserts the current date and time when printing.
357357
You can customize the format using <a href="https://strftime.org/" target="_blank"
358358
rel="noopener">strftime</a> options.</li>
359-
<li><code>{{'{{counter'}}}}</code> — Inserts an up-counting number, increasing for every printed label.
359+
<li><code>{{'{{counter[:start]}}'}}</code> — Inserts an up-counting number. You can optionally specify a <code>start</code> value (defaulting to 1) to start counting from a different number.
360+
When printing multiple labels at once, the counter automatically increments for each label.
360361
</li>
361362
<li><code>{{'{{uuid'}}}}</code> — Inserts a random UUID (Universally Unique Identifier).</li>
362363
<li><code>{{'{{short-uuid'}}}}</code> — Inserts a shortened version of a UUID.</li>
363-
<li><code>{{'{{env:var}}'}}</code> — Inserts the value of the environment variable <code>var</code>.
364-
</li>
364+
<li><code>{{'{{env:var}}'}}</code> — Inserts the value of the environment variable <code>var</code>.</li>
365+
<li><code>{{'{{random[:len]}}'}}</code> — Inserts a random string of optional length <code>len</code> (defaulting to 64).</li>
365366
</ul>
366367
<span class="text-muted">Templates are replaced at print time.</span>
367368
</div>

tests/template.png

78 Bytes
Loading

tests/test_labeldesigner_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ def test_generate_template(client):
392392
{
393393
'family': 'DejaVu Sans',
394394
'style': 'Book',
395-
'text': '{{datetime:%d.%m.%Y %H:%M:%S}} COUNTER: {{counter}}',
395+
'text': '{{datetime:%d.%m.%Y %H:%M:%S}} COUNTER: {{counter}} {{counter:5}}',
396396
'size': '30',
397397
'align': 'left'
398398
},

0 commit comments

Comments
 (0)